Compare commits
9 Commits
412624a93c
...
059c755d14
| Author | SHA1 | Date | |
|---|---|---|---|
| 059c755d14 | |||
| 34d3d047d2 | |||
| a3de3d573a | |||
| bbab4972c3 | |||
| 07a1014889 | |||
| 2ce398a8d4 | |||
| fcf64f335d | |||
| c873f473c8 | |||
| f110ad8d27 |
+2
-1
@@ -2,4 +2,5 @@
|
||||
**/obj
|
||||
.git
|
||||
.env
|
||||
data
|
||||
data
|
||||
Properties
|
||||
@@ -34,10 +34,21 @@
|
||||
}
|
||||
|
||||
public async Task TrySendCode() {
|
||||
Result = "Waiting on response from server";
|
||||
HttpResponseMessage TestLogin = await Http.PostAsJsonAsync("api/account/sendresetpassword", new Account(){ Email = Email });
|
||||
Result = await TestLogin.Content.ReadAsStringAsync();
|
||||
|
||||
MailAddress addr = new MailAddress(Email);
|
||||
if ( addr.Address != Email ){
|
||||
Result = "Enter a valid email address";
|
||||
}else{
|
||||
Result = "";
|
||||
}
|
||||
if (string.IsNullOrEmpty(Result)){
|
||||
Dictionary<string, string> formData = new Dictionary<string, string>{
|
||||
{ "Email", Email }
|
||||
};
|
||||
Result = "Waiting on response from server";
|
||||
HttpResponseMessage TestLogin = await Http.PostAsync("api/account/sendresetpassword", new FormUrlEncodedContent(formData) );
|
||||
Result = await TestLogin.Content.ReadAsStringAsync();
|
||||
}
|
||||
base.StateHasChanged();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -54,34 +54,36 @@
|
||||
Loading = "Waiting for login response from server";
|
||||
ReturnURL = string.IsNullOrEmpty(ReturnURL) ? "/" : ReturnURL;
|
||||
ErrorMsgs = new List<string>();
|
||||
|
||||
if( !string.IsNullOrEmpty(UserName) ) {
|
||||
if( !string.IsNullOrEmpty(Password) ) {
|
||||
if (Password.Length >= 6 ) {
|
||||
HttpResponseMessage TestLogin = await Http.PostAsJsonAsync("api/account/login", new MistoxWebsite.Shared.Account(){ UserName = UserName, PasswordHash = Password, EmailVerified = StayLoggedIn });
|
||||
string result = await TestLogin.Content.ReadAsStringAsync();
|
||||
Account? user = JsonConvert.DeserializeObject<Account>(result);
|
||||
if (user == null ) {
|
||||
ErrorMsgs.Add("No response from the server");
|
||||
base.StateHasChanged();
|
||||
return;
|
||||
}
|
||||
if ( string.IsNullOrEmpty(user.Error) ) {
|
||||
ErrorMsgs.Add("Login Success");
|
||||
Nav.NavigateTo("/", true);
|
||||
} else {
|
||||
ErrorMsgs.Add(user.Error);
|
||||
}
|
||||
Loading = "";
|
||||
} else {
|
||||
ErrorMsgs.Add("Password must be at least 6 Characters long");
|
||||
}
|
||||
} else {
|
||||
ErrorMsgs.Add("The 'password' field is required");
|
||||
}
|
||||
} else{
|
||||
if( string.IsNullOrEmpty(UserName) ) {
|
||||
ErrorMsgs.Add("The 'username' field is required");
|
||||
}
|
||||
if( string.IsNullOrEmpty(Password) ) {
|
||||
ErrorMsgs.Add("The 'password' field is required");
|
||||
}
|
||||
if (Password.Length < 6 ) {
|
||||
ErrorMsgs.Add("Password must be at least 6 Characters long");
|
||||
}
|
||||
if (ErrorMsgs.Count == 0){
|
||||
Dictionary<string, string> formData = new Dictionary<string, string>{
|
||||
{ "UserName", UserName },
|
||||
{ "PasswordHash", Password },
|
||||
{ "StayLoggedIn", StayLoggedIn.ToString() }
|
||||
};
|
||||
HttpResponseMessage TestLogin = await Http.PostAsync("api/account/login", new FormUrlEncodedContent(formData) );
|
||||
string result = await TestLogin.Content.ReadAsStringAsync();
|
||||
Account? user = JsonConvert.DeserializeObject<Account>(result);
|
||||
if (user == null ) {
|
||||
ErrorMsgs.Add("No response from the server");
|
||||
base.StateHasChanged();
|
||||
return;
|
||||
}
|
||||
if ( string.IsNullOrEmpty(user.Error) ) {
|
||||
ErrorMsgs.Add("Login Success");
|
||||
Nav.NavigateTo(ReturnURL, true);
|
||||
} else {
|
||||
ErrorMsgs.Add(user.Error);
|
||||
}
|
||||
}
|
||||
Loading = "";
|
||||
base.StateHasChanged();
|
||||
}
|
||||
|
||||
@@ -52,63 +52,41 @@
|
||||
}
|
||||
}
|
||||
|
||||
public bool CheckEmail(string email ) {
|
||||
int ATcount = 0;
|
||||
int DOTcount = 0;
|
||||
char[] cmail = email.ToArray();
|
||||
foreach(char cur in cmail ) {
|
||||
if(cur == '@' ) {
|
||||
ATcount += 1;
|
||||
}else if(cur == '.' ) {
|
||||
DOTcount += 1;
|
||||
}
|
||||
}
|
||||
if (ATcount == 1 && DOTcount >= 1 ) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public async Task TryRegister() {
|
||||
Loading = "Waiting for a response from the server";
|
||||
ReturnURL = string.IsNullOrEmpty(ReturnURL) ? "/" : ReturnURL;
|
||||
|
||||
ErrorMsgs = new List<string>();
|
||||
|
||||
if ( !string.IsNullOrEmpty(Email) ){
|
||||
if( CheckEmail( Email ) ) {
|
||||
if( !string.IsNullOrEmpty(UserName) ) {
|
||||
if( !string.IsNullOrEmpty(Password) ) {
|
||||
if (Password.Length >= 6 ) {
|
||||
HttpResponseMessage TestRegister = await Http.PostAsJsonAsync("api/account/register", new Account(){
|
||||
UserName = UserName,
|
||||
Email = Email,
|
||||
PasswordHash = Password,
|
||||
EmailVerified = false,
|
||||
});
|
||||
Account? user = await TestRegister.Content.ReadFromJsonAsync<Account>();
|
||||
if ( string.IsNullOrEmpty(user?.Error) ) {
|
||||
ErrorMsgs.Add("Register Success");
|
||||
Nav.NavigateTo("/", true);
|
||||
} else {
|
||||
ErrorMsgs.Add( user.Error );
|
||||
}
|
||||
Loading = "";
|
||||
}else{
|
||||
ErrorMsgs.Add("Password must be at least 6 Characters long");
|
||||
}
|
||||
}else{
|
||||
ErrorMsgs.Add("The 'password' field is required");
|
||||
}
|
||||
}else{
|
||||
ErrorMsgs.Add("The 'username' field is required");
|
||||
}
|
||||
}else{
|
||||
ErrorMsgs.Add("Please check your email address");
|
||||
}
|
||||
}else{
|
||||
MailAddress addr = new MailAddress(Email);
|
||||
if ( addr.Address != Email ){
|
||||
ErrorMsgs.Add("Please check your email address");
|
||||
}
|
||||
if (Password.Length < 6 ) {
|
||||
ErrorMsgs.Add("Password must be at least 6 Characters long");
|
||||
}
|
||||
if( string.IsNullOrEmpty(UserName) ) {
|
||||
ErrorMsgs.Add("The 'username' field is required");
|
||||
}
|
||||
if( string.IsNullOrEmpty(Password) ) {
|
||||
ErrorMsgs.Add("The 'password' field is required");
|
||||
}
|
||||
if ( string.IsNullOrEmpty(Email) ){
|
||||
ErrorMsgs.Add("The 'email' field is required");
|
||||
}
|
||||
if (ErrorMsgs.Count == 0){
|
||||
Dictionary<string, string> formData = new Dictionary<string, string>{
|
||||
{ "Email", Email },
|
||||
{ "UserName", UserName },
|
||||
{ "PasswordHash", Password },
|
||||
};
|
||||
HttpResponseMessage TestRegister = await Http.PostAsync("api/account/register", new FormUrlEncodedContent(formData) );
|
||||
Account? user = await TestRegister.Content.ReadFromJsonAsync<Account>();
|
||||
if ( string.IsNullOrEmpty(user?.Error) ) {
|
||||
ErrorMsgs.Add("Register Success");
|
||||
Nav.NavigateTo(ReturnURL, true);
|
||||
} else {
|
||||
ErrorMsgs.Add( user.Error );
|
||||
}
|
||||
}
|
||||
Loading = "";
|
||||
base.StateHasChanged();
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
[Parameter]
|
||||
[SupplyParameterFromQuery]
|
||||
public string ResetPwd { get; set; } = "";
|
||||
|
||||
public string NewPassword{ get; set; } = "";
|
||||
public string RepeatPassword{ get; set; } = "";
|
||||
|
||||
@@ -52,24 +51,29 @@
|
||||
|
||||
protected async Task TryChange() {
|
||||
Result = "Waiting on response from server";
|
||||
if (NewPassword.Length >= 6){
|
||||
if (NewPassword == RepeatPassword){
|
||||
HttpResponseMessage TestLogin = await Http.PostAsJsonAsync("api/account/resetpassword", new Account(){ UserName = UserName, PasswordHash = NewPassword, Error = ResetPwd });
|
||||
string result = await TestLogin.Content.ReadAsStringAsync();
|
||||
bool success = result == "true" ? true : false;
|
||||
if (success){
|
||||
Result = "Password changed successfully";
|
||||
Thread.Sleep(2000);
|
||||
Nav.NavigateTo("/", true);
|
||||
}else{
|
||||
Result = "Something is wrong";
|
||||
}
|
||||
}else{
|
||||
Result = "Passwords must match";
|
||||
}
|
||||
}else{
|
||||
if (NewPassword != RepeatPassword){
|
||||
Result = "Passwords must match";
|
||||
}
|
||||
if (NewPassword.Length < 6){
|
||||
Result = "Password must be at least 6 Characters long";
|
||||
}
|
||||
if (string.IsNullOrEmpty(Result)){
|
||||
Dictionary<string, string> formData = new Dictionary<string, string>{
|
||||
{ "UserName", UserName },
|
||||
{ "NewPassword", NewPassword },
|
||||
{ "ResetToken", ResetPwd },
|
||||
};
|
||||
HttpResponseMessage TestLogin = await Http.PostAsync("api/account/resetpassword", new FormUrlEncodedContent(formData) );
|
||||
string result = await TestLogin.Content.ReadAsStringAsync();
|
||||
bool success = result == "true" ? true : false;
|
||||
if (success){
|
||||
Result = "Password changed successfully";
|
||||
Thread.Sleep(2000);
|
||||
Nav.NavigateTo("/", true);
|
||||
}else{
|
||||
Result = "Something is wrong";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,7 +26,11 @@
|
||||
public string Result{ get; set; } = "";
|
||||
|
||||
protected override async Task OnInitializedAsync() {
|
||||
HttpResponseMessage Query = await Http.PostAsJsonAsync("api/account/verifyemail", new Account(){ UserName = UserName, PasswordHash = Guid });
|
||||
Dictionary<string, string> formData = new Dictionary<string, string>{
|
||||
{ "UserName", UserName },
|
||||
{ "EmailToken", Guid },
|
||||
};
|
||||
HttpResponseMessage Query = await Http.PostAsync("api/account/verifyemail", new FormUrlEncodedContent(formData) );
|
||||
bool Answer = await Query.Content.ReadFromJsonAsync<bool>();
|
||||
if (Answer == true ) {
|
||||
Result = "Verified Email Successfully";
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
@code {
|
||||
|
||||
public MistoxWebsite.Shared.Account? _account = null;
|
||||
public MistoxWebsite.Shared.Database.Account? _account = null;
|
||||
|
||||
public int MaxFailedLogin = 0;
|
||||
public bool FailedLoginToggle = false;
|
||||
@@ -49,18 +49,19 @@
|
||||
|
||||
public async Task SubmitLoginLock() {
|
||||
if (_account != null ) {
|
||||
_account.SiteData.FailedPasswordLock = FailedLoginToggle;
|
||||
_account.SiteData.PasswordAttempts = MaxFailedLogin;
|
||||
_account.PasswordHash = "";
|
||||
HttpResponseMessage SendVerifyEmail = await Http.PostAsJsonAsync("api/account/toggleAccountLock", _account);
|
||||
LoginCounterResult = await SendVerifyEmail.Content.ReadAsStringAsync();
|
||||
Dictionary<string, string> formData = new Dictionary<string, string>{
|
||||
{ "UserName", _account.UserName },
|
||||
{ "AccountLock", FailedLoginToggle.ToString() },
|
||||
};
|
||||
HttpResponseMessage Query = await Http.PostAsync("api/account/toggleAccountLock", new FormUrlEncodedContent(formData) );
|
||||
LoginCounterResult = await Query.Content.ReadAsStringAsync();
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task OnInitializedAsync() {
|
||||
HttpResponseMessage x = await Http.PostAsync("api/account/get", new StringContent(""));
|
||||
string body = await x.Content.ReadAsStringAsync();
|
||||
_account = JsonConvert.DeserializeObject<MistoxWebsite.Shared.Account>(body);
|
||||
_account = JsonConvert.DeserializeObject<MistoxWebsite.Shared.Database.Account>(body);
|
||||
if (_account != null){
|
||||
FailedLoginToggle = _account.SiteData.FailedPasswordLock;
|
||||
MaxFailedLogin = _account.SiteData.PasswordAttempts;
|
||||
@@ -73,8 +74,11 @@
|
||||
|
||||
public async Task SendVerifyEmail() {
|
||||
if (_account != null){
|
||||
HttpResponseMessage SendVerifyEmail = await Http.PostAsJsonAsync("api/account/sendverifyemail", new MistoxWebsite.Shared.Account(){ UserName = _account.UserName });
|
||||
bool result = await SendVerifyEmail.Content.ReadFromJsonAsync<bool>();
|
||||
Dictionary<string, string> formData = new Dictionary<string, string>{
|
||||
{ "UserName", _account.UserName },
|
||||
};
|
||||
HttpResponseMessage Query = await Http.PostAsync("api/account/sendverifyemail", new FormUrlEncodedContent(formData) );
|
||||
bool result = await Query.Content.ReadFromJsonAsync<bool>();
|
||||
if (result == true ) {
|
||||
EmailSentResult = "Email Sent";
|
||||
} else {
|
||||
@@ -108,8 +112,13 @@
|
||||
return;
|
||||
}
|
||||
if (_account != null){
|
||||
HttpResponseMessage TryChangePassword = await Http.PostAsJsonAsync("api/account/changepassword", new MistoxWebsite.Shared.Account(){ UserName = _account.UserName, PasswordHash = CurPass, Error = NewPass1 });
|
||||
bool resultText = await TryChangePassword.Content.ReadFromJsonAsync<bool>();
|
||||
Dictionary<string, string> formData = new Dictionary<string, string>{
|
||||
{ "UserName", _account.UserName },
|
||||
{ "OldPassword", CurPass },
|
||||
{ "NewPassword", NewPass1 }
|
||||
};
|
||||
HttpResponseMessage Query = await Http.PostAsync("api/account/changepassword", new FormUrlEncodedContent(formData) );
|
||||
bool resultText = await Query.Content.ReadFromJsonAsync<bool>();
|
||||
if (resultText == true ) {
|
||||
PasswordErrorText = "Password changed successfully";
|
||||
} else {
|
||||
|
||||
@@ -5,10 +5,6 @@
|
||||
margin-bottom: 1.4rem;
|
||||
}
|
||||
|
||||
.title-frame{
|
||||
|
||||
}
|
||||
|
||||
.title-frame h1 input{
|
||||
padding-left: 1.4rem;
|
||||
padding-top: 0.4rem;
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
body {
|
||||
}
|
||||
|
||||
.lower-frame{
|
||||
.lower-frame{
|
||||
padding: 1.4rem;
|
||||
}
|
||||
@@ -119,12 +119,12 @@
|
||||
}
|
||||
|
||||
async Task confirmDeleteAccount() {
|
||||
HttpResponseMessage Delete = await Http.PostAsJsonAsync( "api/account/delete", new MistoxWebsite.Shared.Account(){
|
||||
ID = Statics.User.ID,
|
||||
UserName = Statics.User.Email,
|
||||
PasswordHash = Password
|
||||
});
|
||||
string result = await Delete.Content.ReadAsStringAsync();
|
||||
Dictionary<string, string> formData = new Dictionary<string, string>{
|
||||
{ "UserName", Statics.User.UserName },
|
||||
{ "Password", Password },
|
||||
};
|
||||
HttpResponseMessage Query = await Http.PostAsync("api/account/delete", new FormUrlEncodedContent(formData) );
|
||||
string result = await Query.Content.ReadAsStringAsync();
|
||||
bool status = result == "true" ? true : false;
|
||||
if (status){
|
||||
await Http.PostAsync("api/account/logout", new StringContent(""));
|
||||
|
||||
@@ -6,28 +6,11 @@
|
||||
<div class="Big-Div">
|
||||
|
||||
<div id="DirTree">
|
||||
@if (output != null ) {
|
||||
<ExplorerChild Title=@output.Path Children=output.Children PartialPath="\"></ExplorerChild>
|
||||
}
|
||||
|
||||
</div>
|
||||
|
||||
<span>@ErrorTxt</span>
|
||||
</div>
|
||||
|
||||
@code{
|
||||
|
||||
public string ErrorTxt = "";
|
||||
public DirObj? output = null;
|
||||
|
||||
protected override async void OnInitialized() {
|
||||
try {
|
||||
byte[] resultBody = await (await Http.PostAsync( "api/product/showdownloads", new StringContent("") )).Content.ReadAsByteArrayAsync();
|
||||
string JsonData = Encoding.UTF8.GetString(resultBody);
|
||||
output = JsonConvert.DeserializeObject<DirObj>( JsonData );
|
||||
base.StateHasChanged();
|
||||
} catch( Exception e ) {
|
||||
ErrorTxt = "Error : " + e.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,283 +0,0 @@
|
||||
@page "/resume/derek"
|
||||
|
||||
<div class="PopOutFrame">
|
||||
<div class="Content" style="height: 170px !important;">
|
||||
<div class="ImgFrame">
|
||||
<img class="Picture" src="/img/ResumeFace.jpg" />
|
||||
</div>
|
||||
<div class="NameFrame">
|
||||
<h1>Derek Holloway</h1>
|
||||
<h1>Owner and sole developer</h1>
|
||||
</div>
|
||||
<div class="ContactFrame">
|
||||
<h1>derek@mistox.net</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="PopOutHr"></div>
|
||||
</div>
|
||||
|
||||
<div class="PopOutFrame">
|
||||
<div class="Content">
|
||||
<h1 style="margin: 0; margin-bottom: 5px;">Work Experience</h1>
|
||||
<!-- NAVWAR Assistant Contract Tech. Rep. -->
|
||||
<div class="capsule" @onmouseenter="()=>{ MouseEnter(1); }" @onmouseleave="()=>{ MouseLeave(1); }">
|
||||
<div class="Skills" style="height: calc(100% - 40px);">
|
||||
<div class="paddedcell">
|
||||
<h2 class="jobTitle">NAVWAR Assistant Contract Tech. Rep.</h2>
|
||||
<h3 class="jobSub">Redhorse corp. - San Diego, CA</h3>
|
||||
<h3 class="jobSub">888-445-8010</h3>
|
||||
<h3 class="jobSub">February 2022 - Today</h3>
|
||||
<span></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="SkillsContent colored" style="height: calc(100% - 40px); @ContentStyle1">
|
||||
<div class="paddedcell">
|
||||
<ul>
|
||||
<li><span>The first line of support for end users</span></li>
|
||||
<li><span>Fix or escalate issues as required to the correct authority for resolution</span></li>
|
||||
<li><span>The ACTR performs routine office IT functions managing mechanical and printer supplies</span></li>
|
||||
<li><span>Assisting with connectivity to and troubleshooting networked systems and Video Teleconferences</span></li>
|
||||
<li><span>This includes setting up new accounts</span></li>
|
||||
<li><span>Managing users accesses</span></li>
|
||||
<li><span>Uses the building badging system to grant access to appropriate personnel Assist with transition to Office 365 and Navy Flank Speed as required.</span></li>
|
||||
<li><span>Leading role on Junior level tasks/projects</span></li>
|
||||
<li><span>Supports the customer performing moderately complex tasks on a routine basis.</span></li>
|
||||
<br />
|
||||
<li><span>Project manager for NAVWAR tech refresh</span></li>
|
||||
<li><span>Replacing 4010+ computers within a 1 year time-frame</span></li>
|
||||
<li><span>Manage warranties with HP Federal</span></li>
|
||||
<li><span>Coordinating orders and returns for old leased hardware</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- NMCI Field Service -->
|
||||
<div class="capsule" @onmouseenter="()=>{ MouseEnter(2); }" @onmouseleave="()=>{ MouseLeave(2); }">
|
||||
<div class="Skills" style="height: calc(100% - 40px);">
|
||||
<div class="paddedcell">
|
||||
<h2 class="jobTitle">NMCI Field Service Technitian</h2>
|
||||
<h3 class="jobSub">Super Systems Inc - San Diego, CA</h3>
|
||||
<h3 class="jobSub">757-399-3000 - info@supersystemsinc.com</h3>
|
||||
<h3 class="jobSub">June 2021 - Feburary 2022</h3>
|
||||
<br />
|
||||
<h3 class="jobSub">Ohm Systems, Inc - San Diego, CA</h3>
|
||||
<h3 class="jobSub">215-675-2766 - info@ohmsysinc.com</h3>
|
||||
<h3 class="jobSub">February 2021 - June 2021</h3>
|
||||
<span></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="SkillsContent colored" style="height: calc(100% - 40px); @ContentStyle2">
|
||||
<div class="paddedcell">
|
||||
<ul>
|
||||
<li><span>Performed layer 1 network troubleshooting; windows netsh firewalls, 802.1x Authentication issues, and cable and port issues.</span></li>
|
||||
<li><span>Performed hardware troubleshooting and replacements; replacing laptop motherboards, displays, cpus, ram, and peripherals.</span></li>
|
||||
<li><span>Performed software troubleshooting using event viewer, task manager, and command prompt. By uninstalling and reinstalling or reconfiguring.</span></li>
|
||||
<li><span>Worked with network printers, voip's, and video telecommunication devices.</span></li>
|
||||
<li><span>Worked face to face with customers, managing my time between calls and work orders.</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- NMCI Help Desk -->
|
||||
<div class="capsule" @onmouseenter="()=>{ MouseEnter(3); }" @onmouseleave="()=>{ MouseLeave(3); }">
|
||||
<div class="Skills" style="height: calc(100% - 40px);">
|
||||
<div class="paddedcell">
|
||||
<h2 class="jobTitle">NMCI Help Desk Technitian</h2>
|
||||
<h3 class="jobSub">Apex Systems - Coronado, CA</h3>
|
||||
<h3 class="jobSub">619-757-1646</h3>
|
||||
<h3 class="jobSub">September 2019 - September 2020</h3>
|
||||
<span></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="SkillsContent colored" style="height: calc(100% - 40px); @ContentStyle3">
|
||||
<div class="paddedcell">
|
||||
<ul>
|
||||
<li><span>Performed remote troubleshooting: windows cmd, winrs, rdc, winrs. Fixing software issues</span></li>
|
||||
<li><span>Performed administrative Tasks: create active directory accounts and verifying identity to unlock accounts.</span></li>
|
||||
<li><span>Walked users through diagnosing network issues over the phone or escalated issue to field services</span></li>
|
||||
<li><span>Fixed users email issues; server mappings, proxy email addresses, shared emails, and outlook related issues.</span></li>
|
||||
<li><span>Moved users profiles from one domain to another and moved users files along with it.</span></li>
|
||||
<li><span>Fixed account related issues; id to user mismatch and wrong display name.</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Warehouse Reciever -->
|
||||
<div class="capsule" @onmouseenter="()=>{ MouseEnter(4); }" @onmouseleave="()=>{ MouseLeave(4); }">
|
||||
<div class="Skills" style="height: calc(100% - 40px);">
|
||||
<div class="paddedcell">
|
||||
<h2 class="jobTitle">Warehouse receiver</h2>
|
||||
<h3 class="jobSub">Ababa Bolt - El Cajon, CA</h3>
|
||||
<h3 class="jobSub">619-440-1781</h3>
|
||||
<h3 class="jobSub">May 2019 - August 2019</h3>
|
||||
<span></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="SkillsContent colored" style="height: calc(100% - 40px); @ContentStyle4">
|
||||
<div class="paddedcell">
|
||||
<ul>
|
||||
<li><span>Verified that all parts came in off the packing slip</span></li>
|
||||
<li><span>Rejected parts that were damaged and sent back to manufacturer</span></li>
|
||||
<li><span>Sort and add parts into the tracking system</span></li>
|
||||
<li><span>Put parts away in appropriate areas</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Warehouse packer -->
|
||||
<div class="capsule" @onmouseenter="()=>{ MouseEnter(5); }" @onmouseleave="()=>{ MouseLeave(5); }">
|
||||
<div class="Skills" style="height: calc(100% - 40px);">
|
||||
<div class="paddedcell">
|
||||
<h2 class="jobTitle">Warehouse packer</h2>
|
||||
<h3 class="jobSub">Ababa Bolt - El Cajon, CA</h3>
|
||||
<h3 class="jobSub">619-440-1781</h3>
|
||||
<h3 class="jobSub">October 2017 - September 2018</h3>
|
||||
<span></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="SkillsContent colored" style="height: calc(100% - 40px); @ContentStyle5">
|
||||
<div class="paddedcell">
|
||||
<ul>
|
||||
<li><span>Find which parts need more stock on shelves</span></li>
|
||||
<li><span>Split out parts by count or weight</span></li>
|
||||
<li><span>Verified and marked appropriate compliance such as RoHS</span></li>
|
||||
<li><span>Operated forklifts and scissor lifts</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- California Army National Guard -->
|
||||
<div class="capsule" @onmouseenter="()=>{ MouseEnter(6); }" @onmouseleave="()=>{ MouseLeave(6); }">
|
||||
<div class="Skills" style="height: calc(100% - 40px);">
|
||||
<div class="paddedcell">
|
||||
<h2 class="jobTitle">Motor Vehicle Trasport Operator</h2>
|
||||
<h3 class="jobSub">California Army National Guard</h3>
|
||||
<h3 class="jobSub">760-607-8574</h3>
|
||||
<h3 class="jobSub">September 2018 - Today</h3>
|
||||
<h3 class="jobSub">Rank/Grade - Specialist / E-4</h3>
|
||||
<span></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="SkillsContent colored" style="height: calc(100% - 40px); @ContentStyle6">
|
||||
<div class="paddedcell">
|
||||
<ul>
|
||||
<li><span>88M - Motor Transport Operator</span></li>
|
||||
<li><span>Neccesarry to hold secret clearence and keep all cyber security certifications up to date.</span></li>
|
||||
<li><span>June 2020 - Protected and defended the Los Alamitos police department and Six Flags Magic Mountain during the rios cause by BLM movement that caused rioting in the streets.</span></li>
|
||||
<li><span>September 2020 - Worked with Cal-Fire in Chico, CA and Alderpoint, CA to cut fire lines to prevent the spread of fires during the <a href="https://en.wikipedia.org/wiki/August_Complex_fire">August Fire Complex</a> fires.</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="PopOutHr"></div>
|
||||
</div>
|
||||
|
||||
<div class="PopOutFrame" @onmouseenter="()=>{ MouseEnter(7); }" @onmouseleave="()=>{ MouseLeave(7); }">
|
||||
<div class="Content">
|
||||
<div class="Skills">
|
||||
<h1>Development</h1>
|
||||
<ul>
|
||||
<li class="LIPrime">C#</li>
|
||||
<li>Mono</li>
|
||||
<li>ASP.NET</li>
|
||||
<li>ASP Core</li>
|
||||
<li>Blazor Web Assembly</li>
|
||||
<li>Windows Forms Apps</li>
|
||||
<li class="LIPrime">C++</li>
|
||||
<li>Arm Embedded</li>
|
||||
<li>Raspberry Pi</li>
|
||||
<li class="LIPrime">Database</li>
|
||||
<li>MySql</li>
|
||||
<li>MsSql</li>
|
||||
<li>LINQ</li>
|
||||
<li class="LIPrime">Game Engines</li>
|
||||
<li>Godot</li>
|
||||
<li>Unity 3D</li>
|
||||
<li>Solar 2D</li>
|
||||
<li class="LIPrime">Web Development</li>
|
||||
<li>Front End</li>
|
||||
<li>Back End</li>
|
||||
<li>Interfaces</li>
|
||||
<li>Square Payment API</li>
|
||||
<li>Rest Clients</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="SkillsContent" style="@ContentStyle7">
|
||||
<div class="paddedcell textSection">
|
||||
<a href="https://github.com/reverseslayer/LUADNS-DDNS">LUADNS-DDNS : https://github.com/reverseslayer/LUADNS-DDNS</a><br />
|
||||
<span>This is a service that I made for </span><a href="http://luadns.com">luadns.com</a><span>. This allows free ddns by simply changing the dns name servers to luadns nameservers and running this program as a service. This was made for linux but shoud easily run on windows.</span><br /><br />
|
||||
</div>
|
||||
<div class="paddedcell textSection">
|
||||
<a href="https://github.com/reverseslayer/MistoxServer">Mistox-Server : https://github.com/reverseslayer/MistoxServer</a><br />
|
||||
<span>This is a </span><a href="https://en.wikipedia.org/wiki/UDP_hole_punching">UDP Hole Punched</a><span> server; that allows clients to direct connect over the wan without opening ports. It works by having a dedicated TCP server that routes the UDP connections directly to each client. Based on this </span><a href="img/IdeaMap.jpg">Idea map.</a>
|
||||
</div>
|
||||
<div class="paddedcell textSection">
|
||||
<a href="https://www.mistox.net">Mistox.net : https://mistox.net</a><br />
|
||||
<span>Mistox.net is all done by me. The DNS is hosted by <a href="https://domains.google.com">domains.google.com</a> and pushed through <a href="http://luadns.com">luadns.com</a> name server so that I can run LUA-DDNS a service I made to reach other places that behind ddns. The webservers are hosted by <a href="https://www.vultr.com/">vultr.com</a> and the entire stack is built on <a href="https://dotnet.microsoft.com/en-us/apps/aspnet">asp.net</a>. The payment services are run through <a href="https://stripe.com/">stripe-payments</a>. I built this as a side project but its slowly becoming more and more something that I would like to be able to share things that I make; paid or free.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="PopOutHr" style="margin-bottom: 30px;"></div>
|
||||
</div>
|
||||
|
||||
|
||||
@code {
|
||||
string ContentStyle1 = "";
|
||||
string ContentStyle2 = "";
|
||||
string ContentStyle3 = "";
|
||||
string ContentStyle4 = "";
|
||||
string ContentStyle5 = "";
|
||||
string ContentStyle6 = "";
|
||||
string ContentStyle7 = "";
|
||||
|
||||
void MouseEnter( int frameNumber ) {
|
||||
if (frameNumber == 1){
|
||||
ContentStyle1 = "right: 0px;";
|
||||
base.StateHasChanged();
|
||||
}else if (frameNumber == 2){
|
||||
ContentStyle2 = "right: 0px;";
|
||||
base.StateHasChanged();
|
||||
}else if (frameNumber == 3){
|
||||
ContentStyle3 = "right: 0px;";
|
||||
base.StateHasChanged();
|
||||
}else if (frameNumber == 4){
|
||||
ContentStyle4 = "right: 0px;";
|
||||
base.StateHasChanged();
|
||||
}else if (frameNumber == 5){
|
||||
ContentStyle5 = "right: 0px;";
|
||||
base.StateHasChanged();
|
||||
}else if (frameNumber == 6){
|
||||
ContentStyle6 = "right: 0px;";
|
||||
base.StateHasChanged();
|
||||
}else if (frameNumber == 7){
|
||||
ContentStyle7 = "right: 0px;";
|
||||
base.StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void MouseLeave( int frameNumber ){
|
||||
if (frameNumber == 1){
|
||||
ContentStyle1 = "right: -700px;";
|
||||
base.StateHasChanged();
|
||||
}else if (frameNumber == 2){
|
||||
ContentStyle2 = "right: -700px;";
|
||||
base.StateHasChanged();
|
||||
}else if (frameNumber == 3){
|
||||
ContentStyle3 = "right: -700px;";
|
||||
base.StateHasChanged();
|
||||
}else if (frameNumber == 4){
|
||||
ContentStyle4 = "right: -700px;";
|
||||
base.StateHasChanged();
|
||||
}else if (frameNumber == 5){
|
||||
ContentStyle5 = "right: -700px;";
|
||||
base.StateHasChanged();
|
||||
}else if (frameNumber == 6){
|
||||
ContentStyle6 = "right: -700px;";
|
||||
base.StateHasChanged();
|
||||
}else if (frameNumber == 7){
|
||||
ContentStyle7 = "right: -700px;";
|
||||
base.StateHasChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,191 +0,0 @@
|
||||
* {
|
||||
--popout-shadow-color-left: #8c8c8c;
|
||||
--popout-shadow-color-bottom: #595959;
|
||||
--popout-background-color: #004262;
|
||||
--frame-background-color: #005662;
|
||||
--frame-title-color: #ffffff;
|
||||
--job-title-color: #f35100;
|
||||
--job-sub-color: #c85c00;
|
||||
--text-color: #dddddd;
|
||||
--link-color: #4cff00;
|
||||
--link-visited-color: #73ac5b;
|
||||
--skills-bg-color: #c85c00;
|
||||
--skills-text-color: #000;
|
||||
--skills-text-shadow-color: #f35100;
|
||||
--skills-prime-background-color: #972500;
|
||||
--skills-prime-text-color: #fff;
|
||||
}
|
||||
|
||||
body {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: var(--frame-title-color);
|
||||
}
|
||||
|
||||
span {
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.PopOutFrame {
|
||||
position: relative;
|
||||
background-color: white;
|
||||
width: 100%;
|
||||
max-width: 1080px;
|
||||
margin: 15px auto 0 auto;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.PopOutFrame::before {
|
||||
position: absolute;
|
||||
width: 6px;
|
||||
left: -6px;
|
||||
margin-top: 6px;
|
||||
background: var(--popout-shadow-color-left);
|
||||
content: "";
|
||||
display: block;
|
||||
transform: skew(0deg, -61deg);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.PopOutHr {
|
||||
width: 100%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.PopOutHr::after {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
margin-top: 0px;
|
||||
bottom: -11px;
|
||||
left: -3px;
|
||||
background: var(--popout-shadow-color-bottom);
|
||||
content: "";
|
||||
display: block;
|
||||
transform: skew(-31deg, 0deg);
|
||||
height: 11px;
|
||||
}
|
||||
|
||||
.Content{
|
||||
position: relative;
|
||||
padding: 15px;
|
||||
overflow: hidden;
|
||||
background-color: var(--popout-background-color);
|
||||
}
|
||||
|
||||
.ImgFrame {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.Picture{
|
||||
width: 140px;
|
||||
height: 140px;
|
||||
}
|
||||
|
||||
.NameFrame {
|
||||
float: left;
|
||||
width: calc(100% - 510px);
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.ContactFrame {
|
||||
float: left;
|
||||
width: 300px;
|
||||
height: 140px;
|
||||
}
|
||||
|
||||
.ContactFrame h1{
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
.SkillsContent {
|
||||
position: relative;
|
||||
float: left;
|
||||
height: 100%;
|
||||
width: 60%;
|
||||
transition-duration: 2s;
|
||||
right: -700px;
|
||||
}
|
||||
|
||||
.SkillsContent :link {
|
||||
color: var(--link-color);
|
||||
}
|
||||
|
||||
.SkillsContent :visited{
|
||||
color: var(--link-visited-color) !important;
|
||||
}
|
||||
|
||||
.paddedcell {
|
||||
padding: 10px 5px;
|
||||
padding-bottom: 0;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.colored {
|
||||
background-color: var(--frame-background-color);
|
||||
}
|
||||
|
||||
.paddedcell br{
|
||||
display: block;
|
||||
margin: 10px 0;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.Skills {
|
||||
float: left;
|
||||
height: 100%;
|
||||
width: 40%;
|
||||
transition-duration: 2s;
|
||||
}
|
||||
|
||||
.Skills h1{
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.Skills ul{
|
||||
font-size: 14px;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0 5px;
|
||||
}
|
||||
|
||||
.Skills li {
|
||||
float: left;
|
||||
padding: 4px 6px;
|
||||
margin: 0 4px 4px 0;
|
||||
background-color: var(--skills-bg-color);
|
||||
text-shadow: 0 1px 1px var(--skills-text-shadow-color);
|
||||
color: var(--skills-text-color);
|
||||
}
|
||||
|
||||
.LIPrime{
|
||||
text-shadow: none;
|
||||
background-color: var(--skills-prime-background-color) !important;
|
||||
color: var(--skills-prime-text-color) !important;
|
||||
clear: left;
|
||||
}
|
||||
|
||||
.capsule {
|
||||
margin-top: 15px;
|
||||
overflow: hidden;
|
||||
border: solid var(--frame-background-color);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.jobTitle {
|
||||
margin: 0;
|
||||
color: var(--job-title-color);
|
||||
}
|
||||
|
||||
.jobSub {
|
||||
margin: 0;
|
||||
color: var(--job-sub-color);
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.textSection {
|
||||
margin-top: 15px;
|
||||
background-color: var(--frame-background-color);
|
||||
border-radius: 5px;
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
<button type="button" class="collapsible" @onclick=OpenCollapseable>@Title</button>
|
||||
|
||||
<ul class="dropdown-content" style="display : @collapseStyle;">
|
||||
@if (Children != null){
|
||||
@foreach(var Cur in Children){
|
||||
<li>
|
||||
@if(Cur.Type == FileType.Directory) {
|
||||
<ExplorerChild Title=@Cur.Path Children=Cur.Children PartialPath=@(PartialPath+Cur.Path) ></ExplorerChild>
|
||||
} else {
|
||||
<button type="button" @onclick=@((e)=>{ Download(Cur.Path); })>@Cur.Path</button>
|
||||
}
|
||||
</li>
|
||||
}
|
||||
}
|
||||
</ul>
|
||||
|
||||
@code{
|
||||
[Parameter]
|
||||
public string Title{ get; set; } = "";
|
||||
[Parameter]
|
||||
public DirObj[]? Children{ get; set; }
|
||||
[Parameter]
|
||||
public string PartialPath{ get; set; } = "";
|
||||
|
||||
public string collapseStyle = "none";
|
||||
|
||||
void OpenCollapseable() {
|
||||
if (collapseStyle == "block") {
|
||||
collapseStyle = "none";
|
||||
} else {
|
||||
collapseStyle = "block";
|
||||
}
|
||||
}
|
||||
|
||||
void Download(string Path) {
|
||||
Nav.NavigateTo( "api/product/download?Product=" + PartialPath + Path, true );
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
@code {
|
||||
protected override void OnInitialized() {
|
||||
if (Statics.User.ID == -1 ) {
|
||||
Nav.NavigateTo( "/account/login?ReturnURL=Null" );
|
||||
Nav.NavigateTo( "/account/login" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
@page "/snake"
|
||||
|
||||
<div @onkeydown="OnKeyDown" tabindex="0" style="background-color: #333;" >
|
||||
<h1 id="Score" style="width: 100%; text-align: center; color:#fff;">Score : 0</h1>
|
||||
<div id="BODY" style="position: relative; margin-bottom: 5px; margin-left: 50%; right: 300px; background-color: #666; width: 600px; height: 600px;">
|
||||
<!-- Game -->
|
||||
|
||||
@foreach(SnakePart part in SnakeParts ) {
|
||||
<div style="position: absolute; left: @part.getX(); top: @part.getY(); width: 10px; height: 10px; background-color: #111; border: 0; padding: 0; margin: 0;"></div>
|
||||
}
|
||||
<div style="position: absolute; left: @Collectable.getX(); top: @Collectable.getY(); width: 10px; height: 10px; background-color: #f00; border: 0; padding: 0; margin: 0;"></div>
|
||||
|
||||
<!-- End Game -->
|
||||
</div>
|
||||
<div id="PauseScreen"style="position: relative; display: none; width: 500px; margin-left: 50%; right: 250px;">
|
||||
<h2 style="text-align: center; color: #f00; ">Game Paused</h2>
|
||||
</div>
|
||||
<div style="margin: 0 40px; width: calc(100% - 80px); background-color: #777;">
|
||||
<h3 style="text-align: center; font-size: 25px; color: #0f0; padding: 0; margin: 0; border: 0;">LEADERBOARD</h3>
|
||||
</div>
|
||||
<hr style="margin: 0px; width:calc(100% - 82px);" />
|
||||
<div id="Scoreboard" style="margin: 0 40px; width: calc(100% - 80px); background-color: #777;"></div>
|
||||
<h3 style="position: absolute; right: 10px; bottom: 3px; color: #fff;">Designed by Derek in California</h3>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
struct SnakePart {
|
||||
public int X{ get; set; }
|
||||
public int Y{ get; set; }
|
||||
public int Hue{ get; set; }
|
||||
|
||||
public string getX() {
|
||||
return X * 10 + "px";
|
||||
}
|
||||
public string getY() {
|
||||
return Y * 10 + "px";
|
||||
}
|
||||
}
|
||||
enum Direction {
|
||||
Up,
|
||||
Down,
|
||||
Left,
|
||||
Right
|
||||
}
|
||||
|
||||
List<SnakePart> SnakeParts = new List<SnakePart>(){
|
||||
new SnakePart{ X = 5, Y = 10 }, // Tail
|
||||
new SnakePart{ X = 6, Y = 10 },
|
||||
new SnakePart{ X = 7, Y = 10 },
|
||||
new SnakePart{ X = 8, Y = 10 } // Head
|
||||
};
|
||||
int Score = 0;
|
||||
bool Paused = false;
|
||||
Direction SnakeDirection = Direction.Right;
|
||||
int FrameRate = 1000 / 10;
|
||||
int HueRate = 5;
|
||||
|
||||
SnakePart Collectable = new SnakePart{ X = 15, Y = 15 };
|
||||
|
||||
|
||||
void OnKeyDown(KeyboardEventArgs e) {
|
||||
Console.WriteLine(e.Key);
|
||||
if (e.Key.ToLower() == "w" ) {
|
||||
SnakeDirection = Direction.Up;
|
||||
}else if (e.Key.ToLower() == "a" ) {
|
||||
SnakeDirection = Direction.Left;
|
||||
}else if (e.Key.ToLower() == "s" ) {
|
||||
SnakeDirection = Direction.Down;
|
||||
}else if (e.Key.ToLower() == "d" ) {
|
||||
SnakeDirection = Direction.Right;
|
||||
}
|
||||
}
|
||||
|
||||
bool CheckSelfHit() {
|
||||
foreach(SnakePart cur in SnakeParts ) {
|
||||
if (SnakeParts[SnakeParts.Count-1].X == cur.X ) {
|
||||
if (SnakeParts[SnakeParts.Count-1].Y == cur.Y ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CheckBounds() {
|
||||
if (SnakeParts[SnakeParts.Count-1].X > 0 && SnakeParts[SnakeParts.Count-1].X < 50 ) {
|
||||
if (SnakeParts[SnakeParts.Count-1].Y > 0 && SnakeParts[SnakeParts.Count-1].Y < 50 ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CheckCollectibleHit() { // return true if hit
|
||||
if (SnakeParts[SnakeParts.Count-1].X == Collectable.X ) {
|
||||
if (SnakeParts[SnakeParts.Count-1].Y == Collectable.Y ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ResetCollectable() {
|
||||
Collectable.X = new Random().Next(1, 40);
|
||||
Collectable.Y = new Random().Next(1, 40);
|
||||
}
|
||||
|
||||
void Die() {
|
||||
|
||||
}
|
||||
|
||||
void Update() {
|
||||
// Get Next Position
|
||||
if( SnakeDirection == Direction.Up ) {
|
||||
SnakeParts.Add( new SnakePart {
|
||||
X = SnakeParts[SnakeParts.Count-1].X,
|
||||
Y = SnakeParts[SnakeParts.Count-1].Y - 1,
|
||||
Hue = SnakeParts[SnakeParts.Count-1].Hue + HueRate
|
||||
});
|
||||
}else if (SnakeDirection == Direction.Right ) {
|
||||
SnakeParts.Add( new SnakePart {
|
||||
X = SnakeParts[SnakeParts.Count-1].X + 1,
|
||||
Y = SnakeParts[SnakeParts.Count-1].Y,
|
||||
Hue = SnakeParts[SnakeParts.Count-1].Hue + HueRate
|
||||
});
|
||||
}else if (SnakeDirection == Direction.Down ) {
|
||||
SnakeParts.Add( new SnakePart {
|
||||
X = SnakeParts[SnakeParts.Count-1].X,
|
||||
Y = SnakeParts[SnakeParts.Count-1].Y + 1,
|
||||
Hue = SnakeParts[SnakeParts.Count-1].Hue + HueRate
|
||||
});
|
||||
}else if (SnakeDirection == Direction.Left ) {
|
||||
SnakeParts.Add( new SnakePart {
|
||||
X = SnakeParts[SnakeParts.Count-1].X - 1,
|
||||
Y = SnakeParts[SnakeParts.Count-1].Y,
|
||||
Hue = SnakeParts[SnakeParts.Count-1].Hue + HueRate
|
||||
});
|
||||
}
|
||||
if (CheckSelfHit() && CheckBounds() ) {
|
||||
if( CheckCollectibleHit() ) {
|
||||
Score += 1;
|
||||
ResetCollectable();
|
||||
} else {
|
||||
SnakeParts.RemoveAt( 0 );
|
||||
}
|
||||
} else {
|
||||
Die();
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
protected override void OnInitialized() {
|
||||
ResetCollectable();
|
||||
var timer = new System.Threading.Timer((e) => {
|
||||
if (!Paused){
|
||||
Update();
|
||||
}
|
||||
}, null, 0, FrameRate );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
<h3 class="cart-title">Cart</h3>
|
||||
|
||||
<div class="Spacer">
|
||||
@foreach( MistoxWebsite.Shared.Cart obj in Statics.Carts ) {
|
||||
@foreach( MistoxWebsite.Shared.Database.Cart obj in Statics.Carts ) {
|
||||
<div class="cart-item">
|
||||
<h1>@getItem(obj.ProductID)?.Name</h1>
|
||||
@foreach( string cur in getItem( obj.ProductID )?.Images ) {
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
protected override void OnInitialized() {
|
||||
total = 0;
|
||||
foreach( MistoxWebsite.Shared.Cart obj in Statics.Carts ) {
|
||||
foreach( MistoxWebsite.Shared.Database.Cart obj in Statics.Carts ) {
|
||||
foreach( Product item in Statics.Products ) {
|
||||
if( obj.ProductID == item.ID ) {
|
||||
total = total + (item.Cost / 100f);
|
||||
|
||||
@@ -99,7 +99,7 @@
|
||||
|
||||
public bool isOwned(int ID ) {
|
||||
if(Statics.Owned.Count > 0 ) {
|
||||
foreach( MistoxWebsite.Shared.Receipt cur in Statics.Owned ) {
|
||||
foreach( MistoxWebsite.Shared.Database.Receipt cur in Statics.Owned ) {
|
||||
if( cur.ProductID == ID ) {
|
||||
return true;
|
||||
}
|
||||
@@ -109,7 +109,7 @@
|
||||
}
|
||||
|
||||
public bool isInCart(int id) {
|
||||
foreach( MistoxWebsite.Shared.Cart cur in Statics.Carts ) {
|
||||
foreach( MistoxWebsite.Shared.Database.Cart cur in Statics.Carts ) {
|
||||
if (cur.ProductID == id ) {
|
||||
return true;
|
||||
}
|
||||
@@ -118,7 +118,7 @@
|
||||
}
|
||||
|
||||
public async void onAddToCart( int ID ) {
|
||||
MistoxWebsite.Shared.Cart item = new MistoxWebsite.Shared.Cart {
|
||||
MistoxWebsite.Shared.Database.Cart item = new MistoxWebsite.Shared.Database.Cart {
|
||||
ProductID = ID,
|
||||
AccountID = Statics.User.ID
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
using MistoxWebsite.Shared;
|
||||
using MistoxWebsite.Shared.DTO.Session;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace MistoxWebsite.Client.AuthState {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using MistoxWebsite.Shared;
|
||||
using MistoxWebsite.Shared.Database;
|
||||
|
||||
namespace MistoxWebsite.Client.Statics {
|
||||
public class Statics {
|
||||
|
||||
@@ -1,24 +1,28 @@
|
||||
@using System.Net.Http
|
||||
@using System.Net.Http.Json
|
||||
@using System.Net.Mail
|
||||
@using System.Security.Claims
|
||||
@using System.Security.Cryptography
|
||||
@using System.Text
|
||||
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@using Microsoft.AspNetCore.Components.Authorization
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
@using Microsoft.AspNetCore.Components.Routing
|
||||
@using Microsoft.AspNetCore.Components.Web
|
||||
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
||||
@using Microsoft.AspNetCore.Components.WebAssembly.Http
|
||||
@using Microsoft.JSInterop
|
||||
@using MistoxWebsite.Client
|
||||
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@using Microsoft.AspNetCore.Components.Authorization
|
||||
@using System.Security.Claims
|
||||
@using MistoxWebsite.Client
|
||||
@using MistoxWebsite.Client.AuthState
|
||||
@using MistoxWebsite.Client.Statics
|
||||
@using System.Security.Cryptography
|
||||
@using System.Text
|
||||
@using MistoxWebsite.Shared
|
||||
@using Newtonsoft.Json
|
||||
|
||||
@using MistoxWebsite.Client.Pages.Shared
|
||||
@using MistoxWebsite.Shared.Database
|
||||
@using MistoxWebsite.Shared.DTO.Account
|
||||
@using MistoxWebsite.Shared.DTO.Session
|
||||
|
||||
@using Newtonsoft.Json
|
||||
|
||||
@inject IJSRuntime JS
|
||||
@inject NavigationManager Nav
|
||||
|
||||
@@ -13,29 +13,27 @@ namespace MistoxWebsite.Server.Controllers {
|
||||
|
||||
DatabaseService _accountContext;
|
||||
EmailService _emailContext;
|
||||
|
||||
public AuthenticationController( DatabaseService DatabaseContext, EmailService emailContext ) {
|
||||
|
||||
public AuthenticationController(DatabaseService DatabaseContext, EmailService emailContext) {
|
||||
_accountContext = DatabaseContext;
|
||||
_emailContext = emailContext;
|
||||
}
|
||||
|
||||
// In Account -> References UserName / PasswordHash
|
||||
// Out Account
|
||||
[Route( "api/account/login" )]
|
||||
[Route("api/account/login")]
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<Account>> Login( [FromBody] Account request ) {
|
||||
public async Task<ActionResult<Account>> Login([FromForm] string UserName, [FromForm] string PasswordHash, [FromForm] bool StayLoggedIn) {
|
||||
try {
|
||||
Account? test = await _accountContext.GetAccount(request.UserName.ToLower());
|
||||
if( test != null ) {
|
||||
if( test.EmailVerified == true ) {
|
||||
if( test.SiteData.FailedPasswordLock ) {
|
||||
if( test.SiteData.CurrentPasswordAttempts >= test.SiteData.PasswordAttempts ) {
|
||||
Account? test = await _accountContext.GetAccount(UserName.ToLower());
|
||||
if (test != null) {
|
||||
if (test.EmailVerified == true) {
|
||||
if (test.SiteData.FailedPasswordLock) {
|
||||
if (test.SiteData.CurrentPasswordAttempts >= test.SiteData.PasswordAttempts) {
|
||||
return new Account() { Error = "Too many failed password attempts. Please reset your password" };
|
||||
}
|
||||
}
|
||||
if( BCrypt.Net.BCrypt.Verify( request.PasswordHash, test.PasswordHash ) ) {
|
||||
if (BCrypt.Net.BCrypt.Verify(PasswordHash, test.PasswordHash)) {
|
||||
test.SiteData.CurrentPasswordAttempts = 0;
|
||||
await _accountContext.SetAccount( test );
|
||||
await _accountContext.SetAccount(test);
|
||||
|
||||
AccountClaims aClaims = await getClaims(test.ID);
|
||||
List<Claim> claims = new List<Claim>() {
|
||||
@@ -49,64 +47,306 @@ namespace MistoxWebsite.Server.Controllers {
|
||||
|
||||
await HttpContext.SignInAsync(
|
||||
CookieAuthenticationDefaults.AuthenticationScheme,
|
||||
new ClaimsPrincipal( new ClaimsIdentity( claims, "Auth" ) ),
|
||||
new ClaimsPrincipal(new ClaimsIdentity(claims, "Auth")),
|
||||
new AuthenticationProperties {
|
||||
ExpiresUtc = DateTime.UtcNow.AddYears(30), // Add 30 years with sliding on
|
||||
IsPersistent = request.EmailVerified, // Is set from the StayLoggedIn
|
||||
IsPersistent = StayLoggedIn, // Is set from the StayLoggedIn
|
||||
}
|
||||
);
|
||||
return test;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
test.SiteData.CurrentPasswordAttempts += 1;
|
||||
await _accountContext.SetAccount( test );
|
||||
await _accountContext.SetAccount(test);
|
||||
return new Account() { Error = "Wrong password" };
|
||||
}
|
||||
}else{
|
||||
await SendVerify(test);
|
||||
}
|
||||
else {
|
||||
await SendVerify(test.UserName);
|
||||
return new Account() { Error = "A new verify email has been sent. \n Note only 1 email send every 5 mintes" };
|
||||
}
|
||||
}
|
||||
return new Account() { Error = "User doesn't exist" };
|
||||
} catch( Exception ex ) {
|
||||
} catch (Exception ex) {
|
||||
return new Account() { Error = ex.Message };
|
||||
}
|
||||
}
|
||||
|
||||
// In Account -> References UserName / PasswordHash
|
||||
// Out Account
|
||||
[Route( "api/account/session" )]
|
||||
[Route("api/account/session")]
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<Account>> LoginSession( [FromBody] Account request ) {
|
||||
public async Task<ActionResult<Account>> LoginSession([FromBody] Account request) {
|
||||
try {
|
||||
Account? test = await _accountContext.GetAccount(request.UserName.ToLower());
|
||||
if( test != null ) {
|
||||
if( request.PasswordHash == test.PasswordHash ) {
|
||||
if (test != null) {
|
||||
if (request.PasswordHash == test.PasswordHash) {
|
||||
return test;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
test.SiteData.CurrentPasswordAttempts += 1;
|
||||
await _accountContext.SetAccount( test );
|
||||
await _accountContext.SetAccount(test);
|
||||
return new Account() { Error = "Wrong password" };
|
||||
}
|
||||
}
|
||||
return new Account() { Error = "User doesn't exist" };
|
||||
} catch( Exception ex ) {
|
||||
} catch (Exception ex) {
|
||||
return new Account() { Error = ex.Message };
|
||||
}
|
||||
}
|
||||
|
||||
// In Account
|
||||
// Out List<String>
|
||||
[Route( "api/account/claims" )]
|
||||
[Route("api/account/claims")]
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<AccountClaims>> Claims( [FromBody] Account Account ) {
|
||||
public async Task<ActionResult<AccountClaims>> Claims([FromBody] Account Account) {
|
||||
AccountClaims claims = await getClaims(Account.ID);
|
||||
return claims;
|
||||
}
|
||||
|
||||
async Task<AccountClaims> getClaims( int AccountID ) {
|
||||
[Route("api/account/register")]
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<Account>> Register([FromForm] string Email, [FromForm] string UserName, [FromForm] string PasswordHash) {
|
||||
try {
|
||||
if (await _accountContext.GetAccount(UserName.ToLower()) == null) {
|
||||
if (await _accountContext.GetAccount(Email.ToLower()) == null) {
|
||||
Account? created = new Account() {
|
||||
UserName = UserName.ToLower(),
|
||||
Email = Email.ToLower(),
|
||||
EmailVerified = false,
|
||||
PasswordHash = BCrypt.Net.BCrypt.HashPassword(PasswordHash),
|
||||
};
|
||||
await _accountContext.NewAccount(created);
|
||||
created = await _accountContext.GetAccount(Email.ToLower());
|
||||
if (created != null) {
|
||||
AccountClaims aClaims = await getClaims(created.ID);
|
||||
List<Claim> claims = new List<Claim>() {
|
||||
new Claim(ClaimTypes.Name, aClaims.UserName),
|
||||
new Claim(ClaimTypes.Email, aClaims.Email),
|
||||
new Claim("emailverified", aClaims.EmailVerified),
|
||||
new Claim(ClaimTypes.Role, aClaims.Role),
|
||||
new Claim("LockAccount", aClaims.FailedPasswordLock)
|
||||
};
|
||||
|
||||
await SendVerify(created.UserName);
|
||||
return created;
|
||||
}
|
||||
return new Account() { Error = "Unknown Error" };
|
||||
}
|
||||
else {
|
||||
return new Account() { Error = "Email is already in use" };
|
||||
}
|
||||
}
|
||||
else {
|
||||
return new Account() { Error = "UserName is taken" };
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Console.WriteLine("Error: " + ex.Message);
|
||||
return new Account() { Error = ex.Message };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[Route("api/account/changepassword")]
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<bool>> ChangePassword([FromForm]string UserName, [FromForm]string OldPassword, [FromForm]string NewPassword) {
|
||||
try {
|
||||
Account? test = await _accountContext.GetAccount(UserName.ToLower());
|
||||
if (test != null) {
|
||||
if (BCrypt.Net.BCrypt.Verify(OldPassword, test.PasswordHash)) {
|
||||
test.PasswordHash = BCrypt.Net.BCrypt.HashPassword(NewPassword);
|
||||
test.SiteData.CurrentPasswordAttempts = 0;
|
||||
await _accountContext.SetAccount(test);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[Route("api/account/toggleAccountLock")]
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<string>> ToggleAccountLock([FromForm]string UserName, [FromForm]bool AccountLock) {
|
||||
try {
|
||||
Account? test = await _accountContext.GetAccount(UserName);
|
||||
if (test != null) {
|
||||
test.SiteData.FailedPasswordLock = AccountLock;
|
||||
test.SiteData.CurrentPasswordAttempts = 0;
|
||||
await _accountContext.SetAccount(test);
|
||||
return "Account Lock Status Updated";
|
||||
}
|
||||
return "Unknown Error Occurred";
|
||||
} catch (Exception ex) {
|
||||
return ex.Message;
|
||||
}
|
||||
}
|
||||
|
||||
[Route("api/account/get")]
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<Account?>> Get() {
|
||||
try {
|
||||
if (User.Identity != null && User.Identity.IsAuthenticated) {
|
||||
string? email = User.FindFirstValue(ClaimTypes.Email);
|
||||
if (!string.IsNullOrEmpty(email)) {
|
||||
Account? test = await _accountContext.GetAccount(email);
|
||||
if (test != null) {
|
||||
return test;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Ok();
|
||||
} catch {
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
|
||||
[Route("api/account/logout")]
|
||||
[HttpPost]
|
||||
public async Task Logout() {
|
||||
await HttpContext.SignOutAsync();
|
||||
}
|
||||
|
||||
[Route("api/account/sendverifyemail")]
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<string>> SendVerify([FromForm]string UserName) {
|
||||
try {
|
||||
string key = "v" + UserName;
|
||||
// Stop from sending multiple emails quickly
|
||||
if (_emailContext._SentEmails.ContainsKey(key)) {
|
||||
DateTime PreviousSentTime = _emailContext._SentEmails.GetValueOrDefault(key);
|
||||
if (PreviousSentTime.AddMinutes(5) > DateTime.Now) {
|
||||
return "Cannot sent another verify email until 5 minutes has elapsed ";
|
||||
}
|
||||
else {
|
||||
_emailContext._SentEmails.Remove(key);
|
||||
}
|
||||
}
|
||||
Account? test = await _accountContext.GetAccount(UserName.ToLower());
|
||||
if (test != null) {
|
||||
test.SiteData.EmailToken = Guid.NewGuid().ToString();
|
||||
await _accountContext.SetAccount(test);
|
||||
|
||||
string EmailContents = EmailService.VerifyEmailEmail;
|
||||
EmailContents = Substitue(EmailContents, "@UserName", UserName);
|
||||
EmailContents = Substitue(EmailContents, "@UserName", UserName);
|
||||
EmailContents = Substitue(EmailContents, "@VerifyPassword", test.SiteData.EmailToken);
|
||||
|
||||
string result = _emailContext.Send(test.Email, EmailService.VerifyEmailSubject, EmailContents);
|
||||
_emailContext._SentEmails.Add(key, DateTime.Now);
|
||||
return result;
|
||||
}
|
||||
return "Account not found";
|
||||
} catch (Exception) {
|
||||
return "The connection couldn't be established to the email server";
|
||||
}
|
||||
}
|
||||
|
||||
[Route("api/account/verifyemail")]
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<bool>> VerifyEmail([FromForm]string UserName, [FromForm]string EmailToken) {
|
||||
try {
|
||||
Account? test = await _accountContext.GetAccount(UserName.ToLower());
|
||||
if (test != null) {
|
||||
if (test.SiteData.EmailToken == EmailToken) {
|
||||
test.SiteData.EmailToken = "";
|
||||
test.EmailVerified = true;
|
||||
await _accountContext.SetAccount(test);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[Route("api/account/sendresetpassword")]
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<string>> ResetPassword([FromForm] string Email) {
|
||||
try {
|
||||
string key = "p" + Email.ToLower();
|
||||
// Stop from sending multiple emails quickly
|
||||
if (_emailContext._SentEmails.ContainsKey(key)) {
|
||||
DateTime PreviousSentTime = _emailContext._SentEmails.GetValueOrDefault(key);
|
||||
if (PreviousSentTime.AddMinutes(5) > DateTime.Now) {
|
||||
return "Cannot sent another reset requests until 5 minutes has elapsed";
|
||||
}
|
||||
else {
|
||||
_emailContext._SentEmails.Remove(key);
|
||||
}
|
||||
}
|
||||
Account? test = await _accountContext.GetAccount(Email.ToLower());
|
||||
if (test != null) {
|
||||
test.SiteData.EmailToken = Guid.NewGuid().ToString();
|
||||
await _accountContext.SetAccount(test);
|
||||
|
||||
string EmailContents = EmailService.ResetPasswordEmail;
|
||||
EmailContents = Substitue(EmailContents, "@UserName", test.UserName);
|
||||
EmailContents = Substitue(EmailContents, "@UserName", test.UserName);
|
||||
EmailContents = Substitue(EmailContents, "@ResetPassWord", test.SiteData.EmailToken);
|
||||
|
||||
string result = _emailContext.Send(test.Email, EmailService.VerifyEmailSubject, EmailContents);
|
||||
_emailContext._SentEmails.Add(key, DateTime.Now);
|
||||
return result;
|
||||
}
|
||||
return "Account Not Found";
|
||||
} catch (Exception) {
|
||||
return "The connection couldn't be established to the email server";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[Route("api/account/resetpassword")]
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<bool>> ResetPwdVerify([FromForm] string UserName, [FromForm] string NewPassword, [FromForm] string ResetToken) {
|
||||
try {
|
||||
Account? test = await _accountContext.GetAccount(UserName.ToLower());
|
||||
if (test != null && !string.IsNullOrEmpty(test.SiteData.EmailToken)) {
|
||||
if (test.SiteData.EmailToken == ResetToken) {
|
||||
test.SiteData.CurrentPasswordAttempts = 0;
|
||||
test.PasswordHash = BCrypt.Net.BCrypt.HashPassword(NewPassword);
|
||||
await _accountContext.SetAccount(test);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[Route("api/account/delete")]
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<bool>> delete([FromForm]string UserName, [FromForm]string Password) {
|
||||
try {
|
||||
Account? test = await _accountContext.GetAccount(UserName.ToLower());
|
||||
if (test != null) {
|
||||
if (BCrypt.Net.BCrypt.Verify(Password, test.PasswordHash)) {
|
||||
await _accountContext.DeleteAccount(test);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Helper Functions
|
||||
|
||||
string Substitue(string message, string subString, string Replacement) {
|
||||
for (int i = 0; i < (message.Length - subString.Length); i++) {
|
||||
if (message.Substring(i, subString.Length) == subString) {
|
||||
string before = message.Substring(0, i);
|
||||
string after = message.Substring(i + subString.Length);
|
||||
return before + Replacement + after;
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
async Task<AccountClaims> getClaims(int AccountID) {
|
||||
try {
|
||||
Account? test = await _accountContext.GetAccountByID(AccountID);
|
||||
if( test != null ) {
|
||||
if (test != null) {
|
||||
AccountClaims aClaims = new AccountClaims() {
|
||||
UserName = test.UserName,
|
||||
Email = test.Email,
|
||||
@@ -122,265 +362,5 @@ namespace MistoxWebsite.Server.Controllers {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// In Account -> Full account
|
||||
// Out Account
|
||||
[Route( "api/account/register" )]
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<Account>> Register( [FromBody] Account request ) {
|
||||
try {
|
||||
if( await _accountContext.GetAccount( request.UserName.ToLower() ) == null ) {
|
||||
if( await _accountContext.GetAccount( request.Email.ToLower() ) == null ) {
|
||||
Account? created = new Account(){
|
||||
UserName = request.UserName.ToLower(),
|
||||
Email = request.Email.ToLower(),
|
||||
EmailVerified = false,
|
||||
PasswordHash = BCrypt.Net.BCrypt.HashPassword(request.PasswordHash),
|
||||
};
|
||||
await _accountContext.NewAccount( created );
|
||||
created = await _accountContext.GetAccount( request.Email.ToLower() );
|
||||
if( created != null ) {
|
||||
AccountClaims aClaims = await getClaims(created.ID);
|
||||
List<Claim> claims = new List<Claim>() {
|
||||
new Claim(ClaimTypes.Name, aClaims.UserName),
|
||||
new Claim(ClaimTypes.Email, aClaims.Email),
|
||||
new Claim("emailverified", aClaims.EmailVerified),
|
||||
new Claim(ClaimTypes.Role, aClaims.Role),
|
||||
new Claim("LockAccount", aClaims.FailedPasswordLock)
|
||||
};
|
||||
|
||||
await SendVerify(created);
|
||||
return created;
|
||||
}
|
||||
return new Account() { Error = "Unknown Error" };
|
||||
} else {
|
||||
return new Account() { Error = "Email is already in use" };
|
||||
}
|
||||
} else {
|
||||
return new Account() { Error = "UserName is taken" };
|
||||
}
|
||||
} catch( Exception ex ) {
|
||||
Console.WriteLine("Error: " + ex.Message);
|
||||
return new Account() { Error = ex.Message };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// In Account -> References UserName / PasswordHash( Current Password ) / Error( New Password )
|
||||
// Out Bool
|
||||
[Route( "api/account/changepassword" )]
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<bool>> ChangePassword( [FromBody] Account request ) {
|
||||
try {
|
||||
Account? test = await _accountContext.GetAccount(request.UserName.ToLower());
|
||||
if( test != null ) {
|
||||
if( BCrypt.Net.BCrypt.Verify( request.PasswordHash, test.PasswordHash ) ) {
|
||||
test.PasswordHash = BCrypt.Net.BCrypt.HashPassword( request.Error );
|
||||
test.SiteData.CurrentPasswordAttempts = 0;
|
||||
await _accountContext.SetAccount( test );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// In Account -> References UserName / SiteData FailedPasswordLock / SiteData.PasswordAttempts
|
||||
// Out Error String
|
||||
[Route( "api/account/toggleAccountLock" )]
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<string>> ToggleAccountLock( [FromBody] Account request ) {
|
||||
try {
|
||||
Account? test = await _accountContext.GetAccount(request.UserName);
|
||||
if( test != null ) {
|
||||
test.SiteData.FailedPasswordLock = request.SiteData.FailedPasswordLock;
|
||||
test.SiteData.CurrentPasswordAttempts = 0;
|
||||
test.SiteData.PasswordAttempts = request.SiteData.PasswordAttempts;
|
||||
await _accountContext.SetAccount( test );
|
||||
return "Account Lock Status Updated";
|
||||
}
|
||||
return "Unknown Error Occurred";
|
||||
} catch( Exception ex ) {
|
||||
return ex.Message;
|
||||
}
|
||||
}
|
||||
|
||||
// Out Account -> only if logged in
|
||||
[Route( "api/account/get" )]
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<Account?>> Get() {
|
||||
try {
|
||||
if( User.Identity != null && User.Identity.IsAuthenticated ) {
|
||||
string? email = User.FindFirstValue(ClaimTypes.Email);
|
||||
if( !string.IsNullOrEmpty( email ) ) {
|
||||
Account? test = await _accountContext.GetAccount(email);
|
||||
if( test != null ) {
|
||||
return test;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Ok();
|
||||
} catch {
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
|
||||
// In Null
|
||||
// Out Null
|
||||
[Route( "api/account/logout" )]
|
||||
[HttpPost]
|
||||
public async Task Logout() {
|
||||
await HttpContext.SignOutAsync();
|
||||
}
|
||||
|
||||
string Substitue( string message, string subString, string Replacement ) {
|
||||
for( int i = 0; i < (message.Length - subString.Length); i++ ) {
|
||||
if( message.Substring( i, subString.Length ) == subString ) {
|
||||
string before = message.Substring( 0, i );
|
||||
string after = message.Substring(i + subString.Length );
|
||||
return before + Replacement + after;
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// In Account -> References UserName
|
||||
// Out Success bool
|
||||
[Route( "api/account/sendverifyemail" )]
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<string>> SendVerify( [FromBody] Account request ) {
|
||||
try {
|
||||
string key = "v" + request.UserName;
|
||||
// Stop from sending multiple emails quickly
|
||||
if ( _emailContext._SentEmails.ContainsKey(key) ){
|
||||
DateTime PreviousSentTime = _emailContext._SentEmails.GetValueOrDefault(key);
|
||||
if (PreviousSentTime.AddMinutes(5) > DateTime.Now){
|
||||
return "Cannot sent another verify email until 5 minutes has elapsed ";
|
||||
}else{
|
||||
_emailContext._SentEmails.Remove(key);
|
||||
}
|
||||
}
|
||||
Account? test = await _accountContext.GetAccount(request.UserName.ToLower());
|
||||
if( test != null ) {
|
||||
test.SiteData.EmailToken = Guid.NewGuid().ToString();
|
||||
await _accountContext.SetAccount( test );
|
||||
|
||||
string EmailContents = EmailService.VerifyEmailEmail;
|
||||
EmailContents = Substitue( EmailContents, "@UserName", request.UserName );
|
||||
EmailContents = Substitue( EmailContents, "@UserName", request.UserName );
|
||||
EmailContents = Substitue( EmailContents, "@VerifyPassword", test.SiteData.EmailToken );
|
||||
|
||||
string result = _emailContext.Send( test.Email, EmailService.VerifyEmailSubject, EmailContents );
|
||||
_emailContext._SentEmails.Add(key, DateTime.Now);
|
||||
return result;
|
||||
}
|
||||
return "Account not found";
|
||||
} catch (Exception) {
|
||||
return "The connection couldn't be established to the email server";
|
||||
}
|
||||
}
|
||||
|
||||
// In Account -> References UserName / Password( EmailToken )
|
||||
// Out Success bool
|
||||
[Route( "api/account/verifyemail" )]
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<bool>> VerifyEmail( [FromBody] Account request ) {
|
||||
try {
|
||||
Account? test = await _accountContext.GetAccount(request.UserName.ToLower());
|
||||
if( test != null ) {
|
||||
if( test.SiteData.EmailToken == request.PasswordHash ) {
|
||||
test.SiteData.EmailToken = "";
|
||||
test.EmailVerified = true;
|
||||
await _accountContext.SetAccount( test );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// In Account -> References Email
|
||||
// Out Success bool
|
||||
[Route( "api/account/sendresetpassword" )]
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<string>> ResetPassword( [FromBody] Account request ) {
|
||||
try {
|
||||
string key = "p" + request.Email.ToLower();
|
||||
// Stop from sending multiple emails quickly
|
||||
if ( _emailContext._SentEmails.ContainsKey(key) ){
|
||||
DateTime PreviousSentTime = _emailContext._SentEmails.GetValueOrDefault(key);
|
||||
if (PreviousSentTime.AddMinutes(5) > DateTime.Now){
|
||||
return "Cannot sent another reset requests until 5 minutes has elapsed";
|
||||
}else{
|
||||
_emailContext._SentEmails.Remove(key);
|
||||
}
|
||||
}
|
||||
Account? test = await _accountContext.GetAccount(request.Email.ToLower());
|
||||
if( test != null ) {
|
||||
test.SiteData.EmailToken = Guid.NewGuid().ToString();
|
||||
await _accountContext.SetAccount( test );
|
||||
|
||||
string EmailContents = EmailService.ResetPasswordEmail;
|
||||
EmailContents = Substitue( EmailContents, "@UserName", test.UserName );
|
||||
EmailContents = Substitue( EmailContents, "@UserName", test.UserName );
|
||||
EmailContents = Substitue( EmailContents, "@ResetPassWord", test.SiteData.EmailToken );
|
||||
|
||||
string result = _emailContext.Send( test.Email, EmailService.VerifyEmailSubject, EmailContents );
|
||||
_emailContext._SentEmails.Add(key, DateTime.Now);
|
||||
return result;
|
||||
}
|
||||
return "Account Not Found";
|
||||
} catch (Exception) {
|
||||
return "The connection couldn't be established to the email server";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// In Account -> References UserName / Password( NewPassword ) / Error( EmailToken )
|
||||
// Out Success bool
|
||||
[Route( "api/account/resetpassword" )]
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<bool>> ResetPwdVerify( [FromBody] Account request ) {
|
||||
try {
|
||||
Account? test = await _accountContext.GetAccount(request.UserName.ToLower());
|
||||
if( test != null && !string.IsNullOrEmpty(test.SiteData.EmailToken) ) {
|
||||
if( test.SiteData.EmailToken == request.Error ) {
|
||||
test.SiteData.CurrentPasswordAttempts = 0;
|
||||
test.PasswordHash = BCrypt.Net.BCrypt.HashPassword( request.PasswordHash );
|
||||
await _accountContext.SetAccount( test );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// In Account -> References UserName / Password( Password ) )
|
||||
// Out Success bool
|
||||
[Route( "api/account/delete" )]
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<bool>> delete( [FromBody] Account request ) {
|
||||
try {
|
||||
Account? test = await _accountContext.GetAccount(request.UserName.ToLower());
|
||||
if( test != null ) {
|
||||
if( BCrypt.Net.BCrypt.Verify( request.PasswordHash, test.PasswordHash ) ) {
|
||||
await _accountContext.DeleteAccount( test );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"applicationUrl": "http://localhost:6003",
|
||||
"sslPort": 6003
|
||||
},
|
||||
"ProjectName": {
|
||||
"commandName": "Project",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"applicationUrl": "http://localhost:6003",
|
||||
"sslPort": 6003
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user