Compare commits
32 Commits
b37dcf7c7d
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 64cc5066af | |||
| ddb05c305c | |||
| b9cb93071d | |||
| ff91ff9109 | |||
| 57dca6974a | |||
| d83ba35a84 | |||
| 7160515121 | |||
| 66db26c74c | |||
| 4902f9c6ce | |||
| 16a9c5ec5f | |||
| e1d3908e29 | |||
| ea9d1fa24f | |||
| 4f6fc16494 | |||
| 123f739b61 | |||
| 0cdcf9af71 | |||
| 59d6bb1ef1 | |||
| 60d9b844fb | |||
| 1a08e99c6b | |||
| 2e8893b240 | |||
| d0af6ba73c | |||
| 059c755d14 | |||
| 34d3d047d2 | |||
| a3de3d573a | |||
| bbab4972c3 | |||
| 07a1014889 | |||
| 2ce398a8d4 | |||
| fcf64f335d | |||
| c873f473c8 | |||
| f110ad8d27 | |||
| 412624a93c | |||
| e88c7111e6 | |||
| 7c3ac165b7 |
+1
-1
@@ -2,5 +2,5 @@
|
|||||||
**/obj
|
**/obj
|
||||||
.git
|
.git
|
||||||
.env
|
.env
|
||||||
.vscode
|
|
||||||
data
|
data
|
||||||
|
Properties
|
||||||
Vendored
+25
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Launch",
|
||||||
|
"type": "coreclr",
|
||||||
|
"request": "launch",
|
||||||
|
"preLaunchTask": "dotnet: build",
|
||||||
|
"program": "${workspaceFolder}/src/MistoxWebsite.Server/bin/Debug/net9.0/MistoxWebsite.Server.dll",
|
||||||
|
"args":[],
|
||||||
|
"cwd": "${workspaceFolder}/src/MistoxWebsite.Server/",
|
||||||
|
"stopAtEntry": false,
|
||||||
|
"serverReadyAction":{
|
||||||
|
"action": "openExternally",
|
||||||
|
"killOnServerStop": false
|
||||||
|
},
|
||||||
|
"env": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||||
|
},
|
||||||
|
"sourceFileMap": {
|
||||||
|
"/Views": "${workspaceFolder}/Views"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -5,6 +5,13 @@ WORKDIR /src
|
|||||||
# Copy all projects
|
# Copy all projects
|
||||||
COPY ["src", "."]
|
COPY ["src", "."]
|
||||||
|
|
||||||
|
# Needed for AOT Compiling wasm
|
||||||
|
RUN dotnet workload install wasm-tools
|
||||||
|
|
||||||
|
# Needed for compression of AOT files
|
||||||
|
RUN apt update
|
||||||
|
RUN apt install -y python3
|
||||||
|
|
||||||
# Restore the Server
|
# Restore the Server
|
||||||
RUN dotnet restore 'MistoxWebsite.Server/MistoxWebsite.Server.csproj'
|
RUN dotnet restore 'MistoxWebsite.Server/MistoxWebsite.Server.csproj'
|
||||||
|
|
||||||
|
|||||||
@@ -25,3 +25,6 @@ Store Catalog
|
|||||||
|
|
||||||
Program
|
Program
|
||||||
Probably need to turn on cors at some point
|
Probably need to turn on cors at some point
|
||||||
|
|
||||||
|
ProductController
|
||||||
|
No way to download products
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
/* This file is needed for compile for some reason */
|
|
||||||
/* Dont delete this file */
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
<linker>
|
||||||
|
<assembly fullname="Newtonsoft.Json" preserve="all" />
|
||||||
|
<assembly fullname="MistoxWebsite.Client" preserve="all" />
|
||||||
|
</linker>
|
||||||
@@ -5,27 +5,25 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
|
||||||
|
<!-- Without Optimizations 3.92MB Initial Download / 302Kb home page load after -->
|
||||||
|
<!-- All Optimizations Without AOT 3.27MB Initial Download / 302Kb home page load after -->
|
||||||
|
<!-- All Optimizations With AOT 7.44MB Initial Download / 303Kb home page load after-->
|
||||||
|
<!-- Angular with ASPNET backend 0.49Kb Inital Download / 0.49Kb home page load after -->
|
||||||
<PublishTrimmed>true</PublishTrimmed>
|
<PublishTrimmed>true</PublishTrimmed>
|
||||||
<TrimMode>link</TrimMode>
|
<TrimMode>link</TrimMode>
|
||||||
<RunAOTCompilation>true</RunAOTCompilation>
|
<RunAOTCompilation>false</RunAOTCompilation>
|
||||||
<InvariantGlobalization>true</InvariantGlobalization>
|
<InvariantGlobalization>true</InvariantGlobalization>
|
||||||
<BlazorEnableCompression>true</BlazorEnableCompression>
|
<BlazorEnableCompression>true</BlazorEnableCompression>
|
||||||
<BlazorWebAssemblyEnableLinking>true</BlazorWebAssemblyEnableLinking>
|
|
||||||
<EnableCompressionInSingleFile>true</EnableCompressionInSingleFile>
|
<EnableCompressionInSingleFile>true</EnableCompressionInSingleFile>
|
||||||
<StripSymbols>true</StripSymbols>
|
<StripSymbols>true</StripSymbols>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<!-- Retain important files on trimming -->
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Remove="App.razor.css" />
|
<TrimmerRootDescriptor Include="ILLink.Descriptors.xml" />
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Content Include="App.razor.css">
|
|
||||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
|
||||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
|
||||||
</Content>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Packages -->
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="9.0.3" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="9.0.3" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.3" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.3" />
|
||||||
@@ -33,6 +31,7 @@
|
|||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Project References -->
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\MistoxWebsite.Shared\MistoxWebsite.Shared.csproj" />
|
<ProjectReference Include="..\MistoxWebsite.Shared\MistoxWebsite.Shared.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -34,10 +34,21 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async Task TrySendCode() {
|
public async Task TrySendCode() {
|
||||||
|
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";
|
Result = "Waiting on response from server";
|
||||||
HttpResponseMessage TestLogin = await Http.PostAsJsonAsync("api/account/sendresetpassword", new Account(){ Email = Email });
|
HttpResponseMessage TestLogin = await Http.PostAsync("api/account/sendresetpassword", new FormUrlEncodedContent(formData) );
|
||||||
Result = await TestLogin.Content.ReadAsStringAsync();
|
Result = await TestLogin.Content.ReadAsStringAsync();
|
||||||
|
}
|
||||||
|
base.StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -54,11 +54,22 @@
|
|||||||
Loading = "Waiting for login response from server";
|
Loading = "Waiting for login response from server";
|
||||||
ReturnURL = string.IsNullOrEmpty(ReturnURL) ? "/" : ReturnURL;
|
ReturnURL = string.IsNullOrEmpty(ReturnURL) ? "/" : ReturnURL;
|
||||||
ErrorMsgs = new List<string>();
|
ErrorMsgs = new List<string>();
|
||||||
|
if( string.IsNullOrEmpty(UserName) ) {
|
||||||
if( !string.IsNullOrEmpty(UserName) ) {
|
ErrorMsgs.Add("The 'username' field is required");
|
||||||
if( !string.IsNullOrEmpty(Password) ) {
|
}
|
||||||
if (Password.Length >= 6 ) {
|
if( string.IsNullOrEmpty(Password) ) {
|
||||||
HttpResponseMessage TestLogin = await Http.PostAsJsonAsync("api/account/login", new MistoxWebsite.Shared.Account(){ UserName = UserName, PasswordHash = Password, EmailVerified = StayLoggedIn });
|
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();
|
string result = await TestLogin.Content.ReadAsStringAsync();
|
||||||
Account? user = JsonConvert.DeserializeObject<Account>(result);
|
Account? user = JsonConvert.DeserializeObject<Account>(result);
|
||||||
if (user == null ) {
|
if (user == null ) {
|
||||||
@@ -68,19 +79,10 @@
|
|||||||
}
|
}
|
||||||
if ( string.IsNullOrEmpty(user.Error) ) {
|
if ( string.IsNullOrEmpty(user.Error) ) {
|
||||||
ErrorMsgs.Add("Login Success");
|
ErrorMsgs.Add("Login Success");
|
||||||
Nav.NavigateTo("/", true);
|
Nav.NavigateTo(ReturnURL, true);
|
||||||
} else {
|
} else {
|
||||||
ErrorMsgs.Add(user.Error);
|
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");
|
|
||||||
}
|
}
|
||||||
Loading = "";
|
Loading = "";
|
||||||
base.StateHasChanged();
|
base.StateHasChanged();
|
||||||
|
|||||||
@@ -52,62 +52,40 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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() {
|
public async Task TryRegister() {
|
||||||
Loading = "Waiting for a response from the server";
|
Loading = "Waiting for a response from the server";
|
||||||
ReturnURL = string.IsNullOrEmpty(ReturnURL) ? "/" : ReturnURL;
|
ReturnURL = string.IsNullOrEmpty(ReturnURL) ? "/" : ReturnURL;
|
||||||
|
|
||||||
ErrorMsgs = new List<string>();
|
ErrorMsgs = new List<string>();
|
||||||
|
MailAddress addr = new MailAddress(Email);
|
||||||
if ( !string.IsNullOrEmpty(Email) ){
|
if ( addr.Address != Email ){
|
||||||
if( CheckEmail( Email ) ) {
|
ErrorMsgs.Add("Please check your email address");
|
||||||
if( !string.IsNullOrEmpty(UserName) ) {
|
}
|
||||||
if( !string.IsNullOrEmpty(Password) ) {
|
if (Password.Length < 6 ) {
|
||||||
if (Password.Length >= 6 ) {
|
ErrorMsgs.Add("Password must be at least 6 Characters long");
|
||||||
HttpResponseMessage TestRegister = await Http.PostAsJsonAsync("api/account/register", new Account(){
|
}
|
||||||
UserName = UserName,
|
if( string.IsNullOrEmpty(UserName) ) {
|
||||||
Email = Email,
|
ErrorMsgs.Add("The 'username' field is required");
|
||||||
PasswordHash = Password,
|
}
|
||||||
EmailVerified = false,
|
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>();
|
Account? user = await TestRegister.Content.ReadFromJsonAsync<Account>();
|
||||||
if ( string.IsNullOrEmpty(user?.Error) ) {
|
if ( string.IsNullOrEmpty(user?.Error) ) {
|
||||||
ErrorMsgs.Add("Register Success");
|
ErrorMsgs.Add("Register Success");
|
||||||
Nav.NavigateTo("/", true);
|
Nav.NavigateTo(ReturnURL, true);
|
||||||
} else {
|
} else {
|
||||||
ErrorMsgs.Add( user.Error );
|
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{
|
|
||||||
ErrorMsgs.Add("The 'email' field is required");
|
|
||||||
}
|
}
|
||||||
Loading = "";
|
Loading = "";
|
||||||
base.StateHasChanged();
|
base.StateHasChanged();
|
||||||
|
|||||||
@@ -38,7 +38,6 @@
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
[SupplyParameterFromQuery]
|
[SupplyParameterFromQuery]
|
||||||
public string ResetPwd { get; set; } = "";
|
public string ResetPwd { get; set; } = "";
|
||||||
|
|
||||||
public string NewPassword{ get; set; } = "";
|
public string NewPassword{ get; set; } = "";
|
||||||
public string RepeatPassword{ get; set; } = "";
|
public string RepeatPassword{ get; set; } = "";
|
||||||
|
|
||||||
@@ -52,9 +51,19 @@
|
|||||||
|
|
||||||
protected async Task TryChange() {
|
protected async Task TryChange() {
|
||||||
Result = "Waiting on response from server";
|
Result = "Waiting on response from server";
|
||||||
if (NewPassword.Length >= 6){
|
if (NewPassword != RepeatPassword){
|
||||||
if (NewPassword == RepeatPassword){
|
Result = "Passwords must match";
|
||||||
HttpResponseMessage TestLogin = await Http.PostAsJsonAsync("api/account/resetpassword", new Account(){ UserName = UserName, PasswordHash = NewPassword, Error = ResetPwd });
|
}
|
||||||
|
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();
|
string result = await TestLogin.Content.ReadAsStringAsync();
|
||||||
bool success = result == "true" ? true : false;
|
bool success = result == "true" ? true : false;
|
||||||
if (success){
|
if (success){
|
||||||
@@ -64,11 +73,6 @@
|
|||||||
}else{
|
}else{
|
||||||
Result = "Something is wrong";
|
Result = "Something is wrong";
|
||||||
}
|
}
|
||||||
}else{
|
|
||||||
Result = "Passwords must match";
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
Result = "Password must be at least 6 Characters long";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,11 @@
|
|||||||
public string Result{ get; set; } = "";
|
public string Result{ get; set; } = "";
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync() {
|
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>();
|
bool Answer = await Query.Content.ReadFromJsonAsync<bool>();
|
||||||
if (Answer == true ) {
|
if (Answer == true ) {
|
||||||
Result = "Verified Email Successfully";
|
Result = "Verified Email Successfully";
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
|
||||||
public MistoxWebsite.Shared.Account? _account = null;
|
public MistoxWebsite.Shared.Database.Account? _account = null;
|
||||||
|
|
||||||
public int MaxFailedLogin = 0;
|
public int MaxFailedLogin = 0;
|
||||||
public bool FailedLoginToggle = false;
|
public bool FailedLoginToggle = false;
|
||||||
@@ -49,18 +49,19 @@
|
|||||||
|
|
||||||
public async Task SubmitLoginLock() {
|
public async Task SubmitLoginLock() {
|
||||||
if (_account != null ) {
|
if (_account != null ) {
|
||||||
_account.SiteData.FailedPasswordLock = FailedLoginToggle;
|
Dictionary<string, string> formData = new Dictionary<string, string>{
|
||||||
_account.SiteData.PasswordAttempts = MaxFailedLogin;
|
{ "UserName", _account.UserName },
|
||||||
_account.PasswordHash = "";
|
{ "AccountLock", FailedLoginToggle.ToString() },
|
||||||
HttpResponseMessage SendVerifyEmail = await Http.PostAsJsonAsync("api/account/toggleAccountLock", _account);
|
};
|
||||||
LoginCounterResult = await SendVerifyEmail.Content.ReadAsStringAsync();
|
HttpResponseMessage Query = await Http.PostAsync("api/account/toggleAccountLock", new FormUrlEncodedContent(formData) );
|
||||||
|
LoginCounterResult = await Query.Content.ReadAsStringAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync() {
|
protected override async Task OnInitializedAsync() {
|
||||||
HttpResponseMessage x = await Http.PostAsync("api/account/get", new StringContent(""));
|
HttpResponseMessage x = await Http.PostAsync("api/account/get", new StringContent(""));
|
||||||
string body = await x.Content.ReadAsStringAsync();
|
string body = await x.Content.ReadAsStringAsync();
|
||||||
_account = JsonConvert.DeserializeObject<MistoxWebsite.Shared.Account>(body);
|
_account = JsonConvert.DeserializeObject<MistoxWebsite.Shared.Database.Account>(body);
|
||||||
if (_account != null){
|
if (_account != null){
|
||||||
FailedLoginToggle = _account.SiteData.FailedPasswordLock;
|
FailedLoginToggle = _account.SiteData.FailedPasswordLock;
|
||||||
MaxFailedLogin = _account.SiteData.PasswordAttempts;
|
MaxFailedLogin = _account.SiteData.PasswordAttempts;
|
||||||
@@ -73,8 +74,11 @@
|
|||||||
|
|
||||||
public async Task SendVerifyEmail() {
|
public async Task SendVerifyEmail() {
|
||||||
if (_account != null){
|
if (_account != null){
|
||||||
HttpResponseMessage SendVerifyEmail = await Http.PostAsJsonAsync("api/account/sendverifyemail", new MistoxWebsite.Shared.Account(){ UserName = _account.UserName });
|
Dictionary<string, string> formData = new Dictionary<string, string>{
|
||||||
bool result = await SendVerifyEmail.Content.ReadFromJsonAsync<bool>();
|
{ "UserName", _account.UserName },
|
||||||
|
};
|
||||||
|
HttpResponseMessage Query = await Http.PostAsync("api/account/sendverifyemail", new FormUrlEncodedContent(formData) );
|
||||||
|
bool result = await Query.Content.ReadFromJsonAsync<bool>();
|
||||||
if (result == true ) {
|
if (result == true ) {
|
||||||
EmailSentResult = "Email Sent";
|
EmailSentResult = "Email Sent";
|
||||||
} else {
|
} else {
|
||||||
@@ -108,8 +112,13 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (_account != null){
|
if (_account != null){
|
||||||
HttpResponseMessage TryChangePassword = await Http.PostAsJsonAsync("api/account/changepassword", new MistoxWebsite.Shared.Account(){ UserName = _account.UserName, PasswordHash = CurPass, Error = NewPass1 });
|
Dictionary<string, string> formData = new Dictionary<string, string>{
|
||||||
bool resultText = await TryChangePassword.Content.ReadFromJsonAsync<bool>();
|
{ "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 ) {
|
if (resultText == true ) {
|
||||||
PasswordErrorText = "Password changed successfully";
|
PasswordErrorText = "Password changed successfully";
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -5,10 +5,6 @@
|
|||||||
margin-bottom: 1.4rem;
|
margin-bottom: 1.4rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.title-frame{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.title-frame h1 input{
|
.title-frame h1 input{
|
||||||
padding-left: 1.4rem;
|
padding-left: 1.4rem;
|
||||||
padding-top: 0.4rem;
|
padding-top: 0.4rem;
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
body {
|
.lower-frame{
|
||||||
}
|
|
||||||
|
|
||||||
.lower-frame{
|
|
||||||
padding: 1.4rem;
|
padding: 1.4rem;
|
||||||
}
|
}
|
||||||
@@ -119,12 +119,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async Task confirmDeleteAccount() {
|
async Task confirmDeleteAccount() {
|
||||||
HttpResponseMessage Delete = await Http.PostAsJsonAsync( "api/account/delete", new MistoxWebsite.Shared.Account(){
|
Dictionary<string, string> formData = new Dictionary<string, string>{
|
||||||
ID = Statics.User.ID,
|
{ "UserName", Statics.User.UserName },
|
||||||
UserName = Statics.User.Email,
|
{ "Password", Password },
|
||||||
PasswordHash = Password
|
};
|
||||||
});
|
HttpResponseMessage Query = await Http.PostAsync("api/account/delete", new FormUrlEncodedContent(formData) );
|
||||||
string result = await Delete.Content.ReadAsStringAsync();
|
string result = await Query.Content.ReadAsStringAsync();
|
||||||
bool status = result == "true" ? true : false;
|
bool status = result == "true" ? true : false;
|
||||||
if (status){
|
if (status){
|
||||||
await Http.PostAsync("api/account/logout", new StringContent(""));
|
await Http.PostAsync("api/account/logout", new StringContent(""));
|
||||||
|
|||||||
@@ -6,28 +6,11 @@
|
|||||||
<div class="Big-Div">
|
<div class="Big-Div">
|
||||||
|
|
||||||
<div id="DirTree">
|
<div id="DirTree">
|
||||||
@if (output != null ) {
|
|
||||||
<ExplorerChild Title=@output.Path Children=output.Children PartialPath="\"></ExplorerChild>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span>@ErrorTxt</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@code{
|
@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 {
|
@code {
|
||||||
protected override void OnInitialized() {
|
protected override void OnInitialized() {
|
||||||
if (Statics.User.ID == -1 ) {
|
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>
|
<h3 class="cart-title">Cart</h3>
|
||||||
|
|
||||||
<div class="Spacer">
|
<div class="Spacer">
|
||||||
@foreach( MistoxWebsite.Shared.Cart obj in Statics.Carts ) {
|
@foreach( MistoxWebsite.Shared.Database.Cart obj in Statics.Carts ) {
|
||||||
<div class="cart-item">
|
<div class="cart-item">
|
||||||
<h1>@getItem(obj.ProductID)?.Name</h1>
|
<h1>@getItem(obj.ProductID)?.Name</h1>
|
||||||
@foreach( string cur in getItem( obj.ProductID )?.Images ) {
|
@foreach( string cur in getItem( obj.ProductID )?.Images ) {
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
|
|
||||||
protected override void OnInitialized() {
|
protected override void OnInitialized() {
|
||||||
total = 0;
|
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 ) {
|
foreach( Product item in Statics.Products ) {
|
||||||
if( obj.ProductID == item.ID ) {
|
if( obj.ProductID == item.ID ) {
|
||||||
total = total + (item.Cost / 100f);
|
total = total + (item.Cost / 100f);
|
||||||
|
|||||||
@@ -99,7 +99,7 @@
|
|||||||
|
|
||||||
public bool isOwned(int ID ) {
|
public bool isOwned(int ID ) {
|
||||||
if(Statics.Owned.Count > 0 ) {
|
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 ) {
|
if( cur.ProductID == ID ) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -109,7 +109,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
public bool isInCart(int id) {
|
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 ) {
|
if (cur.ProductID == id ) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -118,7 +118,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async void onAddToCart( int ID ) {
|
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,
|
ProductID = ID,
|
||||||
AccountID = Statics.User.ID
|
AccountID = Statics.User.ID
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using Microsoft.AspNetCore.Components.Authorization;
|
using Microsoft.AspNetCore.Components.Authorization;
|
||||||
using MistoxWebsite.Shared;
|
using MistoxWebsite.Shared.DTO.Session;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace MistoxWebsite.Client.AuthState {
|
namespace MistoxWebsite.Client.AuthState {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using MistoxWebsite.Shared;
|
using MistoxWebsite.Shared.Database;
|
||||||
|
|
||||||
namespace MistoxWebsite.Client.Statics {
|
namespace MistoxWebsite.Client.Statics {
|
||||||
public class Statics {
|
public class Statics {
|
||||||
|
|||||||
@@ -1,24 +1,28 @@
|
|||||||
@using System.Net.Http
|
@using System.Net.Http
|
||||||
@using System.Net.Http.Json
|
@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.Forms
|
||||||
@using Microsoft.AspNetCore.Components.Routing
|
@using Microsoft.AspNetCore.Components.Routing
|
||||||
@using Microsoft.AspNetCore.Components.Web
|
@using Microsoft.AspNetCore.Components.Web
|
||||||
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
||||||
@using Microsoft.AspNetCore.Components.WebAssembly.Http
|
@using Microsoft.AspNetCore.Components.WebAssembly.Http
|
||||||
@using Microsoft.JSInterop
|
@using Microsoft.JSInterop
|
||||||
@using MistoxWebsite.Client
|
|
||||||
|
|
||||||
@using Microsoft.AspNetCore.Authorization
|
@using MistoxWebsite.Client
|
||||||
@using Microsoft.AspNetCore.Components.Authorization
|
|
||||||
@using System.Security.Claims
|
|
||||||
@using MistoxWebsite.Client.AuthState
|
@using MistoxWebsite.Client.AuthState
|
||||||
@using MistoxWebsite.Client.Statics
|
@using MistoxWebsite.Client.Statics
|
||||||
@using System.Security.Cryptography
|
|
||||||
@using System.Text
|
|
||||||
@using MistoxWebsite.Shared
|
|
||||||
@using Newtonsoft.Json
|
|
||||||
|
|
||||||
@using MistoxWebsite.Client.Pages.Shared
|
@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 IJSRuntime JS
|
||||||
@inject NavigationManager Nav
|
@inject NavigationManager Nav
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using MistoxWebsite.Shared;
|
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using MistoxWebsite.Server.Services;
|
using MistoxWebsite.Server.Services;
|
||||||
using MistoxWebsite.Server.Services.DatabaseService;
|
using MistoxWebsite.Server.Services.DatabaseService;
|
||||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
using MistoxWebsite.Shared.Database;
|
||||||
|
using MistoxWebsite.Shared.DTO.Session;
|
||||||
|
|
||||||
namespace MistoxWebsite.Server.Controllers {
|
namespace MistoxWebsite.Server.Controllers {
|
||||||
[ApiController]
|
[ApiController]
|
||||||
@@ -13,28 +14,26 @@ namespace MistoxWebsite.Server.Controllers {
|
|||||||
DatabaseService _accountContext;
|
DatabaseService _accountContext;
|
||||||
EmailService _emailContext;
|
EmailService _emailContext;
|
||||||
|
|
||||||
public AuthenticationController( DatabaseService DatabaseContext, EmailService emailContext ) {
|
public AuthenticationController(DatabaseService DatabaseContext, EmailService emailContext) {
|
||||||
_accountContext = DatabaseContext;
|
_accountContext = DatabaseContext;
|
||||||
_emailContext = emailContext;
|
_emailContext = emailContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
// In Account -> References UserName / PasswordHash
|
[Route("api/account/login")]
|
||||||
// Out Account
|
|
||||||
[Route( "api/account/login" )]
|
|
||||||
[HttpPost]
|
[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 {
|
try {
|
||||||
Account? test = await _accountContext.GetAccount(request.UserName.ToLower());
|
Account? test = await _accountContext.GetAccount(UserName.ToLower());
|
||||||
if( test != null ) {
|
if (test != null) {
|
||||||
if( test.EmailVerified == true ) {
|
if (test.EmailVerified == true) {
|
||||||
if( test.SiteData.FailedPasswordLock ) {
|
if (test.SiteData.FailedPasswordLock) {
|
||||||
if( test.SiteData.CurrentPasswordAttempts >= test.SiteData.PasswordAttempts ) {
|
if (test.SiteData.CurrentPasswordAttempts >= test.SiteData.PasswordAttempts) {
|
||||||
return new Account() { Error = "Too many failed password attempts. Please reset your password" };
|
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;
|
test.SiteData.CurrentPasswordAttempts = 0;
|
||||||
await _accountContext.SetAccount( test );
|
await _accountContext.SetAccount(test);
|
||||||
|
|
||||||
AccountClaims aClaims = await getClaims(test.ID);
|
AccountClaims aClaims = await getClaims(test.ID);
|
||||||
List<Claim> claims = new List<Claim>() {
|
List<Claim> claims = new List<Claim>() {
|
||||||
@@ -48,64 +47,306 @@ namespace MistoxWebsite.Server.Controllers {
|
|||||||
|
|
||||||
await HttpContext.SignInAsync(
|
await HttpContext.SignInAsync(
|
||||||
CookieAuthenticationDefaults.AuthenticationScheme,
|
CookieAuthenticationDefaults.AuthenticationScheme,
|
||||||
new ClaimsPrincipal( new ClaimsIdentity( claims, "Auth" ) ),
|
new ClaimsPrincipal(new ClaimsIdentity(claims, "Auth")),
|
||||||
new AuthenticationProperties {
|
new AuthenticationProperties {
|
||||||
ExpiresUtc = DateTime.UtcNow.AddYears(30), // Add 30 years with sliding on
|
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;
|
return test;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
test.SiteData.CurrentPasswordAttempts += 1;
|
test.SiteData.CurrentPasswordAttempts += 1;
|
||||||
await _accountContext.SetAccount( test );
|
await _accountContext.SetAccount(test);
|
||||||
return new Account() { Error = "Wrong password" };
|
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 = "A new verify email has been sent. \n Note only 1 email send every 5 mintes" };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new Account() { Error = "User doesn't exist" };
|
return new Account() { Error = "User doesn't exist" };
|
||||||
} catch( Exception ex ) {
|
} catch (Exception ex) {
|
||||||
return new Account() { Error = ex.Message };
|
return new Account() { Error = ex.Message };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// In Account -> References UserName / PasswordHash
|
[Route("api/account/session")]
|
||||||
// Out Account
|
|
||||||
[Route( "api/account/session" )]
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public async Task<ActionResult<Account>> LoginSession( [FromBody] Account request ) {
|
public async Task<ActionResult<Account>> LoginSession([FromBody] Account request) {
|
||||||
try {
|
try {
|
||||||
Account? test = await _accountContext.GetAccount(request.UserName.ToLower());
|
Account? test = await _accountContext.GetAccount(request.UserName.ToLower());
|
||||||
if( test != null ) {
|
if (test != null) {
|
||||||
if( request.PasswordHash == test.PasswordHash ) {
|
if (request.PasswordHash == test.PasswordHash) {
|
||||||
return test;
|
return test;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
test.SiteData.CurrentPasswordAttempts += 1;
|
test.SiteData.CurrentPasswordAttempts += 1;
|
||||||
await _accountContext.SetAccount( test );
|
await _accountContext.SetAccount(test);
|
||||||
return new Account() { Error = "Wrong password" };
|
return new Account() { Error = "Wrong password" };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new Account() { Error = "User doesn't exist" };
|
return new Account() { Error = "User doesn't exist" };
|
||||||
} catch( Exception ex ) {
|
} catch (Exception ex) {
|
||||||
return new Account() { Error = ex.Message };
|
return new Account() { Error = ex.Message };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// In Account
|
[Route("api/account/claims")]
|
||||||
// Out List<String>
|
|
||||||
[Route( "api/account/claims" )]
|
|
||||||
[HttpPost]
|
[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);
|
AccountClaims claims = await getClaims(Account.ID);
|
||||||
return claims;
|
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 {
|
try {
|
||||||
Account? test = await _accountContext.GetAccountByID(AccountID);
|
Account? test = await _accountContext.GetAccountByID(AccountID);
|
||||||
if( test != null ) {
|
if (test != null) {
|
||||||
AccountClaims aClaims = new AccountClaims() {
|
AccountClaims aClaims = new AccountClaims() {
|
||||||
UserName = test.UserName,
|
UserName = test.UserName,
|
||||||
Email = test.Email,
|
Email = test.Email,
|
||||||
@@ -121,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,6 +1,6 @@
|
|||||||
using MistoxWebsite.Server.Services.DatabaseService;
|
using MistoxWebsite.Server.Services.DatabaseService;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using MistoxWebsite.Shared;
|
using MistoxWebsite.Shared.DTO.Session;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace MistoxWebsite.Server.Controllers {
|
namespace MistoxWebsite.Server.Controllers {
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
using Microsoft.AspNetCore.Cors;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using MistoxWebsite.Server.Controllers.Payment;
|
using MistoxWebsite.Server.Controllers.Payment;
|
||||||
using MistoxWebsite.Server.Services.DatabaseService;
|
using MistoxWebsite.Server.Services.DatabaseService;
|
||||||
using MistoxWebsite.Shared;
|
using MistoxWebsite.Shared.Database;
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Stripe;
|
using Stripe;
|
||||||
using Stripe.Climate;
|
|
||||||
using Stripe.Tax;
|
|
||||||
|
|
||||||
namespace MistoxWebsite.Server.Controllers {
|
namespace MistoxWebsite.Server.Controllers {
|
||||||
[ApiController]
|
[ApiController]
|
||||||
@@ -24,7 +20,7 @@ namespace MistoxWebsite.Server.Controllers {
|
|||||||
public async Task<string> GetPaymentKey( [FromQuery] string userID ) {
|
public async Task<string> GetPaymentKey( [FromQuery] string userID ) {
|
||||||
|
|
||||||
string OrderNumber = Guid.NewGuid().ToString().Substring(0,10);
|
string OrderNumber = Guid.NewGuid().ToString().Substring(0,10);
|
||||||
Shared.Account? acc = await _databaseService.GetAccount(userID);
|
Shared.Database.Account? acc = await _databaseService.GetAccount(userID);
|
||||||
if (acc != null) {
|
if (acc != null) {
|
||||||
List<Cart> cart = await _databaseService.GetCart(acc);
|
List<Cart> cart = await _databaseService.GetCart(acc);
|
||||||
|
|
||||||
@@ -84,7 +80,7 @@ namespace MistoxWebsite.Server.Controllers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Clear the cart
|
// Clear the cart
|
||||||
Shared.Account account = new Shared.Account{
|
Shared.Database.Account account = new() {
|
||||||
ID = userID
|
ID = userID
|
||||||
};
|
};
|
||||||
await _databaseService.ClearCart( account );
|
await _databaseService.ClearCart( account );
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using MistoxWebsite.Shared;
|
using MistoxWebsite.Shared.Database;
|
||||||
|
|
||||||
namespace MistoxWebsite.Server.Controllers.Payment {
|
namespace MistoxWebsite.Server.Controllers.Payment {
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using MistoxWebsite.Server.Controllers.Payment;
|
using MistoxWebsite.Server.Controllers.Payment;
|
||||||
using MistoxWebsite.Server.Services.DatabaseService;
|
using MistoxWebsite.Server.Services.DatabaseService;
|
||||||
using MistoxWebsite.Shared;
|
using MistoxWebsite.Shared.Database;
|
||||||
using Stripe;
|
using Stripe;
|
||||||
using Stripe.Tax;
|
using Stripe.Tax;
|
||||||
|
|
||||||
@@ -17,7 +14,7 @@ namespace MistoxWebsite.Server.Controllers {
|
|||||||
_databaseService = databaseService;
|
_databaseService = databaseService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<(bool, string)> Purchase(string OrderNumber, Shared.Account user, List<Cart> cart) {
|
public async Task<(bool, string)> Purchase(string OrderNumber, Shared.Database.Account user, List<Cart> cart) {
|
||||||
try {
|
try {
|
||||||
// build Recipt and calculate Tax
|
// build Recipt and calculate Tax
|
||||||
var options = new CalculationCreateOptions {
|
var options = new CalculationCreateOptions {
|
||||||
@@ -34,7 +31,7 @@ namespace MistoxWebsite.Server.Controllers {
|
|||||||
// Add items to receipt
|
// Add items to receipt
|
||||||
int subtotal = 0;
|
int subtotal = 0;
|
||||||
foreach (Cart items in cart) {
|
foreach (Cart items in cart) {
|
||||||
Shared.Product? product = await _databaseService.GetProduct(items.ProductID);
|
Shared.Database.Product? product = await _databaseService.GetProduct(items.ProductID);
|
||||||
if (product != null) {
|
if (product != null) {
|
||||||
prods.Add(product.ID);
|
prods.Add(product.ID);
|
||||||
if (product != null) {
|
if (product != null) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using MistoxWebsite.Server.Services.DatabaseService;
|
using MistoxWebsite.Server.Services.DatabaseService;
|
||||||
using MistoxWebsite.Shared;
|
using MistoxWebsite.Shared.Database;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -128,74 +128,6 @@ namespace MistoxWebsite.Server.Controllers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DirObj RecursiveBuild( DirObj DirObj, string workingPath, List<ReceiptProduct> purchased ) {
|
|
||||||
|
|
||||||
string[] files = Directory.GetFiles(workingPath);
|
|
||||||
string[] directories = Directory.GetDirectories(workingPath);
|
|
||||||
|
|
||||||
List<DirObj> building = new List<DirObj>();
|
|
||||||
|
|
||||||
// Get File Names
|
|
||||||
Parallel.For( 0, files.Length, ( i ) => {
|
|
||||||
string fileName = files[i].Substring(workingPath.Length, files[i].Length - (workingPath.Length));
|
|
||||||
building.Add( new DirObj {
|
|
||||||
Type = FileType.File,
|
|
||||||
Path = fileName
|
|
||||||
});
|
|
||||||
} );
|
|
||||||
|
|
||||||
// Get Path Names
|
|
||||||
Parallel.For( 0, directories.Length, ( i ) => {
|
|
||||||
foreach( ReceiptProduct cur in purchased ) {
|
|
||||||
string dirName = directories[i].Substring(workingPath.Length, directories[i].Length - (workingPath.Length));
|
|
||||||
if( contains( dirName, cur.product.URL ) ) {
|
|
||||||
DirObj dir = new DirObj {
|
|
||||||
Type = FileType.Directory,
|
|
||||||
Path = dirName,
|
|
||||||
};
|
|
||||||
building.Add( dir );
|
|
||||||
RecursiveBuild( dir, directories [i], purchased );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
|
|
||||||
DirObj.Children = building.ToArray();
|
|
||||||
|
|
||||||
return DirObj;
|
|
||||||
}
|
|
||||||
|
|
||||||
string _FolderRoot = "/home/downloads/";
|
|
||||||
|
|
||||||
[Route( "api/product/showdownloads" )]
|
|
||||||
[HttpPost]
|
|
||||||
public async Task<IActionResult> ShowDownloads() {
|
|
||||||
try {
|
|
||||||
if( User.Identity != null && User.Identity.IsAuthenticated ) {
|
|
||||||
|
|
||||||
List<Claim> userClaims = User.Claims.ToList();
|
|
||||||
int UserID = -1;
|
|
||||||
foreach( Claim claim in userClaims ) {
|
|
||||||
if( claim.Type == "ID" ) {
|
|
||||||
UserID = Convert.ToInt32( claim.Value );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<ReceiptProduct> purchased = await _databaseService.GetAllReceiptsJoinedToProduct( new Account{ ID = UserID } );
|
|
||||||
|
|
||||||
byte[] datapacket = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(RecursiveBuild(new DirObj {
|
|
||||||
Path = @"\",
|
|
||||||
Type = FileType.Directory,
|
|
||||||
}, _FolderRoot, purchased)));
|
|
||||||
|
|
||||||
return new FileContentResult( datapacket, "text/html" );
|
|
||||||
}
|
|
||||||
return Unauthorized();
|
|
||||||
} catch {
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool contains( string outer, string inner ) {
|
bool contains( string outer, string inner ) {
|
||||||
if ( outer.Length >= inner.Length ) {
|
if ( outer.Length >= inner.Length ) {
|
||||||
for ( int i=0; i<outer.Length-inner.Length; i++ ) {
|
for ( int i=0; i<outer.Length-inner.Length; i++ ) {
|
||||||
@@ -221,10 +153,10 @@ namespace MistoxWebsite.Server.Controllers {
|
|||||||
if ( contains( Product, product.URL ) ) {
|
if ( contains( Product, product.URL ) ) {
|
||||||
Receipt? receipt = await _databaseService.GetReceipt(user, product);
|
Receipt? receipt = await _databaseService.GetReceipt(user, product);
|
||||||
if( receipt != null ) {
|
if( receipt != null ) {
|
||||||
FileStream fileStream = new FileStream(_FolderRoot + Product, FileMode.Open, FileAccess.Read);
|
//FileStream fileStream = new FileStream(_FolderRoot + Product, FileMode.Open, FileAccess.Read);
|
||||||
return new FileStreamResult( fileStream, "application/octet-stream" ) {
|
//return new FileStreamResult( fileStream, "application/octet-stream" ) {
|
||||||
FileDownloadName = fileStream.Name
|
// FileDownloadName = fileStream.Name
|
||||||
};
|
//};
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using MistoxWebsite.Shared;
|
using MistoxWebsite.Shared.Database;
|
||||||
using MySql.Data.MySqlClient;
|
using MySql.Data.MySqlClient;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Data.Common;
|
using System.Data.Common;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using MistoxWebsite.Shared;
|
using MistoxWebsite.Shared.Database;
|
||||||
|
using MistoxWebsite.Shared.DTO.Account;
|
||||||
using MySql.Data.MySqlClient;
|
using MySql.Data.MySqlClient;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Data.Common;
|
using System.Data.Common;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using MistoxWebsite.Shared;
|
using MistoxWebsite.Shared.Database;
|
||||||
using MySql.Data.MySqlClient;
|
using MySql.Data.MySqlClient;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Data.Common;
|
using System.Data.Common;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using MistoxWebsite.Shared;
|
using MistoxWebsite.Shared.Database;
|
||||||
|
using MistoxWebsite.Shared.DTO.Session;
|
||||||
using MySql.Data.MySqlClient;
|
using MySql.Data.MySqlClient;
|
||||||
using System.Data;
|
|
||||||
using System.Data.Common;
|
using System.Data.Common;
|
||||||
|
|
||||||
namespace MistoxWebsite.Server.Services.DatabaseService {
|
namespace MistoxWebsite.Server.Services.DatabaseService {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using MistoxWebsite.Shared;
|
using MistoxWebsite.Shared.Database;
|
||||||
using MySql.Data.MySqlClient;
|
using MySql.Data.MySqlClient;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Data.Common;
|
using System.Data.Common;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using MistoxWebsite.Shared;
|
using MistoxWebsite.Shared.Database;
|
||||||
using MySql.Data.MySqlClient;
|
using MySql.Data.MySqlClient;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Data.Common;
|
using System.Data.Common;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using MistoxWebsite.Shared;
|
using MistoxWebsite.Shared.Database;
|
||||||
using MySql.Data.MySqlClient;
|
using MySql.Data.MySqlClient;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Data.Common;
|
using System.Data.Common;
|
||||||
@@ -46,8 +46,8 @@ namespace MistoxWebsite.Server.Services.DatabaseService {
|
|||||||
return receipts;
|
return receipts;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<ReceiptProduct>> GetAllReceiptsJoinedToProduct( Account account ) {
|
public async Task<List<( Receipt, Product )>> GetAllReceiptsJoinedToProduct( Account account ) {
|
||||||
List<ReceiptProduct> join = new List<ReceiptProduct> ();
|
List<( Receipt, Product )> join = new();
|
||||||
using( MySqlConnection connection = GetConnection() ) {
|
using( MySqlConnection connection = GetConnection() ) {
|
||||||
connection.Open();
|
connection.Open();
|
||||||
string command = @"
|
string command = @"
|
||||||
@@ -78,8 +78,7 @@ namespace MistoxWebsite.Server.Services.DatabaseService {
|
|||||||
int _cost = !reader.IsDBNull( "Cost" ) ? reader.GetInt32("Cost") : 0;
|
int _cost = !reader.IsDBNull( "Cost" ) ? reader.GetInt32("Cost") : 0;
|
||||||
string _url = !reader.IsDBNull( "URL" ) ? reader.GetString("URL") : "Something Random That Wont Ever Be In A URL";
|
string _url = !reader.IsDBNull( "URL" ) ? reader.GetString("URL") : "Something Random That Wont Ever Be In A URL";
|
||||||
|
|
||||||
join.Add( new ReceiptProduct() {
|
Receipt r = new() {
|
||||||
receipt = new Receipt {
|
|
||||||
AccountID = _accountid,
|
AccountID = _accountid,
|
||||||
ProductID = _gameid,
|
ProductID = _gameid,
|
||||||
ReceiptID = _receiptid,
|
ReceiptID = _receiptid,
|
||||||
@@ -87,15 +86,17 @@ namespace MistoxWebsite.Server.Services.DatabaseService {
|
|||||||
TotalCost = _totalcost,
|
TotalCost = _totalcost,
|
||||||
TaxAmount = _taxamount,
|
TaxAmount = _taxamount,
|
||||||
LineItem = _lineitem
|
LineItem = _lineitem
|
||||||
},
|
};
|
||||||
product = new Product() {
|
|
||||||
|
Product p = new() {
|
||||||
ID = _id,
|
ID = _id,
|
||||||
Cost = _cost,
|
Cost = _cost,
|
||||||
Description = _desc,
|
Description = _desc,
|
||||||
Name = _name,
|
Name = _name,
|
||||||
URL = _url
|
URL = _url
|
||||||
}
|
};
|
||||||
} );
|
|
||||||
|
join.Add( (r, p) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using MistoxWebsite.Shared;
|
using MistoxWebsite.Shared.Database;
|
||||||
using MySql.Data.MySqlClient;
|
using MySql.Data.MySqlClient;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Data.Common;
|
using System.Data.Common;
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
using System.Net.Mail;
|
|
||||||
|
|
||||||
namespace MistoxWebsite.Server.Services {
|
namespace MistoxWebsite.Server.Services {
|
||||||
public partial class EmailService {
|
public partial class EmailService {
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
using System.Net.Mail;
|
|
||||||
|
|
||||||
namespace MistoxWebsite.Server.Services {
|
namespace MistoxWebsite.Server.Services {
|
||||||
public partial class EmailService {
|
public partial class EmailService {
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
namespace MistoxWebsite.Shared.DTO.Account {
|
||||||
|
|
||||||
|
public class UserInventory {
|
||||||
|
public string Item { get; set; } = string.Empty;
|
||||||
|
public int Quantity { get; set; }
|
||||||
|
public string Stats { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PaymentObject {
|
||||||
|
public string CardNumber { get; set; } = string.Empty;
|
||||||
|
public long ExperationMonth { get; set; }
|
||||||
|
public long ExperationYear { get; set; }
|
||||||
|
public string CVC { get; set; } = string.Empty;
|
||||||
|
public string FullName { get; set; } = string.Empty;
|
||||||
|
public string Email { get; set; } = string.Empty;
|
||||||
|
public string Zip { get; set; } = string.Empty;
|
||||||
|
public List<int> productIDs { get; set; } = new List<int>();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using MistoxWebsite.Shared.Database;
|
||||||
|
|
||||||
|
namespace MistoxWebsite.Shared.DTO.Session {
|
||||||
|
|
||||||
|
public class PageLoadObject {
|
||||||
|
public Database.Account? user { get; set; }
|
||||||
|
public AccountClaims? claims { get; set; }
|
||||||
|
public List<Receipt>? receipts { get; set; }
|
||||||
|
public List<Product>? products { get; set; }
|
||||||
|
public List<Cart>? Cart { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AccountClaims {
|
||||||
|
public string UserName { get; set; } = string.Empty;
|
||||||
|
public string Email { get; set; } = string.Empty;
|
||||||
|
public string EmailVerified { get; set; } = string.Empty;
|
||||||
|
public string Role { get; set; } = string.Empty;
|
||||||
|
public string FailedPasswordLock { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,27 +1,6 @@
|
|||||||
using System.Diagnostics;
|
// Reflections of SQL Database objects
|
||||||
|
|
||||||
// Reflections of SQL Database objects
|
namespace MistoxWebsite.Shared.Database {
|
||||||
|
|
||||||
namespace MistoxWebsite.Shared {
|
|
||||||
|
|
||||||
public class PageLoadObject {
|
|
||||||
public Account? user { get; set; }
|
|
||||||
public AccountClaims? claims { get; set; }
|
|
||||||
public List<Receipt>? receipts { get; set; }
|
|
||||||
public List<Product>? products { get; set; }
|
|
||||||
public List<Cart>? Cart { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class DirObj {
|
|
||||||
public FileType? Type { get; set; }
|
|
||||||
public string Path { get; set; } = "";
|
|
||||||
public DirObj? [] Children { get; set; } = new DirObj?[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum FileType {
|
|
||||||
File,
|
|
||||||
Directory
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Account {
|
public class Account {
|
||||||
public int ID { get; set; } // PK
|
public int ID { get; set; } // PK
|
||||||
@@ -33,25 +12,6 @@ namespace MistoxWebsite.Shared {
|
|||||||
public string Error { get; set; } = "";
|
public string Error { get; set; } = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Product {
|
|
||||||
public int ID { get; set; } // PK
|
|
||||||
public string Name { get; set; } = "";
|
|
||||||
public string Description { get; set; } = "";
|
|
||||||
public int CurShowingIMG = 0;
|
|
||||||
public List<string> Images { get; set; } = new List<string>();
|
|
||||||
public int Cost { get; set; }
|
|
||||||
public string URL { get; set; } = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
public class WebSiteData {
|
|
||||||
public int AccountID { get; set; } // PK
|
|
||||||
public bool FailedPasswordLock { get; set; } = false;
|
|
||||||
public int PasswordAttempts { get; set; } = 5;
|
|
||||||
public int CurrentPasswordAttempts { get; set; } = 0;
|
|
||||||
public string Role { get; set; } = "Generic";
|
|
||||||
public string EmailToken { get; set; } = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
public class AccountInventory {
|
public class AccountInventory {
|
||||||
public int AccountID { get; set; } // PK
|
public int AccountID { get; set; } // PK
|
||||||
public int ProductID { get; set; } // PK
|
public int ProductID { get; set; } // PK
|
||||||
@@ -60,25 +20,14 @@ namespace MistoxWebsite.Shared {
|
|||||||
public string Stats { get; set; } = string.Empty;
|
public string Stats { get; set; } = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class UserInventory {
|
public class Product {
|
||||||
public string Item { get; set; } = string.Empty;
|
public int ID { get; set; } // PK
|
||||||
public int Quantity { get; set; }
|
public string Name { get; set; } = "";
|
||||||
public string Stats { get; set; } = string.Empty;
|
public string Description { get; set; } = "";
|
||||||
}
|
public int CurShowingIMG = 0;
|
||||||
|
public List<string> Images { get; set; } = new List<string>();
|
||||||
public class Receipt {
|
public int Cost { get; set; }
|
||||||
public int AccountID { get; set; } // PK
|
public string URL { get; set; } = "";
|
||||||
public int ProductID { get; set; } // PK
|
|
||||||
public string ReceiptID { get; set; } = string.Empty;
|
|
||||||
public int LineItem { get; set; }
|
|
||||||
public int TaxAmount { get; set; }
|
|
||||||
public int TotalCost { get; set; }
|
|
||||||
public DateTime Time { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ReceiptProduct {
|
|
||||||
public Receipt receipt { get; set; } = new Receipt();
|
|
||||||
public Product product { get; set; } = new Product();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Cart {
|
public class Cart {
|
||||||
@@ -97,23 +46,23 @@ namespace MistoxWebsite.Shared {
|
|||||||
public int Deaths { get; set; }
|
public int Deaths { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AccountClaims {
|
public class Receipt {
|
||||||
public string UserName { get; set; } = string.Empty;
|
public int AccountID { get; set; } // PK
|
||||||
public string Email { get; set; } = string.Empty;
|
public int ProductID { get; set; } // PK
|
||||||
public string EmailVerified { get; set; } = string.Empty;
|
public string ReceiptID { get; set; } = string.Empty;
|
||||||
public string Role { get; set; } = string.Empty;
|
public int LineItem { get; set; }
|
||||||
public string FailedPasswordLock { get; set; } = string.Empty;
|
public int TaxAmount { get; set; }
|
||||||
|
public int TotalCost { get; set; }
|
||||||
|
public DateTime Time { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PaymentObject {
|
public class WebSiteData {
|
||||||
public string CardNumber { get; set; } = string.Empty;
|
public int AccountID { get; set; } // PK
|
||||||
public long ExperationMonth { get; set; }
|
public bool FailedPasswordLock { get; set; } = false;
|
||||||
public long ExperationYear { get; set; }
|
public int PasswordAttempts { get; set; } = 5;
|
||||||
public string CVC { get; set; } = string.Empty;
|
public int CurrentPasswordAttempts { get; set; } = 0;
|
||||||
public string FullName { get; set; } = string.Empty;
|
public string Role { get; set; } = "Generic";
|
||||||
public string Email { get; set; } = string.Empty;
|
public string EmailToken { get; set; } = "";
|
||||||
public string Zip { get; set; } = string.Empty;
|
|
||||||
public List<int> productIDs { get; set; } = new List<int>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user