From 62c4dcac969c3c72304f3f1c49722a811c6fe4b3 Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Thu, 17 Jul 2025 17:40:50 -0700 Subject: [PATCH 01/26] Complete fix for account database --- database/mistox.sql | 12 ++++++------ src/Server/Controllers/AuthenticationController.cs | 1 - src/Server/Services/DatabaseService/Account.cs | 4 ++-- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/database/mistox.sql b/database/mistox.sql index a16ece7..995ee57 100755 --- a/database/mistox.sql +++ b/database/mistox.sql @@ -205,14 +205,14 @@ INSERT INTO Account ( DataServer ) VALUES ( 1, - `admin`, - `admin@mistox.com`, + 'admin', + 'admin@mistox.com', 1, - `$2a$11$0UeWLLqTXe3FG161QVuI0OQJ9rulspUpMG581DI6KSzDXBbFKd00S`, + '$2a$11$0UeWLLqTXe3FG161QVuI0OQJ9rulspUpMG581DI6KSzDXBbFKd00S', 0, 5, 0, - `Admin`, - ``, - `` + 'Admin', + '', + '' ); \ No newline at end of file diff --git a/src/Server/Controllers/AuthenticationController.cs b/src/Server/Controllers/AuthenticationController.cs index 4a532da..463ab62 100755 --- a/src/Server/Controllers/AuthenticationController.cs +++ b/src/Server/Controllers/AuthenticationController.cs @@ -5,7 +5,6 @@ using System.Security.Claims; using BoredCareers.Services; using BoredCareers.Services.DatabaseService; using BoredCareers.Entities; -using Microsoft.AspNetCore.Http.HttpResults; using System.Web.Http; namespace BoredCareers.Controllers { diff --git a/src/Server/Services/DatabaseService/Account.cs b/src/Server/Services/DatabaseService/Account.cs index ae527da..09d5cf8 100755 --- a/src/Server/Services/DatabaseService/Account.cs +++ b/src/Server/Services/DatabaseService/Account.cs @@ -110,7 +110,7 @@ namespace BoredCareers.Services.DatabaseService { INSERT INTO Account (ID,UserName,Email,EmailVerified,PasswordHash,FailedPasswordLock,PasswordAttempts,CurrentPasswordAttempts,Role,EmailToken,DataServer) VALUES - (@ID,@UserName,@Email,@EmailVerified,@PasswordHash,@FailedPasswordLock,@PasswordAttempts,@CurrentPasswordAttempts,@Role,@EmailToken,@DataServer); + (@ID,@UserName,@Email,@EmailVerified,@PasswordHash,@FailedPasswordLock,@PasswordAttempts,@CurrentPasswordAttempts,@Role,@EmailToken,@DataServer) ON DUPLICATE KEY UPDATE UserName = @UserName, Email = @Email, @@ -120,7 +120,7 @@ namespace BoredCareers.Services.DatabaseService { PasswordAttempts = @PasswordAttempts, CurrentPasswordAttempts = @CurrentPasswordAttempts, Role = @Role, - EmailToken = @EmailToken; + EmailToken = @EmailToken, DataServer = @DataServer; "; -- 2.52.0 From edbf8516b7d780968e051d5f9accb19d44828c76 Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Thu, 17 Jul 2025 18:03:30 -0700 Subject: [PATCH 02/26] Import DB types --- src/Client/src/app/models/Account.ts | 16 ++- src/Client/src/app/models/Company.ts | 20 ++++ src/Client/src/app/models/JobListing.ts | 17 +++ src/Client/src/app/models/Product.ts | 15 --- src/Client/src/app/models/Resume.ts | 106 ++++++++++++++++++ src/Client/src/app/models/WebsiteData.ts | 12 -- .../store/admin/edititem/edit.component.ts | 2 +- .../store/admin/newitem/new.component.ts | 2 +- .../pages/store/catalog/catalog.component.ts | 2 +- 9 files changed, 153 insertions(+), 39 deletions(-) create mode 100644 src/Client/src/app/models/Company.ts create mode 100644 src/Client/src/app/models/JobListing.ts delete mode 100644 src/Client/src/app/models/Product.ts create mode 100644 src/Client/src/app/models/Resume.ts delete mode 100644 src/Client/src/app/models/WebsiteData.ts diff --git a/src/Client/src/app/models/Account.ts b/src/Client/src/app/models/Account.ts index 3ae7944..99c9acf 100644 --- a/src/Client/src/app/models/Account.ts +++ b/src/Client/src/app/models/Account.ts @@ -1,15 +1,13 @@ -import { WebSiteData } from "./WebsiteData"; - export class Account { - public id: number = -1; + public id: number = 0; public userName: string = ""; public email: string = ""; public emailVerified: boolean = false; public passwordHash: string = ""; - public siteData: WebSiteData = new WebSiteData(); - public error: string = ""; - - constructor(init?: Partial) { - Object.assign(this, init); - } + public failedPasswordLock: boolean = false; + public passwordAttempts: number = 5; + public currentPasswordAttempts: number = 0; + public role: string = "Generic"; + public emailToken: string = ""; + public dataServer: string = ""; } \ No newline at end of file diff --git a/src/Client/src/app/models/Company.ts b/src/Client/src/app/models/Company.ts new file mode 100644 index 0000000..684ae1e --- /dev/null +++ b/src/Client/src/app/models/Company.ts @@ -0,0 +1,20 @@ +export class Company { + public id: number = 0; + public name: string = ""; + public email: string = ""; + public emailVerified: boolean = false; + public websiteURL: string = ""; + public logoURL: string = ""; + public phone: string = ""; + public postalCode: string = ""; + public country: string = ""; // 2 Letter Country Code + public stateOrRegion: string = ""; + public city: string = ""; + public description: string = ""; +} + +export class Employee { + public id: number = 0; + public accountID: number = 0; + public companyID: number = 0; +} \ No newline at end of file diff --git a/src/Client/src/app/models/JobListing.ts b/src/Client/src/app/models/JobListing.ts new file mode 100644 index 0000000..060dadf --- /dev/null +++ b/src/Client/src/app/models/JobListing.ts @@ -0,0 +1,17 @@ +export class WebSiteData { + public id: number = 0; + public companyID: number = 0; + public title: string = ""; + public postalCode: string = ""; + public country: string = ""; + public stateOrRegion: string = ""; + public city: string = ""; + public salaryMin: number = 0; + public salaryMax: number = 0; + public jobType: string = ""; + public remote: boolean = false; + public description: string = ""; + public createdTime: Date = new Date(); + public modifiedTime: Date = new Date(); + public isDeleted: boolean = false; +} \ No newline at end of file diff --git a/src/Client/src/app/models/Product.ts b/src/Client/src/app/models/Product.ts deleted file mode 100644 index 1904aab..0000000 --- a/src/Client/src/app/models/Product.ts +++ /dev/null @@ -1,15 +0,0 @@ -export class Product { - public id: number = -1; - public name: string = ""; - public description: string = ""; - public curShowingIMG: number = 0; - public images: ProductImage[] = []; - public cost: number = 0; - public url: string = ""; -} - -export class ProductImage { - imageID: number = 0; - productID: number = 0; - imageSrc: string = ""; -} \ No newline at end of file diff --git a/src/Client/src/app/models/Resume.ts b/src/Client/src/app/models/Resume.ts new file mode 100644 index 0000000..d054b9a --- /dev/null +++ b/src/Client/src/app/models/Resume.ts @@ -0,0 +1,106 @@ +export class Resume { + public id: number = 0; + public accountID: number = 0; + public name: string = ""; + public field: string = ""; + public email: string = ""; + public phoneNumber: string = ""; + public postalCode: string = ""; + public country: string = ""; + public stateOrRegion: string = ""; + public city: string = ""; + public isActive: boolean = false; + public experience: ResumeExperience[] = []; + public military: ResumeMilitary = []; + public education: ResumeEducation[] = []; + public skills: ResumeSkill[] = []; + public languages: ResumeLanguage[] = []; + public certification: ResumeCertification[] = []; + public projects: ResumeProject[] = []; +} + +export class ResumeExperience { + id: number = 0; + resumeID: number = 0; + jobTitle: string = ""; + company: string = ""; + postalCode: string = ""; + country: string = ""; + stateOrRegion: string = ""; + city: string = ""; + dateStarted: Date = new Date(); + stillEmployed: boolean = false; + dateEnded: Date = new Date(); + experienceBullets: ResumeExperienceBullet[] = []; +} + +export class ResumeExperienceBullet { + id: number = 0; + resumeID: number = 0; + resumeExperienceID: number = 0; + jobFunction: string = ""; +} + +export class ResumeMilitary { + id: number = 0; + resumeID: number = 0; + country: string = ""; + rank: string = ""; + dateStarted: Date = new Date(); + stillServing: boolean = false; + dateEnded: Date = new Date(); + millitaryBullets: ResumeMilitaryBullet[] = []; +} + +export class ResumeMilitaryBullet { + id: number = 0; + resumeID: number = 0; + resumeMilitaryID: number = 0; + achievement: string = ""; + description: string = ""; +} + +export class ResumeEducation { + id: number = 0; + resumeID: number = 0; + degreeType: string = ""; + degreeField: string = ""; + school: string = ""; + postalCode: string = ""; + country: string = ""; + stateOrRegion: string = ""; + city: string = ""; + dateStarted: Date = new Date(); + stillStudying: boolean = false; + dateEnded: Date = new Date(); +} + +export class ResumeSkill { + id: number = 0; // PK + resumeID: number = 0; // FK + name: string = ""; + description: string = ""; +} + +export class ResumeLanguage { + id: number = 0; + resumeID: number = 0; + language: string = ""; + proficiency: string = ""; +} + +export class ResumeCertification { + id: number = 0; + resumeID: number = 0; + name: string = ""; + verificationURL: string = ""; + description: string = ""; +} + +export class ResumeProject { + id: number = 0; + resumeID: number = 0; + name: string = ""; + url: string = ""; + description: string = ""; +} \ No newline at end of file diff --git a/src/Client/src/app/models/WebsiteData.ts b/src/Client/src/app/models/WebsiteData.ts deleted file mode 100644 index bf00e26..0000000 --- a/src/Client/src/app/models/WebsiteData.ts +++ /dev/null @@ -1,12 +0,0 @@ -export class WebSiteData { - public accountID: number = -1; - public failedPasswordLock: boolean = false; - public passwordAttempts: number = 5; - public currentPasswordAttempts: number = 0; - public role: string = "Generic"; - public emailToken: string = ""; - - constructor(init?: Partial) { - Object.assign(this, init); - } -} \ No newline at end of file diff --git a/src/Client/src/app/pages/store/admin/edititem/edit.component.ts b/src/Client/src/app/pages/store/admin/edititem/edit.component.ts index 272fefc..17e7508 100644 --- a/src/Client/src/app/pages/store/admin/edititem/edit.component.ts +++ b/src/Client/src/app/pages/store/admin/edititem/edit.component.ts @@ -5,7 +5,7 @@ import { Router, ActivatedRoute } from '@angular/router'; import { Title } from '@angular/platform-browser'; import { CommonModule } from '@angular/common'; import { Authentication } from '../../../../services/Authentication'; -import { Product } from 'app/models/Product'; +import { Product } from 'app/models/Company'; @Component({ selector: 'item-edit', diff --git a/src/Client/src/app/pages/store/admin/newitem/new.component.ts b/src/Client/src/app/pages/store/admin/newitem/new.component.ts index 2171eb7..f1502dc 100644 --- a/src/Client/src/app/pages/store/admin/newitem/new.component.ts +++ b/src/Client/src/app/pages/store/admin/newitem/new.component.ts @@ -5,7 +5,7 @@ import { Router, ActivatedRoute } from '@angular/router'; import { Title } from '@angular/platform-browser'; import { CommonModule } from '@angular/common'; import { Authentication } from '../../../../services/Authentication'; -import { Product } from 'app/models/Product'; +import { Product } from 'app/models/Company'; @Component({ selector: 'item-new', diff --git a/src/Client/src/app/pages/store/catalog/catalog.component.ts b/src/Client/src/app/pages/store/catalog/catalog.component.ts index 4ee173c..5b4af5c 100644 --- a/src/Client/src/app/pages/store/catalog/catalog.component.ts +++ b/src/Client/src/app/pages/store/catalog/catalog.component.ts @@ -5,7 +5,7 @@ import { Router, ActivatedRoute, RouterModule } from '@angular/router'; import { Title } from '@angular/platform-browser'; import { CommonModule } from '@angular/common'; import { Authentication } from '../../../services/Authentication'; -import { Product } from 'app/models/Product'; +import { Product } from 'app/models/Company'; @Component({ selector: 'store-catalog', -- 2.52.0 From 20a2e45020379ff40350d849f024a7af1384ff21 Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Thu, 17 Jul 2025 18:08:42 -0700 Subject: [PATCH 03/26] Remove old stuff --- .../pages/project/mist/mist.component.html | 18 --- .../app/pages/project/mist/mist.component.ts | 19 --- .../store/admin/edititem/edit.component.html | 50 ------ .../store/admin/edititem/edit.component.ts | 128 ---------------- .../store/admin/newitem/new.component.html | 50 ------ .../store/admin/newitem/new.component.ts | 101 ------------ .../pages/store/catalog/catalog.component.css | 145 ------------------ .../store/catalog/catalog.component.html | 32 ---- .../pages/store/catalog/catalog.component.ts | 71 --------- .../pages/store/payment/payment.component.css | 24 --- .../store/payment/payment.component.html | 8 - .../pages/store/payment/payment.component.ts | 62 -------- 12 files changed, 708 deletions(-) delete mode 100644 src/Client/src/app/pages/project/mist/mist.component.html delete mode 100644 src/Client/src/app/pages/project/mist/mist.component.ts delete mode 100644 src/Client/src/app/pages/store/admin/edititem/edit.component.html delete mode 100644 src/Client/src/app/pages/store/admin/edititem/edit.component.ts delete mode 100644 src/Client/src/app/pages/store/admin/newitem/new.component.html delete mode 100644 src/Client/src/app/pages/store/admin/newitem/new.component.ts delete mode 100644 src/Client/src/app/pages/store/catalog/catalog.component.css delete mode 100644 src/Client/src/app/pages/store/catalog/catalog.component.html delete mode 100644 src/Client/src/app/pages/store/catalog/catalog.component.ts delete mode 100644 src/Client/src/app/pages/store/payment/payment.component.css delete mode 100644 src/Client/src/app/pages/store/payment/payment.component.html delete mode 100644 src/Client/src/app/pages/store/payment/payment.component.ts diff --git a/src/Client/src/app/pages/project/mist/mist.component.html b/src/Client/src/app/pages/project/mist/mist.component.html deleted file mode 100644 index 86ec944..0000000 --- a/src/Client/src/app/pages/project/mist/mist.component.html +++ /dev/null @@ -1,18 +0,0 @@ -
-
-

What is the game

-

Project-Mist is a survival game. Kind of like a battle royal in a sense but, think of it backwards. And no I know what your thinking. Its not the first person to die wins. No instead its a never ending survival game where you can free roam and build structures. The catch is, the person who has the highest stats [i.e A combination of kills, survival time] has a marker placed on their forhead.

-

How will the game play

-

When you join the game you will be able to customize your character. There you can set a default loadout for your player. This will be the spawn weapon and gear. After that you will drop into the map with other players to fend for your life. The kill-leader will be marked loosely on the mini-map. You can choose to go after the kill leader or you can choose to loot first. The choice is yours. But be aware that if you survive long enough you will become the new kill leader.

-

Current Idea Board *SUBJECT TO CHANGE*

-

Survival Game
look at item to pick up 'e' for third person and click for third [No nearby]
normal weapons with bullet drop bullet travel time
snipers but rare [Maybe special]

-

Abilities selectable at spawn
a max 20 credit slider where you can spend them on traits
Stamina -> run for longer distances
Strength -> carry more weight
Vitality -> Have more base health
Stealth -> Approximate location on map is bigger

-

More weight slows player some
Backpacks -> Add slots but not weight

-

Oddball style game
Map that shows the relitive area of the top player

-

spawn with classes
2 mags
no attachments
unlock guns with experience

-

no health regen
final hit headshots = 20 credits
final hit bodyshots = 10 credits

-

classes require credits to spawn with better stuff
inventory and credits are transferrable between servers and sessions
combat loggging - if leave in combat start from scratch
one dynamicly roaming entity of the night ( Impossible to kill, when near heart starts pumping and vinegrette )
goes after people possible to get away
Dyanmic day and night cycle
Dynamic weather ( rain, fog, thunder, lightning )
floods that cause roaring rivers to fill that cannot be swam
Fires that char trees(no leaves), regrows in 3ish days
Master leaderboard in the main menu of top players per rank
Ranked lobby ( Disabled until player base )
small towns around a main centralized area( ie city or temple )
large servers
random spawned skin boxes that require credits to open
purchasable skins
bullet penatration on certain materials
bullet reflection on certain materials
No kill leader until you get at least 2 kills minimum

-

Tournament mode
all players spawn at the same time
hold oddball for 30mins total

-

server quits introducing people into game after 5 hrs. (last man standing mode)
last person in server wins
on death quit to new server
everyone becomes oddball
less players alive equal less oddball area

-
-
\ No newline at end of file diff --git a/src/Client/src/app/pages/project/mist/mist.component.ts b/src/Client/src/app/pages/project/mist/mist.component.ts deleted file mode 100644 index 3296237..0000000 --- a/src/Client/src/app/pages/project/mist/mist.component.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Component } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { FormsModule } from '@angular/forms'; -import { Router, ActivatedRoute } from '@angular/router'; -import { Title } from '@angular/platform-browser'; -import { CommonModule } from '@angular/common'; - -@Component({ - selector: 'project-mist', - templateUrl: './mist.component.html', - imports: [ FormsModule, CommonModule ] -}) -export class MistComponent { - - constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title ) { - this.title.setTitle("Mist | Mistox"); - }; - -} \ No newline at end of file diff --git a/src/Client/src/app/pages/store/admin/edititem/edit.component.html b/src/Client/src/app/pages/store/admin/edititem/edit.component.html deleted file mode 100644 index c7ae0fb..0000000 --- a/src/Client/src/app/pages/store/admin/edititem/edit.component.html +++ /dev/null @@ -1,50 +0,0 @@ -
-
-
-

Edit Item

- -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
-
- -
- -
-
- -
-
- -
    -
  • {{ msg }}
  • -
-
- - -
-
- - Image Preview -
-
-
-
\ No newline at end of file diff --git a/src/Client/src/app/pages/store/admin/edititem/edit.component.ts b/src/Client/src/app/pages/store/admin/edititem/edit.component.ts deleted file mode 100644 index 17e7508..0000000 --- a/src/Client/src/app/pages/store/admin/edititem/edit.component.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { Component, ElementRef, ViewChild } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { FormsModule } from '@angular/forms'; -import { Router, ActivatedRoute } from '@angular/router'; -import { Title } from '@angular/platform-browser'; -import { CommonModule } from '@angular/common'; -import { Authentication } from '../../../../services/Authentication'; -import { Product } from 'app/models/Company'; - -@Component({ - selector: 'item-edit', - templateUrl: './edit.component.html', - imports: [ FormsModule, CommonModule ] -}) -export class EditItemComponent { - @ViewChild('FileUpload') InputDOM!: ElementRef; - - readonly maxFileMB = 16; - - newItem: Product = new Product(); - errorMsgs: string[] = []; - - constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) { - this.title.setTitle("Edit | ADMIN"); - this.route.queryParams.subscribe(params => { - this.newItem.id = params['ProductID'] || ''; - }); - - // If user is not logged in -> route home - if (!auth.isLoggedIn){ - router.navigate(["/"]); - } - - // If user is not Admin -> route home - if (auth.loggedInUser.siteData.role != "Admin"){ - router.navigate(["/"]); - } - - // Load product - const formData = new FormData(); - formData.append("productID", this.newItem.id.toString()); - this.http.post( "api/product/get", formData ).subscribe({ - next: async (data) => { - this.newItem = data; - this.newItem.images.forEach(img => { - http.get("api/productimage/get?ProductID=" + img.productID + "&ImageID=" + img.imageID, { responseType: 'blob' }).subscribe(blob => { - img.imageSrc = URL.createObjectURL(blob); - this.imagePreviews.push(img.imageSrc); - this.selectedFiles.push(new File([blob], "EmptyName", {type: "image/jpeg"})); - }); - }); - }, - error: err => { - console.log("Err loading product: ", err); - } - }); - }; - - sleep(ms: number) { - return new Promise(resolve => setTimeout(resolve, ms)); - } - - selectedFiles: File[] = []; - imagePreviews: string[] = []; - onFileSelected(event: Event){ - const fileInput = event.target as HTMLInputElement; - - if (!fileInput.files?.length){ - return; - } - - for (let i=0; i this.maxFileMB * 1024 * 1024){ - this.errorMsgs.push("File exceeds max file size of 16MB"); - continue; - } - // No issues add file to the list - this.selectedFiles.push( file ); - - const reader = new FileReader(); - reader.onload= () => { - this.imagePreviews.push(reader.result as string); - } - reader.readAsDataURL(file); - - this.InputDOM.nativeElement.value = ''; - } - } - - RemovePhoto(imagePreview: string){ - let i = this.imagePreviews.indexOf(imagePreview); - this.imagePreviews.splice(i, 1); - this.selectedFiles.splice(i, 1); - } - - onSubmit(){ - const formData = new FormData(); - // Append non-file fields - formData.append("Name", this.newItem.name); - formData.append("Description", this.newItem.description); - formData.append("Cost", this.newItem.cost.toString()); - formData.append("Url", this.newItem.url); - - // Add image fileds - if (this.selectedFiles.length > 0){ - for(let i=0; i( "api/product/create", formData ).subscribe({ - next: async (data) => { - if (data == true){ - this.errorMsgs = ["Product Created Successfully"]; - await this.sleep(3000); - this.router.navigate(["/catalog"]); - }else{ - this.errorMsgs = ["Error has ocurred"]; - } - }, - error: err => { - console.log("New Product Err: ", err); - } - }); - } -} \ No newline at end of file diff --git a/src/Client/src/app/pages/store/admin/newitem/new.component.html b/src/Client/src/app/pages/store/admin/newitem/new.component.html deleted file mode 100644 index 85d0c23..0000000 --- a/src/Client/src/app/pages/store/admin/newitem/new.component.html +++ /dev/null @@ -1,50 +0,0 @@ -
-
-
-

Create New Item

- -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- -
- -
- -
-
- -
-
- -
    -
  • {{ msg }}
  • -
-
- - -
-
- Image Preview -
-
-
-
\ No newline at end of file diff --git a/src/Client/src/app/pages/store/admin/newitem/new.component.ts b/src/Client/src/app/pages/store/admin/newitem/new.component.ts deleted file mode 100644 index f1502dc..0000000 --- a/src/Client/src/app/pages/store/admin/newitem/new.component.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { Component } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { FormsModule } from '@angular/forms'; -import { Router, ActivatedRoute } from '@angular/router'; -import { Title } from '@angular/platform-browser'; -import { CommonModule } from '@angular/common'; -import { Authentication } from '../../../../services/Authentication'; -import { Product } from 'app/models/Company'; - -@Component({ - selector: 'item-new', - templateUrl: './new.component.html', - imports: [ FormsModule, CommonModule ] -}) -export class NewItemComponent { - - readonly maxFileMB = 16; - - newItem: Product = new Product(); - errorMsgs: string[] = []; - - constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) { - this.title.setTitle("New | ADMIN"); - - // If user is not logged in -> route home - if (!auth.isLoggedIn){ - router.navigate(["/"]); - } - - // If user is not Admin -> route home - if (auth.loggedInUser.siteData.role != "Admin"){ - router.navigate(["/"]); - } - }; - - sleep(ms: number) { - return new Promise(resolve => setTimeout(resolve, ms)); - } - - selectedFiles: File[] = []; - imagePreviews: string[] = []; - onFileSelected(event: Event){ - const fileInput = event.target as HTMLInputElement; - this.imagePreviews = []; - this.selectedFiles = []; - - if (!fileInput.files?.length){ - return; - } - - for (let i=0; i this.maxFileMB * 1024 * 1024){ - this.errorMsgs.push("File exceeds max file size of 16MB"); - continue; - } - // No issues add file to the list - this.selectedFiles.push( file ); - - const reader = new FileReader(); - reader.onload= () => { - this.imagePreviews.push(reader.result as string); - } - reader.readAsDataURL(file); - } - } - - onSubmit(){ - - const formData = new FormData(); - - // Append non-file fields - formData.append("Name", this.newItem.name); - formData.append("Description", this.newItem.description); - formData.append("Cost", this.newItem.cost.toString()); - formData.append("Url", this.newItem.url); - - // Add image fileds - if (this.selectedFiles.length > 0){ - for(let i=0; i( "api/product/create", formData ).subscribe({ - next: async (data) => { - if (data == true){ - this.errorMsgs = ["Product Created Successfully"]; - await this.sleep(3000); - this.router.navigate(["store/catalog"]); - }else{ - this.errorMsgs = ["Error has ocurred"]; - } - }, - error: err => { - console.log("New Product Err: ", err); - } - }); - } -} \ No newline at end of file diff --git a/src/Client/src/app/pages/store/catalog/catalog.component.css b/src/Client/src/app/pages/store/catalog/catalog.component.css deleted file mode 100644 index 1081939..0000000 --- a/src/Client/src/app/pages/store/catalog/catalog.component.css +++ /dev/null @@ -1,145 +0,0 @@ -.gameCard { - position: relative; - background-color: var(--Mistox-Black); - float: left; - box-sizing: border-box; - margin: 0; - padding: 0; - width: 100%; - border-radius: 10px; - break-inside: avoid; - margin-bottom: 2rem; - border: solid 2px var(--Mistox-Background); - transition-duration: 1s; -} - -.gameCard :hover{ - border-color: var(--Mistox-Light); -} - -.gameCard-Name { - width: 100%; - text-align: left; - font-size: 25px; - padding: 5px 0 0 5px; - background-color: rgba(0,0,0,.1); -} - -.gameCard-Grid { - column-count: 4; - column-gap: 2rem; - padding-top: 20px; - width: calc(100% - 40px); - margin-left: 20px; -} - -@media (max-width: 1400px) { - .gameCard-Grid { - column-count: 3; - padding-top: 20px; - width: calc(100% - 40px); - margin-left: 20px; - } -} - -@media (max-width: 1100px) { - .gameCard-Grid { - column-count: 2; - padding-top: 20px; - width: calc(100% - 40px); - margin-left: 20px; - } -} - -@media (max-width: 900px) { - .gameCard-Grid { - column-count: 1; - padding-top: 20px; - width: calc(100% - 40px); - margin-left: 20px; - } -} - -.gameCard-Img { - width: 100%; - border-radius: 10px 10px 0 0; -} - -.gameCard-Next, -.gameCard-Prev { - background-color: transparent; - color: var(--Mistox-White); - padding: 16px; - margin-top: -22px; - font-size: 18px; - font-weight: bold; - border: none; - transition: background-color 0.6s ease; -} - - .gameCard-Next:hover, - .gameCard-Prev:hover { - background-color: rgba(0, 0, 0, 0.5); - } - -.gameCard-Prev { - position: absolute; - top: 50%; -} - -.gameCard-Next { - position: absolute; - top: 50%; - right: 0; -} - -.gameCard-Desc { - font-size: 13px; - margin: 5px; - color: var(--Mistox-Light); -} - -.gameCard-Price { - width: calc(50% - 10px); - float: left; - margin: 5px; - text-align: center; - margin-bottom: 10px; -} - -.gameCard-Button { - width: 40%; - margin: 5px 5%; - height: 38.4px; - color: var(--Mistox-Black); - background-color: var(--Mistox-Light); - font-size: 16px; - text-decoration: none; - text-transform: uppercase; - overflow: hidden; - transition: 0.5s; - letter-spacing: 2px; - border: 1px solid var(--Mistox-Light); - border-radius: 5px; -} - - .gameCard-Button :hover{ - background-color: var(--Mistox-Light); - color: var(--Mistox-White); - box-shadow: 4px 3px 6px var(--Mistox-Dark); - } - -.cartopen { - position: absolute; - background: var(--Mistox-Offset); - right: 10px; - top: 55px; - width: 400px; - border-radius: 5px; - backdrop-filter: blur(3px); - border: 1px solid var(--Mistox-Light); -} - -.cartclosed { - display: none; -} \ No newline at end of file diff --git a/src/Client/src/app/pages/store/catalog/catalog.component.html b/src/Client/src/app/pages/store/catalog/catalog.component.html deleted file mode 100644 index ee11ebb..0000000 --- a/src/Client/src/app/pages/store/catalog/catalog.component.html +++ /dev/null @@ -1,32 +0,0 @@ -
-
-
-
- - -
-
- -
-
-

{{ product.name }}

-
-

{{ line }}

-
-

${{ (product.cost/100).toFixed(2) }}

- -
- - -
-
-
- -
-
\ No newline at end of file diff --git a/src/Client/src/app/pages/store/catalog/catalog.component.ts b/src/Client/src/app/pages/store/catalog/catalog.component.ts deleted file mode 100644 index 5b4af5c..0000000 --- a/src/Client/src/app/pages/store/catalog/catalog.component.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { Component, NgZone } from '@angular/core'; -import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'; -import { FormsModule, NgModel } from '@angular/forms'; -import { Router, ActivatedRoute, RouterModule } from '@angular/router'; -import { Title } from '@angular/platform-browser'; -import { CommonModule } from '@angular/common'; -import { Authentication } from '../../../services/Authentication'; -import { Product } from 'app/models/Company'; - -@Component({ - selector: 'store-catalog', - templateUrl: './catalog.component.html', - styleUrl: './catalog.component.css', - imports: [ FormsModule, CommonModule, RouterModule ] -}) -export class CatalogComponent { - - public Products: Product[] = []; - - constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) { - this.title.setTitle("Store | Mistox"); - - // load each product - http.post("api/product/getall", null).subscribe( - response => { - this.Products = response; - - // Load each image - this.Products.forEach(item => { - item.curShowingIMG = 0; - item.images.forEach(img => { - http.get("api/productimage/get?ProductID=" + img.productID + "&ImageID=" + img.imageID, { responseType: 'blob' }).subscribe(blob => { - img.imageSrc = URL.createObjectURL(blob); - console.log(img.imageSrc); - }); - }); - }); - - } - ) - }; - - nextImg( prod: Product ){ - prod.curShowingIMG += 1; - if (prod.curShowingIMG == prod.images.length){ - prod.curShowingIMG = 0; - } - } - - prevImg( prod: Product ){ - prod.curShowingIMG -= 1; - if (prod.curShowingIMG == -1){ - prod.curShowingIMG = prod.images.length -1; - } - } - - DeleteItem( ProductID: number ) { - const body = new HttpParams() - .set("productID", ProductID); - const headers = new HttpHeaders({ - 'Content-Type': 'application/x-www-form-urlencoded', - }); - this.http.post( "api/product/delete", body, { headers } ).subscribe({ - next: data => { - if (data){ - window.location.reload(); - } - } - }) - } -} \ No newline at end of file diff --git a/src/Client/src/app/pages/store/payment/payment.component.css b/src/Client/src/app/pages/store/payment/payment.component.css deleted file mode 100644 index 30d2f6c..0000000 --- a/src/Client/src/app/pages/store/payment/payment.component.css +++ /dev/null @@ -1,24 +0,0 @@ -#payment-form { - max-width: 500px; - margin: 0 auto; -} - -.form-group { - margin-bottom: 20px; -} - -#card-element { - padding: 12px; - border: 1px solid #ccc; - border-radius: 4px; - background: #fff; -} - -#submit { - background-color: #5469d4; - color: white; - padding: 12px 20px; - border: none; - border-radius: 4px; - cursor: pointer; -} \ No newline at end of file diff --git a/src/Client/src/app/pages/store/payment/payment.component.html b/src/Client/src/app/pages/store/payment/payment.component.html deleted file mode 100644 index 52aca46..0000000 --- a/src/Client/src/app/pages/store/payment/payment.component.html +++ /dev/null @@ -1,8 +0,0 @@ -
-
- -
- -
- -
\ No newline at end of file diff --git a/src/Client/src/app/pages/store/payment/payment.component.ts b/src/Client/src/app/pages/store/payment/payment.component.ts deleted file mode 100644 index 8c285f2..0000000 --- a/src/Client/src/app/pages/store/payment/payment.component.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { Component } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { FormsModule } from '@angular/forms'; -import { Router, ActivatedRoute, RouterModule } from '@angular/router'; -import { Title } from '@angular/platform-browser'; -import { CommonModule } from '@angular/common'; -import { Authentication } from '../../../services/Authentication'; -import { loadStripe, Stripe, StripeElements } from '@stripe/stripe-js'; -import { firstValueFrom } from 'rxjs'; - -@Component({ - selector: 'store-payment', - templateUrl: './payment.component.html', - styleUrl: './payment.component.css', - imports: [ FormsModule, CommonModule, RouterModule ] -}) -export class PaymentComponent { - - stripe: Stripe | null = null; - elements: StripeElements | null = null; - - async ngOnInit(){ - - let ApiKey = await firstValueFrom(this.http.get("/api/payment/publickey")); - - this.stripe = await loadStripe(ApiKey); - if (this.stripe){ - this.elements = this.stripe?.elements(); - } - } - - ngAfterViewInit(){ - if (this.elements){ - const cardStyle = { - base: { - color: '#32325d', - fontFamily: '"Helvetica Neue", Helvetica, sans-serif', - fontSize: '16px', - '::placeholder': { - color: '#aab7c4', - } - }, - invalid: { - color: '#fa755a', - } - } - const card = this.elements.create('card', { style: cardStyle }); - card.mount('#card-element'); - } - } - - constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) { - this.title.setTitle("Payment | Mistox"); - - http.post("api/product/getall", null).subscribe( - response => { - - } - ) - }; - -} \ No newline at end of file -- 2.52.0 From ab4e15c5698a2afea6de121fe25b61323b1bac69 Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Thu, 17 Jul 2025 18:08:52 -0700 Subject: [PATCH 04/26] Cleanup routes --- src/Client/src/app/app.routes.ts | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/src/Client/src/app/app.routes.ts b/src/Client/src/app/app.routes.ts index 0bfac0d..41fdf03 100644 --- a/src/Client/src/app/app.routes.ts +++ b/src/Client/src/app/app.routes.ts @@ -2,19 +2,18 @@ import { Routes } from '@angular/router'; import { ForgotPasswordComponent } from './pages/account/forgotpassword/forgotpassword.component'; import { LoginComponent } from './pages/account/login/login.component'; import { RegisterComponent } from './pages/account/register/register.component'; -import { MistComponent } from './pages/project/mist/mist.component'; -import { CatalogComponent } from './pages/store/catalog/catalog.component'; import { AboutComponent } from './pages/legal/about/about.component'; import { SettingsComponent } from './pages/account/settings/settings.component'; import { LogoutComponent } from './pages/account/logout/logout.component'; import { ResetPasswordComponent } from './pages/account/resetpassword/resetpassword.component'; import { VerifyEmailComponent } from './pages/account/verifyemail/verifyemail.component'; -import { NewItemComponent } from './pages/store/admin/newitem/new.component'; -import { EditItemComponent } from './pages/store/admin/edititem/edit.component'; import { HomeComponent } from './pages/home/home.component'; export const routes: Routes = [ + // Home + { path: "", component: HomeComponent }, + // Account stuff { path: "account/forgotpassword", component: ForgotPasswordComponent }, { path: "account/resetpassword", component: ResetPasswordComponent }, @@ -24,18 +23,6 @@ export const routes: Routes = [ { path: "account/register", component: RegisterComponent }, { path: "account/settings", component: SettingsComponent }, - { path: "", component: HomeComponent }, - - // Projects - { path: "project/mist", component: MistComponent }, - - // Store - { path: "store/catalog", component: CatalogComponent }, - - // AdminPages - { path: "store/admin/new", component: NewItemComponent }, - { path: "store/admin/edit", component: EditItemComponent }, - // Legal { path: "about", component: AboutComponent }, ] \ No newline at end of file -- 2.52.0 From da04fa7a5b0c098b58c247b88d37a3db374de996 Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Thu, 17 Jul 2025 18:09:03 -0700 Subject: [PATCH 05/26] Fix resume type error --- src/Client/src/app/models/Resume.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Client/src/app/models/Resume.ts b/src/Client/src/app/models/Resume.ts index d054b9a..ef68ba7 100644 --- a/src/Client/src/app/models/Resume.ts +++ b/src/Client/src/app/models/Resume.ts @@ -11,7 +11,7 @@ export class Resume { public city: string = ""; public isActive: boolean = false; public experience: ResumeExperience[] = []; - public military: ResumeMilitary = []; + public military: ResumeMilitary = new ResumeMilitary; public education: ResumeEducation[] = []; public skills: ResumeSkill[] = []; public languages: ResumeLanguage[] = []; -- 2.52.0 From d59d476a6e34f66a8ba64d98b6a8d114efff5ccd Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Thu, 17 Jul 2025 18:09:23 -0700 Subject: [PATCH 06/26] Fix user errors for login auth --- .../pages/account/login/login.component.ts | 7 +---- .../account/register/register.component.ts | 29 ++++++++----------- src/Client/src/app/services/Authentication.ts | 6 ++-- 3 files changed, 15 insertions(+), 27 deletions(-) diff --git a/src/Client/src/app/pages/account/login/login.component.ts b/src/Client/src/app/pages/account/login/login.component.ts index d0e23a9..1420e0f 100644 --- a/src/Client/src/app/pages/account/login/login.component.ts +++ b/src/Client/src/app/pages/account/login/login.component.ts @@ -45,12 +45,7 @@ export class LoginComponent { this.errorMsgs.push("Waiting for response from server"); this.auth.Login(this.UserName, this.Password, this.StayLoggedIn).subscribe( data => { - if (data.error.length === 0){ - this.router.navigate([this.returnURL]); - }else{ - this.errorMsgs.pop(); - this.errorMsgs.push(data.error); - } + this.router.navigate([this.returnURL]); } ) } diff --git a/src/Client/src/app/pages/account/register/register.component.ts b/src/Client/src/app/pages/account/register/register.component.ts index 5a7b7aa..154bdf0 100644 --- a/src/Client/src/app/pages/account/register/register.component.ts +++ b/src/Client/src/app/pages/account/register/register.component.ts @@ -60,26 +60,21 @@ export class RegisterComponent { // Send to server and wait for response this.errorMsgs.push("Waiting for response from server"); const body = new HttpParams() - .set("Email", this.email) - .set("UserName", this.userName) - .set("PasswordHash", this.passwordHash); + .set("Email", this.email) + .set("UserName", this.userName) + .set("PasswordHash", this.passwordHash); const headers = new HttpHeaders({ - 'Content-Type': 'application/x-www-form-urlencoded' + 'Content-Type': 'application/x-www-form-urlencoded' }); this.http.post( "api/account/register", body, { headers } ).subscribe({ - next: async (data) => { - if (data.error.length === 0){ - this.errorMsgs = ["Account Created"]; - await this.sleep(3000); - this.router.navigate([this.returnURL]); - }else{ - this.errorMsgs = []; - this.errorMsgs.push(data.error); - } - }, - error: err => { - console.log("HTTP Error Signing In: ", err); - } + next: async (data) => { + this.errorMsgs = ["Account Created"]; + await this.sleep(3000); + this.router.navigate([this.returnURL]); + }, + error: err => { + console.log("HTTP Error Signing In: ", err); + } }); } } \ No newline at end of file diff --git a/src/Client/src/app/services/Authentication.ts b/src/Client/src/app/services/Authentication.ts index ca3b9ae..dfb95c9 100644 --- a/src/Client/src/app/services/Authentication.ts +++ b/src/Client/src/app/services/Authentication.ts @@ -24,10 +24,8 @@ export class Authentication{ let sub = this.http.post( "api/account/login", body, { headers } ); sub.subscribe({ next: data => { - if (data.error.length === 0){ - this._user.next(data); - this.setUserToStorage(data, StayLoggedIn == true ? SessionType.Forever : SessionType.Session); - } + this._user.next(data); + this.setUserToStorage(data, StayLoggedIn == true ? SessionType.Forever : SessionType.Session); }, error: err => { console.log("HTTP Error Signing In: ", err); -- 2.52.0 From 792e0abba379b0347c1639a6ef769c92965f512d Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Thu, 17 Jul 2025 18:18:27 -0700 Subject: [PATCH 07/26] Authentication works as designed --- .../src/app/pages/account/login/login.component.ts | 9 ++++++--- .../src/app/pages/account/register/register.component.ts | 2 +- src/Client/src/app/services/Authentication.ts | 2 +- src/Server/Controllers/AuthenticationController.cs | 4 ++-- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/Client/src/app/pages/account/login/login.component.ts b/src/Client/src/app/pages/account/login/login.component.ts index 1420e0f..751f5ed 100644 --- a/src/Client/src/app/pages/account/login/login.component.ts +++ b/src/Client/src/app/pages/account/login/login.component.ts @@ -43,10 +43,13 @@ export class LoginComponent { } this.errorMsgs.push("Waiting for response from server"); - this.auth.Login(this.UserName, this.Password, this.StayLoggedIn).subscribe( - data => { + this.auth.Login(this.UserName, this.Password, this.StayLoggedIn).subscribe({ + next: data => { this.router.navigate([this.returnURL]); + }, + error: err => { + this.errorMsgs = [ err.error ]; } - ) + }) } } \ No newline at end of file diff --git a/src/Client/src/app/pages/account/register/register.component.ts b/src/Client/src/app/pages/account/register/register.component.ts index 154bdf0..321c552 100644 --- a/src/Client/src/app/pages/account/register/register.component.ts +++ b/src/Client/src/app/pages/account/register/register.component.ts @@ -73,7 +73,7 @@ export class RegisterComponent { this.router.navigate([this.returnURL]); }, error: err => { - console.log("HTTP Error Signing In: ", err); + this.errorMsgs = [ err.error ] } }); } diff --git a/src/Client/src/app/services/Authentication.ts b/src/Client/src/app/services/Authentication.ts index dfb95c9..4e7c8a9 100644 --- a/src/Client/src/app/services/Authentication.ts +++ b/src/Client/src/app/services/Authentication.ts @@ -28,7 +28,7 @@ export class Authentication{ this.setUserToStorage(data, StayLoggedIn == true ? SessionType.Forever : SessionType.Session); }, error: err => { - console.log("HTTP Error Signing In: ", err); + console.log("HTTP Error Signing In: ", err.error); } }); return sub; diff --git a/src/Server/Controllers/AuthenticationController.cs b/src/Server/Controllers/AuthenticationController.cs index 463ab62..3971608 100755 --- a/src/Server/Controllers/AuthenticationController.cs +++ b/src/Server/Controllers/AuthenticationController.cs @@ -51,7 +51,7 @@ namespace BoredCareers.Controllers { } else { test.CurrentPasswordAttempts += 1; await _databaseService.SetAccount(test); - return Ok(new Account() { ID = -1, UserName = "Wrong Password" }); + return NotFound("Wrong Password"); } } else { await SendVerify(test.UserName); @@ -92,7 +92,7 @@ namespace BoredCareers.Controllers { } } catch (Exception ex) { Console.WriteLine("Register Error: " + ex.Message); - return NotFound(); + return NotFound("An internal server error has occured"); } } -- 2.52.0 From 91b39504b6fa43a0e8910fa46274109a0cf27eb1 Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Thu, 17 Jul 2025 18:25:50 -0700 Subject: [PATCH 08/26] Make all api follow the same error pattern --- .../Controllers/AuthenticationController.cs | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/Server/Controllers/AuthenticationController.cs b/src/Server/Controllers/AuthenticationController.cs index 3971608..994ddc1 100755 --- a/src/Server/Controllers/AuthenticationController.cs +++ b/src/Server/Controllers/AuthenticationController.cs @@ -47,7 +47,7 @@ namespace BoredCareers.Controllers { IsPersistent = StayLoggedIn, // Is set from the StayLoggedIn } ); - return test; + return Ok(test); } else { test.CurrentPasswordAttempts += 1; await _databaseService.SetAccount(test); @@ -61,7 +61,7 @@ namespace BoredCareers.Controllers { return NotFound("Account Not Found"); } catch (Exception ex) { Console.WriteLine("Login Error: " + ex.Message); - return NotFound(); + return NotFound("An internal server error has occured"); } } @@ -110,10 +110,10 @@ namespace BoredCareers.Controllers { return Ok(); } } - return NotFound(); + return NotFound("Not logged in"); } catch (Exception ex) { Console.WriteLine("ChangePassword Error: " + ex.Message); - return NotFound(); + return NotFound("An internal server error has occured"); } } @@ -128,10 +128,10 @@ namespace BoredCareers.Controllers { await _databaseService.SetAccount(user); return Ok(); } - return NotFound(); + return NotFound("Not logged in"); } catch (Exception ex) { Console.WriteLine("ToggleAccountLock Error: " + ex.Message); - return NotFound(); + return NotFound("An internal server error has occured"); } } @@ -142,10 +142,10 @@ namespace BoredCareers.Controllers { if (isLoggedIn()) { return Ok(await getLoggedInUser()); } - return NotFound(); + return NotFound("Not logged in"); } catch (Exception ex) { Console.WriteLine("Get Error: " + ex); - return NotFound(); + return NotFound("An internal server error has occured"); } } @@ -168,7 +168,7 @@ namespace BoredCareers.Controllers { 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 "; + return NotFound("Cannot sent another verify email until 5 minutes has elapsed"); } else { _emailContext._SentEmails.Remove(key); @@ -186,11 +186,11 @@ namespace BoredCareers.Controllers { string result = _emailContext.Send(test.Email, EmailService.VerifyEmailSubject, EmailContents); _emailContext._SentEmails.Add(key, DateTime.Now); - return result; + return Ok(result); } - return "Account not found"; + return NotFound("Account not found"); } catch (Exception) { - return "The connection couldn't be established to the email server"; + return NotFound("An internal server error has occured"); } } @@ -204,12 +204,12 @@ namespace BoredCareers.Controllers { test.EmailToken = ""; test.EmailVerified = true; await _databaseService.SetAccount(test); - return true; + return Ok(true); } } - return false; + return NotFound("Account not found or token is invalid");; } catch { - return false; + return NotFound("An internal server error has occured"); } } @@ -222,7 +222,7 @@ namespace BoredCareers.Controllers { 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"; + return NotFound("Cannot sent another reset requests until 5 minutes has elapsed"); } else { _emailContext._SentEmails.Remove(key); @@ -240,12 +240,12 @@ namespace BoredCareers.Controllers { string result = _emailContext.Send(test.Email, EmailService.VerifyEmailSubject, EmailContents); _emailContext._SentEmails.Add(key, DateTime.Now); - return result; + return Ok(result); } - return "Account Not Found"; + return NotFound("Account Not Found"); } catch (Exception e) { Console.WriteLine("EmailService Error: " + e.ToString()); - return "The connection couldn't be established to the email server"; + return NotFound("An internal server error has occured"); } } @@ -261,12 +261,12 @@ namespace BoredCareers.Controllers { test.EmailToken = ""; test.PasswordHash = BCrypt.Net.BCrypt.HashPassword(NewPassword); await _databaseService.SetAccount(test); - return true; + return Ok(true); } } - return false; + return NotFound("Account not found or reset token is bad"); } catch { - return false; + return NotFound("An internal server error has occured"); } } @@ -281,10 +281,10 @@ namespace BoredCareers.Controllers { return Ok(); } } - return NotFound(); + return NotFound("User is not logged in"); } catch (Exception ex) { Console.WriteLine("Delete Error: " + ex.Message); - return NotFound(); + return NotFound("An internal server error has occured"); } } -- 2.52.0 From 521a8a20245ac84f95cee8a2b9566f7d422dd8db Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Thu, 17 Jul 2025 21:39:06 -0700 Subject: [PATCH 09/26] Move Home into folder --- src/Client/src/app/pages/home/home.component.css | 15 --------------- src/Client/src/app/pages/home/home.component.html | 11 ----------- .../src/app/pages/main/home/home.component.css | 0 .../src/app/pages/main/home/home.component.html | 0 .../app/pages/{ => main}/home/home.component.ts | 2 +- 5 files changed, 1 insertion(+), 27 deletions(-) delete mode 100644 src/Client/src/app/pages/home/home.component.css delete mode 100644 src/Client/src/app/pages/home/home.component.html create mode 100644 src/Client/src/app/pages/main/home/home.component.css create mode 100644 src/Client/src/app/pages/main/home/home.component.html rename src/Client/src/app/pages/{ => main}/home/home.component.ts (96%) diff --git a/src/Client/src/app/pages/home/home.component.css b/src/Client/src/app/pages/home/home.component.css deleted file mode 100644 index 26081b8..0000000 --- a/src/Client/src/app/pages/home/home.component.css +++ /dev/null @@ -1,15 +0,0 @@ -.center { - background-color: green; -} - -.tile-frame { - column-count: 4; - column-gap: 20px; - padding: 20px; - width: calc(100% - 40px); -} - -.tile{ - background-color: aqua; - height: 40px; -} \ No newline at end of file diff --git a/src/Client/src/app/pages/home/home.component.html b/src/Client/src/app/pages/home/home.component.html deleted file mode 100644 index 29da843..0000000 --- a/src/Client/src/app/pages/home/home.component.html +++ /dev/null @@ -1,11 +0,0 @@ -
- -
- -
- -
- -
- -
\ No newline at end of file diff --git a/src/Client/src/app/pages/main/home/home.component.css b/src/Client/src/app/pages/main/home/home.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/Client/src/app/pages/main/home/home.component.html b/src/Client/src/app/pages/main/home/home.component.html new file mode 100644 index 0000000..e69de29 diff --git a/src/Client/src/app/pages/home/home.component.ts b/src/Client/src/app/pages/main/home/home.component.ts similarity index 96% rename from src/Client/src/app/pages/home/home.component.ts rename to src/Client/src/app/pages/main/home/home.component.ts index 6d409fd..478962e 100644 --- a/src/Client/src/app/pages/home/home.component.ts +++ b/src/Client/src/app/pages/main/home/home.component.ts @@ -6,7 +6,7 @@ import { Title } from '@angular/platform-browser'; import { CommonModule } from '@angular/common'; @Component({ - selector: 'home', + selector: 'main-home', templateUrl: './home.component.html', styleUrls: [ './home.component.css' ], imports: [ FormsModule, CommonModule ] -- 2.52.0 From 87cac2be8eb8c03b5e37fc6c9790fe783850c8af Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Thu, 17 Jul 2025 21:39:29 -0700 Subject: [PATCH 10/26] Change titlebar options --- src/Client/src/app/app.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Client/src/app/app.html b/src/Client/src/app/app.html index 17d70fc..61c0b51 100644 --- a/src/Client/src/app/app.html +++ b/src/Client/src/app/app.html @@ -1,8 +1,8 @@
\ No newline at end of file diff --git a/src/Client/src/app/pages/legal/about/about.component.ts b/src/Client/src/app/pages/legal/about/about.component.ts index 633ccb3..24cb909 100644 --- a/src/Client/src/app/pages/legal/about/about.component.ts +++ b/src/Client/src/app/pages/legal/about/about.component.ts @@ -8,6 +8,7 @@ import { CommonModule } from '@angular/common'; @Component({ selector: 'legal-about', templateUrl: './about.component.html', + styleUrls: [ './about.component.css' ], imports: [ FormsModule, CommonModule ] }) export class AboutComponent { diff --git a/src/Client/src/app/pages/legal/contact/contact.component.css b/src/Client/src/app/pages/legal/contact/contact.component.css new file mode 100644 index 0000000..26081b8 --- /dev/null +++ b/src/Client/src/app/pages/legal/contact/contact.component.css @@ -0,0 +1,15 @@ +.center { + background-color: green; +} + +.tile-frame { + column-count: 4; + column-gap: 20px; + padding: 20px; + width: calc(100% - 40px); +} + +.tile{ + background-color: aqua; + height: 40px; +} \ No newline at end of file diff --git a/src/Client/src/app/pages/legal/contact/contact.component.html b/src/Client/src/app/pages/legal/contact/contact.component.html new file mode 100644 index 0000000..29da843 --- /dev/null +++ b/src/Client/src/app/pages/legal/contact/contact.component.html @@ -0,0 +1,11 @@ +
+ +
+ +
+ +
+ +
+ +
\ No newline at end of file diff --git a/src/Client/src/app/pages/legal/contact/contact.component.ts b/src/Client/src/app/pages/legal/contact/contact.component.ts new file mode 100644 index 0000000..eaa44cf --- /dev/null +++ b/src/Client/src/app/pages/legal/contact/contact.component.ts @@ -0,0 +1,20 @@ +import { Component } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { FormsModule } from '@angular/forms'; +import { Router, ActivatedRoute } from '@angular/router'; +import { Title } from '@angular/platform-browser'; +import { CommonModule } from '@angular/common'; + +@Component({ + selector: 'legal-contact', + templateUrl: './contact.component.html', + styleUrls: [ './contact.component.css' ], + imports: [ FormsModule, CommonModule ] +}) +export class ContactComponent { + + constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title ) { + this.title.setTitle("Contact | BoredCareers"); + }; + +} \ No newline at end of file diff --git a/src/Client/src/app/pages/legal/privacy/privacy.component.css b/src/Client/src/app/pages/legal/privacy/privacy.component.css new file mode 100644 index 0000000..26081b8 --- /dev/null +++ b/src/Client/src/app/pages/legal/privacy/privacy.component.css @@ -0,0 +1,15 @@ +.center { + background-color: green; +} + +.tile-frame { + column-count: 4; + column-gap: 20px; + padding: 20px; + width: calc(100% - 40px); +} + +.tile{ + background-color: aqua; + height: 40px; +} \ No newline at end of file diff --git a/src/Client/src/app/pages/legal/privacy/privacy.component.html b/src/Client/src/app/pages/legal/privacy/privacy.component.html new file mode 100644 index 0000000..29da843 --- /dev/null +++ b/src/Client/src/app/pages/legal/privacy/privacy.component.html @@ -0,0 +1,11 @@ +
+ +
+ +
+ +
+ +
+ +
\ No newline at end of file diff --git a/src/Client/src/app/pages/legal/privacy/privacy.component.ts b/src/Client/src/app/pages/legal/privacy/privacy.component.ts new file mode 100644 index 0000000..f934ab4 --- /dev/null +++ b/src/Client/src/app/pages/legal/privacy/privacy.component.ts @@ -0,0 +1,20 @@ +import { Component } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { FormsModule } from '@angular/forms'; +import { Router, ActivatedRoute } from '@angular/router'; +import { Title } from '@angular/platform-browser'; +import { CommonModule } from '@angular/common'; + +@Component({ + selector: 'legal-privacy', + templateUrl: './privacy.component.html', + styleUrls: [ './privacy.component.css' ], + imports: [ FormsModule, CommonModule ] +}) +export class PrivacyComponent { + + constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title ) { + this.title.setTitle("Contact | BoredCareers"); + }; + +} \ No newline at end of file -- 2.52.0 From 485ad1b3de7b9797cc05daa31dde509b401b844e Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Thu, 17 Jul 2025 21:40:58 -0700 Subject: [PATCH 14/26] add resume page --- .../pages/main/resumes/resumes.component.css | 0 .../pages/main/resumes/resumes.component.html | 13 ++++++++++ .../pages/main/resumes/resumes.component.ts | 24 +++++++++++++++++++ 3 files changed, 37 insertions(+) create mode 100644 src/Client/src/app/pages/main/resumes/resumes.component.css create mode 100644 src/Client/src/app/pages/main/resumes/resumes.component.html create mode 100644 src/Client/src/app/pages/main/resumes/resumes.component.ts diff --git a/src/Client/src/app/pages/main/resumes/resumes.component.css b/src/Client/src/app/pages/main/resumes/resumes.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/Client/src/app/pages/main/resumes/resumes.component.html b/src/Client/src/app/pages/main/resumes/resumes.component.html new file mode 100644 index 0000000..196d036 --- /dev/null +++ b/src/Client/src/app/pages/main/resumes/resumes.component.html @@ -0,0 +1,13 @@ +
+
+

{{ cur.name }}

+

{{ cur.field }}

+

{{ cur.email }}

+

{{ cur.phoneNumber }}

+

{{ cur.city }}

+

{{ cur.stateOrRegion }}

+

{{ cur.country }}

+

{{ cur.postalCode }}

+

Active: {{ cur.isActive }}

+
+
\ No newline at end of file diff --git a/src/Client/src/app/pages/main/resumes/resumes.component.ts b/src/Client/src/app/pages/main/resumes/resumes.component.ts new file mode 100644 index 0000000..75cba38 --- /dev/null +++ b/src/Client/src/app/pages/main/resumes/resumes.component.ts @@ -0,0 +1,24 @@ +import { Component } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { FormsModule } from '@angular/forms'; +import { Router, ActivatedRoute } from '@angular/router'; +import { Title } from '@angular/platform-browser'; +import { CommonModule } from '@angular/common'; +import { Resume } from 'app/models/Resume'; + +@Component({ + selector: 'main-resumes', + templateUrl: './resumes.component.html', + styleUrls: [ './resumes.component.css' ], + imports: [ FormsModule, CommonModule ] +}) +export class ResumesComponent { + + public ResumePage: Resume[] = []; + + constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title ) { + this.title.setTitle("Resumes | BoredCareers"); + + }; + +} \ No newline at end of file -- 2.52.0 From 30cfe67a7bd5887b8f8764d00b966ed2b6e1ea8d Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Thu, 17 Jul 2025 21:41:18 -0700 Subject: [PATCH 15/26] Start work on job listings --- .../main/jobs/edit/jobedit.component.css | 12 +++++ .../main/jobs/edit/jobedit.component.html | 16 ++++++ .../pages/main/jobs/edit/jobedit.component.ts | 53 +++++++++++++++++++ .../app/pages/main/jobs/jobs.component.css | 12 +++++ .../app/pages/main/jobs/jobs.component.html | 42 +++++++++++++++ .../src/app/pages/main/jobs/jobs.component.ts | 53 +++++++++++++++++++ .../pages/main/jobs/new/jobnew.component.css | 12 +++++ .../pages/main/jobs/new/jobnew.component.html | 16 ++++++ .../pages/main/jobs/new/jobnew.component.ts | 53 +++++++++++++++++++ .../Controllers/JobListingController.cs | 2 + 10 files changed, 271 insertions(+) create mode 100644 src/Client/src/app/pages/main/jobs/edit/jobedit.component.css create mode 100644 src/Client/src/app/pages/main/jobs/edit/jobedit.component.html create mode 100644 src/Client/src/app/pages/main/jobs/edit/jobedit.component.ts create mode 100644 src/Client/src/app/pages/main/jobs/jobs.component.css create mode 100644 src/Client/src/app/pages/main/jobs/jobs.component.html create mode 100644 src/Client/src/app/pages/main/jobs/jobs.component.ts create mode 100644 src/Client/src/app/pages/main/jobs/new/jobnew.component.css create mode 100644 src/Client/src/app/pages/main/jobs/new/jobnew.component.html create mode 100644 src/Client/src/app/pages/main/jobs/new/jobnew.component.ts diff --git a/src/Client/src/app/pages/main/jobs/edit/jobedit.component.css b/src/Client/src/app/pages/main/jobs/edit/jobedit.component.css new file mode 100644 index 0000000..9d97a2c --- /dev/null +++ b/src/Client/src/app/pages/main/jobs/edit/jobedit.component.css @@ -0,0 +1,12 @@ +.tile-frame { + column-count: 4; + column-gap: 20px; + padding: 20px; + width: calc(100% - 40px); +} + +.tile{ + background-color: var(--Mistox-Dark)\); + height: 40px; + break-inside: avoid; +} \ No newline at end of file diff --git a/src/Client/src/app/pages/main/jobs/edit/jobedit.component.html b/src/Client/src/app/pages/main/jobs/edit/jobedit.component.html new file mode 100644 index 0000000..05e4dca --- /dev/null +++ b/src/Client/src/app/pages/main/jobs/edit/jobedit.component.html @@ -0,0 +1,16 @@ +
+
+

{{ cur.title }}

+

{{ cur.jobType }}

+

Is Remote: {{ cur.remote }}

+

{{ cur.salaryMin }}

+

{{ cur.salaryMax }}

+

{{ cur.city }}

+

{{ cur.stateOrRegion }}

+

{{ cur.country }}

+

{{ cur.postalCode }}

+

{{ cur.description }}

+

Posted: {{ cur.createdTime }}

+

Modified: {{ cur.modifiedTime }}

+
+
\ No newline at end of file diff --git a/src/Client/src/app/pages/main/jobs/edit/jobedit.component.ts b/src/Client/src/app/pages/main/jobs/edit/jobedit.component.ts new file mode 100644 index 0000000..33bd400 --- /dev/null +++ b/src/Client/src/app/pages/main/jobs/edit/jobedit.component.ts @@ -0,0 +1,53 @@ +import { Component } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { FormsModule } from '@angular/forms'; +import { Router, ActivatedRoute, RouterModule } from '@angular/router'; +import { Title } from '@angular/platform-browser'; +import { CommonModule } from '@angular/common'; +import { JobListing } from 'app/models/JobListing'; +import { Authentication } from 'app/services/Authentication'; + +@Component({ + selector: 'main-jobs-edit', + templateUrl: './jobedit.component.html', + styleUrls: [ './jobedit.component.css' ], + imports: [ FormsModule, CommonModule, RouterModule ] +}) +export class JobEditComponent { + + public MyJobListings: JobListing[] = []; + public JobListingPage: JobListing[] = []; + public ErrorMsg: string = ""; + + public Page: number = 1; + + constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) { + this.title.setTitle("Jobs | BoredCareers"); + + if (this.Page == 1){ + + } + + http.get("api/joblisting?PageQuantity=" + 10 + "&Page=" + 1).subscribe({ + next: data => { + this.JobListingPage = data; + }, + error: err => { + this.ErrorMsg = err.error; + } + }); + + }; + + RemoveJobListing( JobListingID: number ){ + this.http.delete("api/joblisting?JobListingID=" + JobListingID).subscribe({ + next: data => { + window.location.reload(); + }, + error: err => { + alert("Failed to delete the job listing. Try again"); + } + }); + } + +} \ No newline at end of file diff --git a/src/Client/src/app/pages/main/jobs/jobs.component.css b/src/Client/src/app/pages/main/jobs/jobs.component.css new file mode 100644 index 0000000..9d97a2c --- /dev/null +++ b/src/Client/src/app/pages/main/jobs/jobs.component.css @@ -0,0 +1,12 @@ +.tile-frame { + column-count: 4; + column-gap: 20px; + padding: 20px; + width: calc(100% - 40px); +} + +.tile{ + background-color: var(--Mistox-Dark)\); + height: 40px; + break-inside: avoid; +} \ No newline at end of file diff --git a/src/Client/src/app/pages/main/jobs/jobs.component.html b/src/Client/src/app/pages/main/jobs/jobs.component.html new file mode 100644 index 0000000..5c422ac --- /dev/null +++ b/src/Client/src/app/pages/main/jobs/jobs.component.html @@ -0,0 +1,42 @@ + +
+
+
+

{{ cur.title }}

+

{{ cur.jobType }}

+

Is Remote: {{ cur.remote }}

+

{{ cur.salaryMin }}

+

{{ cur.salaryMax }}

+

{{ cur.city }}

+

{{ cur.stateOrRegion }}

+

{{ cur.country }}

+

{{ cur.postalCode }}

+

{{ cur.description }}

+

Posted: {{ cur.createdTime }}

+

Modified: {{ cur.modifiedTime }}

+
+ + +
+
+ +
+
+ + +
+
+

{{ cur.title }}

+

{{ cur.jobType }}

+

Is Remote: {{ cur.remote }}

+

{{ cur.salaryMin }}

+

{{ cur.salaryMax }}

+

{{ cur.city }}

+

{{ cur.stateOrRegion }}

+

{{ cur.country }}

+

{{ cur.postalCode }}

+

{{ cur.description }}

+

Posted: {{ cur.createdTime }}

+

Modified: {{ cur.modifiedTime }}

+
+
\ No newline at end of file diff --git a/src/Client/src/app/pages/main/jobs/jobs.component.ts b/src/Client/src/app/pages/main/jobs/jobs.component.ts new file mode 100644 index 0000000..336d4ef --- /dev/null +++ b/src/Client/src/app/pages/main/jobs/jobs.component.ts @@ -0,0 +1,53 @@ +import { Component } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { FormsModule } from '@angular/forms'; +import { Router, ActivatedRoute, RouterModule } from '@angular/router'; +import { Title } from '@angular/platform-browser'; +import { CommonModule } from '@angular/common'; +import { JobListing } from 'app/models/JobListing'; +import { Authentication } from 'app/services/Authentication'; + +@Component({ + selector: 'main-jobs', + templateUrl: './jobs.component.html', + styleUrls: [ './jobs.component.css' ], + imports: [ FormsModule, CommonModule, RouterModule ] +}) +export class JobsComponent { + + public MyJobListings: JobListing[] = []; + public JobListingPage: JobListing[] = []; + public ErrorMsg: string = ""; + + public Page: number = 1; + + constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) { + this.title.setTitle("Jobs | BoredCareers"); + + if (this.Page == 1){ + + } + + http.get("api/joblisting?PageQuantity=" + 10 + "&Page=" + 1).subscribe({ + next: data => { + this.JobListingPage = data; + }, + error: err => { + this.ErrorMsg = err.error; + } + }); + + }; + + RemoveJobListing( JobListingID: number ){ + this.http.delete("api/joblisting?JobListingID=" + JobListingID).subscribe({ + next: data => { + window.location.reload(); + }, + error: err => { + alert("Failed to delete the job listing. Try again"); + } + }); + } + +} \ No newline at end of file diff --git a/src/Client/src/app/pages/main/jobs/new/jobnew.component.css b/src/Client/src/app/pages/main/jobs/new/jobnew.component.css new file mode 100644 index 0000000..9d97a2c --- /dev/null +++ b/src/Client/src/app/pages/main/jobs/new/jobnew.component.css @@ -0,0 +1,12 @@ +.tile-frame { + column-count: 4; + column-gap: 20px; + padding: 20px; + width: calc(100% - 40px); +} + +.tile{ + background-color: var(--Mistox-Dark)\); + height: 40px; + break-inside: avoid; +} \ No newline at end of file diff --git a/src/Client/src/app/pages/main/jobs/new/jobnew.component.html b/src/Client/src/app/pages/main/jobs/new/jobnew.component.html new file mode 100644 index 0000000..05e4dca --- /dev/null +++ b/src/Client/src/app/pages/main/jobs/new/jobnew.component.html @@ -0,0 +1,16 @@ +
+
+

{{ cur.title }}

+

{{ cur.jobType }}

+

Is Remote: {{ cur.remote }}

+

{{ cur.salaryMin }}

+

{{ cur.salaryMax }}

+

{{ cur.city }}

+

{{ cur.stateOrRegion }}

+

{{ cur.country }}

+

{{ cur.postalCode }}

+

{{ cur.description }}

+

Posted: {{ cur.createdTime }}

+

Modified: {{ cur.modifiedTime }}

+
+
\ No newline at end of file diff --git a/src/Client/src/app/pages/main/jobs/new/jobnew.component.ts b/src/Client/src/app/pages/main/jobs/new/jobnew.component.ts new file mode 100644 index 0000000..9e7e3b0 --- /dev/null +++ b/src/Client/src/app/pages/main/jobs/new/jobnew.component.ts @@ -0,0 +1,53 @@ +import { Component } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { FormsModule } from '@angular/forms'; +import { Router, ActivatedRoute, RouterModule } from '@angular/router'; +import { Title } from '@angular/platform-browser'; +import { CommonModule } from '@angular/common'; +import { JobListing } from 'app/models/JobListing'; +import { Authentication } from 'app/services/Authentication'; + +@Component({ + selector: 'main-jobs-new', + templateUrl: './jobnew.component.html', + styleUrls: [ './jobnew.component.css' ], + imports: [ FormsModule, CommonModule, RouterModule ] +}) +export class JobNewComponent { + + public MyJobListings: JobListing[] = []; + public JobListingPage: JobListing[] = []; + public ErrorMsg: string = ""; + + public Page: number = 1; + + constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) { + this.title.setTitle("Jobs | BoredCareers"); + + if (this.Page == 1){ + + } + + http.get("api/joblisting?PageQuantity=" + 10 + "&Page=" + 1).subscribe({ + next: data => { + this.JobListingPage = data; + }, + error: err => { + this.ErrorMsg = err.error; + } + }); + + }; + + RemoveJobListing( JobListingID: number ){ + this.http.delete("api/joblisting?JobListingID=" + JobListingID).subscribe({ + next: data => { + window.location.reload(); + }, + error: err => { + alert("Failed to delete the job listing. Try again"); + } + }); + } + +} \ No newline at end of file diff --git a/src/Server/Controllers/JobListingController.cs b/src/Server/Controllers/JobListingController.cs index 495fb0b..3325908 100644 --- a/src/Server/Controllers/JobListingController.cs +++ b/src/Server/Controllers/JobListingController.cs @@ -30,6 +30,7 @@ namespace BoredCareers.Controllers { if (isLoggedIn()) { if (await isLoggedInUserEmployeeOf(JobListing.CompanyID)) { await _databaseService.SetJobListing(JobListing); + return Ok(); } } return NotFound(); @@ -42,6 +43,7 @@ namespace BoredCareers.Controllers { if (jobListing != null) { if (await isLoggedInUserEmployeeOf(JobListingID)) { await _databaseService.DeleteJobListing(JobListingID); + return Ok(); } } } -- 2.52.0 From a4d7dd79733fcabee0f1dc4174cae9952539dac5 Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Thu, 17 Jul 2025 21:41:28 -0700 Subject: [PATCH 16/26] Add all the routes --- src/Client/src/app/app.routes.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Client/src/app/app.routes.ts b/src/Client/src/app/app.routes.ts index 41fdf03..7fec6b3 100644 --- a/src/Client/src/app/app.routes.ts +++ b/src/Client/src/app/app.routes.ts @@ -7,12 +7,24 @@ import { SettingsComponent } from './pages/account/settings/settings.component'; import { LogoutComponent } from './pages/account/logout/logout.component'; import { ResetPasswordComponent } from './pages/account/resetpassword/resetpassword.component'; import { VerifyEmailComponent } from './pages/account/verifyemail/verifyemail.component'; -import { HomeComponent } from './pages/home/home.component'; +import { HomeComponent } from './pages/main/home/home.component'; +import { ContactComponent } from './pages/legal/contact/contact.component'; +import { PrivacyComponent } from './pages/legal/privacy/privacy.component'; +import { JobsComponent } from './pages/main/jobs/jobs.component'; +import { ResumesComponent } from './pages/main/resumes/resumes.component'; +import { JobNewComponent } from './pages/main/jobs/new/jobnew.component'; +import { JobEditComponent } from './pages/main/jobs/edit/jobedit.component'; export const routes: Routes = [ // Home { path: "", component: HomeComponent }, + { path: "resumes", component: ResumesComponent }, + + // Jobs + { path: "jobs", component: JobsComponent }, + { path: "jobs/new", component: JobNewComponent }, + { path: "jobs/edit", component: JobEditComponent }, // Account stuff { path: "account/forgotpassword", component: ForgotPasswordComponent }, @@ -25,4 +37,6 @@ export const routes: Routes = [ // Legal { path: "about", component: AboutComponent }, + { path: "contact", component: ContactComponent }, + { path: "privacy", component: PrivacyComponent } ] \ No newline at end of file -- 2.52.0 From 7491e78dba7c71b0fbf0079cf2c002b46bc85b85 Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Thu, 17 Jul 2025 21:49:49 -0700 Subject: [PATCH 17/26] Attempt to fix auth --- .../src/app/pages/account/logout/logout.component.ts | 7 +++++-- .../src/app/pages/legal/privacy/privacy.component.ts | 2 +- src/Client/src/app/services/Authentication.ts | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Client/src/app/pages/account/logout/logout.component.ts b/src/Client/src/app/pages/account/logout/logout.component.ts index 5d4c3b1..4357ff9 100644 --- a/src/Client/src/app/pages/account/logout/logout.component.ts +++ b/src/Client/src/app/pages/account/logout/logout.component.ts @@ -21,7 +21,10 @@ export class LogoutComponent { } ngAfterViewInit(){ - this.auth.Logout(); - this.router.navigate(["/"]); + this.auth.Logout().subscribe({ + next: data => { + this.router.navigate(["/"]); + } + }); } } \ No newline at end of file diff --git a/src/Client/src/app/pages/legal/privacy/privacy.component.ts b/src/Client/src/app/pages/legal/privacy/privacy.component.ts index f934ab4..9543545 100644 --- a/src/Client/src/app/pages/legal/privacy/privacy.component.ts +++ b/src/Client/src/app/pages/legal/privacy/privacy.component.ts @@ -14,7 +14,7 @@ import { CommonModule } from '@angular/common'; export class PrivacyComponent { constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title ) { - this.title.setTitle("Contact | BoredCareers"); + this.title.setTitle("Privacy | BoredCareers"); }; } \ No newline at end of file diff --git a/src/Client/src/app/services/Authentication.ts b/src/Client/src/app/services/Authentication.ts index 4e7c8a9..138ccf7 100644 --- a/src/Client/src/app/services/Authentication.ts +++ b/src/Client/src/app/services/Authentication.ts @@ -35,9 +35,9 @@ export class Authentication{ } Logout(){ - this.http.post( "api/account/logout", {}, { responseType: 'json' } ).subscribe( ); this._user.next( new Account ); this.delUserFromStorage(); + return this.http.post( "api/account/logout", {}, { responseType: 'json' } ); } get isLoggedIn(): boolean { -- 2.52.0 From c57ac574c43fb019c163a3f7ea19361e314e8731 Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Thu, 17 Jul 2025 22:23:17 -0700 Subject: [PATCH 18/26] Layout framework for new job --- .../pages/main/jobs/edit/jobedit.component.ts | 2 +- .../pages/main/jobs/new/jobnew.component.html | 70 +++++++++++++++---- .../pages/main/jobs/new/jobnew.component.ts | 31 ++------ 3 files changed, 63 insertions(+), 40 deletions(-) diff --git a/src/Client/src/app/pages/main/jobs/edit/jobedit.component.ts b/src/Client/src/app/pages/main/jobs/edit/jobedit.component.ts index 33bd400..35075b9 100644 --- a/src/Client/src/app/pages/main/jobs/edit/jobedit.component.ts +++ b/src/Client/src/app/pages/main/jobs/edit/jobedit.component.ts @@ -22,7 +22,7 @@ export class JobEditComponent { public Page: number = 1; constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) { - this.title.setTitle("Jobs | BoredCareers"); + this.title.setTitle("Jobs - edit | BoredCareers"); if (this.Page == 1){ diff --git a/src/Client/src/app/pages/main/jobs/new/jobnew.component.html b/src/Client/src/app/pages/main/jobs/new/jobnew.component.html index 05e4dca..c9e2958 100644 --- a/src/Client/src/app/pages/main/jobs/new/jobnew.component.html +++ b/src/Client/src/app/pages/main/jobs/new/jobnew.component.html @@ -1,16 +1,56 @@ -
-
-

{{ cur.title }}

-

{{ cur.jobType }}

-

Is Remote: {{ cur.remote }}

-

{{ cur.salaryMin }}

-

{{ cur.salaryMax }}

-

{{ cur.city }}

-

{{ cur.stateOrRegion }}

-

{{ cur.country }}

-

{{ cur.postalCode }}

-

{{ cur.description }}

-

Posted: {{ cur.createdTime }}

-

Modified: {{ cur.modifiedTime }}

+
+
+

Title

+
-
\ No newline at end of file +
+

Description

+ +
+
+
+

Postal Code

+ +
+
+

Country

+ +
+
+

State/Region

+ +
+
+

City

+ +
+
+
+
+

Minimum Salary

+ +
+
+

Maximum Salary

+ +
+
+
+

Job Type

+ +
+
+

Remote Position

+ +
+
+ +
+ \ No newline at end of file diff --git a/src/Client/src/app/pages/main/jobs/new/jobnew.component.ts b/src/Client/src/app/pages/main/jobs/new/jobnew.component.ts index 9e7e3b0..f4a8b35 100644 --- a/src/Client/src/app/pages/main/jobs/new/jobnew.component.ts +++ b/src/Client/src/app/pages/main/jobs/new/jobnew.component.ts @@ -15,37 +15,20 @@ import { Authentication } from 'app/services/Authentication'; }) export class JobNewComponent { - public MyJobListings: JobListing[] = []; - public JobListingPage: JobListing[] = []; + public newListing: JobListing = new JobListing(); public ErrorMsg: string = ""; - public Page: number = 1; - - constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) { - this.title.setTitle("Jobs | BoredCareers"); - - if (this.Page == 1){ - - } - - http.get("api/joblisting?PageQuantity=" + 10 + "&Page=" + 1).subscribe({ - next: data => { - this.JobListingPage = data; - }, - error: err => { - this.ErrorMsg = err.error; - } - }); - + constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) { + this.title.setTitle("Jobs - new | BoredCareers"); }; - RemoveJobListing( JobListingID: number ){ - this.http.delete("api/joblisting?JobListingID=" + JobListingID).subscribe({ + PostJobListing(jobListing: JobListing){ + this.http.post("api/joblisting", jobListing).subscribe({ next: data => { - window.location.reload(); + }, error: err => { - alert("Failed to delete the job listing. Try again"); + alert("Failed to create the job listing. Try again"); } }); } -- 2.52.0 From 2916fa977c375d64a59dd5fffa2cb17d868cf850 Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Fri, 18 Jul 2025 15:10:54 -0700 Subject: [PATCH 19/26] deny spyware --- src/Client/angular.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Client/angular.json b/src/Client/angular.json index bf33e66..c593301 100644 --- a/src/Client/angular.json +++ b/src/Client/angular.json @@ -93,5 +93,8 @@ } } } + }, + "cli": { + "analytics": false } } -- 2.52.0 From 935c3e904977e50f3a8c8119dbd8b4d5d6dc139b Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Fri, 18 Jul 2025 15:11:12 -0700 Subject: [PATCH 20/26] Create UI flow for New Job --- .../pages/main/jobs/new/jobnew.component.css | 72 +++++++++ .../pages/main/jobs/new/jobnew.component.html | 144 ++++++++++++------ .../pages/main/jobs/new/jobnew.component.ts | 43 +++++- 3 files changed, 211 insertions(+), 48 deletions(-) diff --git a/src/Client/src/app/pages/main/jobs/new/jobnew.component.css b/src/Client/src/app/pages/main/jobs/new/jobnew.component.css index 9d97a2c..3606281 100644 --- a/src/Client/src/app/pages/main/jobs/new/jobnew.component.css +++ b/src/Client/src/app/pages/main/jobs/new/jobnew.component.css @@ -1,3 +1,75 @@ +.title-text { + width: 100%; + text-align: center; +} + +form { + display: grid; + grid-template-areas: "stack"; + position: relative; + width: 100%; + overflow: hidden; + transition: 0.5s; +} + +.center { + width: 100%; + display: flex; + justify-content: center; +} + +.sub-frame { + position: relative; + grid-area: stack; + transition: 0.5s; + width: 100%; + text-align: center; +} + +.content-frame { + background-color: #00000088; + border-radius: 10px; + padding: 40px; + break-inside: avoid; +} + +.split { + column-count: 2; +} + +.half-frame { + width: 400px; + break-inside: avoid; +} + +.content-frame label { + color: #FFF; +} + +.content-frame textarea { + width: calc(100% - 40px); + margin: 0 20px; + height: 200px; + resize: none; +} + +.content-frame input { + width: calc(50% - 24px); + margin: 0 calc(25% + 10px); + margin-bottom: 20px; + appearance: textfield; +} + +.content-frame input:focus ~ label { + color: green; +} + +.content-frame select { + width: calc(50% - 24px); + margin: 0 calc(25% + 10px); + margin-bottom: 20px; +} + .tile-frame { column-count: 4; column-gap: 20px; diff --git a/src/Client/src/app/pages/main/jobs/new/jobnew.component.html b/src/Client/src/app/pages/main/jobs/new/jobnew.component.html index c9e2958..fd17166 100644 --- a/src/Client/src/app/pages/main/jobs/new/jobnew.component.html +++ b/src/Client/src/app/pages/main/jobs/new/jobnew.component.html @@ -1,56 +1,106 @@ +
+

POST A NEW JOB

+
-
-

Title

- -
-
-

Description

- -
-
-
-

Postal Code

- -
-
-

Country

- -
-
-

State/Region

- -
-
-

City

- + +
+
+
+ + + +
-
-
-

Minimum Salary

- -
-
-

Maximum Salary

- + + +
+
+
+ + + + +
-
-

Job Type

- + + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ + +
+
-
-

Remote Position

- + + +
+
+
+
+ + +
+
+ + +
+ + +
+
-
- + + +
+
+
+
+ + +
+
+ + +
+ + +
+
+
+ + +
+
+
+ + +
+
\ No newline at end of file diff --git a/src/Client/src/app/pages/main/jobs/new/jobnew.component.ts b/src/Client/src/app/pages/main/jobs/new/jobnew.component.ts index f4a8b35..0d8a586 100644 --- a/src/Client/src/app/pages/main/jobs/new/jobnew.component.ts +++ b/src/Client/src/app/pages/main/jobs/new/jobnew.component.ts @@ -1,4 +1,4 @@ -import { Component } from '@angular/core'; +import { Component, ElementRef, QueryList, ViewChildren } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { FormsModule } from '@angular/forms'; import { Router, ActivatedRoute, RouterModule } from '@angular/router'; @@ -15,6 +15,9 @@ import { Authentication } from 'app/services/Authentication'; }) export class JobNewComponent { + @ViewChildren('step') formSteps!: QueryList>; + currentStep: number = 0; + public newListing: JobListing = new JobListing(); public ErrorMsg: string = ""; @@ -22,6 +25,44 @@ export class JobNewComponent { this.title.setTitle("Jobs - new | BoredCareers"); }; + ngAfterViewInit(){ + this.formSteps.forEach((step: ElementRef, i: number) => { + if (i === this.currentStep) { + step.nativeElement.style.left = '0%'; + } else if (i < this.currentStep) { + step.nativeElement.style.left = '-100%'; + } else { + step.nativeElement.style.left = '100%'; + } + }); + } + + nextStep(){ + this.currentStep += 1; + this.formSteps.forEach((step: ElementRef, i: number) => { + if (i === this.currentStep) { + step.nativeElement.style.left = '0%'; + } else if (i < this.currentStep) { + step.nativeElement.style.left = '-100%'; + } else { + step.nativeElement.style.left = '100%'; + } + }); + } + + prevStep(){ + this.currentStep -= 1; + this.formSteps.forEach((step: ElementRef, i: number) => { + if (i === this.currentStep) { + step.nativeElement.style.left = '0%'; + } else if (i < this.currentStep) { + step.nativeElement.style.left = '-100%'; + } else { + step.nativeElement.style.left = '100%'; + } + }); + } + PostJobListing(jobListing: JobListing){ this.http.post("api/joblisting", jobListing).subscribe({ next: data => { -- 2.52.0 From 1ef887166af5094b2a19d80cd7e3c654f82806ad Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Fri, 18 Jul 2025 15:14:39 -0700 Subject: [PATCH 21/26] reorder flow --- .../pages/main/jobs/new/jobnew.component.html | 116 +++++++++--------- 1 file changed, 59 insertions(+), 57 deletions(-) diff --git a/src/Client/src/app/pages/main/jobs/new/jobnew.component.html b/src/Client/src/app/pages/main/jobs/new/jobnew.component.html index fd17166..949fd56 100644 --- a/src/Client/src/app/pages/main/jobs/new/jobnew.component.html +++ b/src/Client/src/app/pages/main/jobs/new/jobnew.component.html @@ -6,69 +6,13 @@
- +
- -
-
-
- - - - -
-
-
- - -
-
-
-
- - -
-
- - -
-
- - -
-
- - -
- - -
-
-
- - -
-
-
-
- - -
-
- - -
- - -
-
-
-
@@ -94,6 +38,64 @@
+ +
+
+

Job Location

+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ + +
+
+
+ + +
+

Salary Range

+
+
+
+ + +
+
+ + +
+ + +
+
+
+ + +
+
+
+ + + + +
+
+
+
-- 2.52.0 From d8762408d4d89aa547be6b3f809a23405f1beb5a Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Fri, 18 Jul 2025 19:55:53 -0700 Subject: [PATCH 22/26] Start work on Company New --- src/Client/src/app/app.routes.ts | 4 + .../connect/companyconnect.component.css | 93 +++++++++++ .../connect/companyconnect.component.html | 147 ++++++++++++++++++ .../connect/companyconnect.component.ts | 77 +++++++++ src/Server/Controllers/CompanyController.cs | 26 +++- 5 files changed, 340 insertions(+), 7 deletions(-) create mode 100644 src/Client/src/app/pages/main/company/connect/companyconnect.component.css create mode 100644 src/Client/src/app/pages/main/company/connect/companyconnect.component.html create mode 100644 src/Client/src/app/pages/main/company/connect/companyconnect.component.ts diff --git a/src/Client/src/app/app.routes.ts b/src/Client/src/app/app.routes.ts index 7fec6b3..9a9b176 100644 --- a/src/Client/src/app/app.routes.ts +++ b/src/Client/src/app/app.routes.ts @@ -14,6 +14,7 @@ import { JobsComponent } from './pages/main/jobs/jobs.component'; import { ResumesComponent } from './pages/main/resumes/resumes.component'; import { JobNewComponent } from './pages/main/jobs/new/jobnew.component'; import { JobEditComponent } from './pages/main/jobs/edit/jobedit.component'; +import { CompanyConnectComponent } from './pages/main/company/connect/companyconnect.component'; export const routes: Routes = [ @@ -26,6 +27,9 @@ export const routes: Routes = [ { path: "jobs/new", component: JobNewComponent }, { path: "jobs/edit", component: JobEditComponent }, + // Company + { path: "company/connect", component: CompanyConnectComponent }, + // Account stuff { path: "account/forgotpassword", component: ForgotPasswordComponent }, { path: "account/resetpassword", component: ResetPasswordComponent }, diff --git a/src/Client/src/app/pages/main/company/connect/companyconnect.component.css b/src/Client/src/app/pages/main/company/connect/companyconnect.component.css new file mode 100644 index 0000000..4203dc9 --- /dev/null +++ b/src/Client/src/app/pages/main/company/connect/companyconnect.component.css @@ -0,0 +1,93 @@ +.title-text { + width: 100%; + text-align: center; +} + +form { + display: grid; + grid-template-areas: "stack"; + position: relative; + width: 100%; + overflow: hidden; + transition: 0.5s; +} + +.center { + width: 100%; + display: grid; + justify-content: center; +} + +.sub-frame { + position: relative; + grid-area: stack; + transition: 0.5s; + width: 100%; + text-align: center; +} + +.content-frame { + background-color: #00000088; + border-radius: 10px; + padding: 40px; + break-inside: avoid; + margin-bottom: 20px; +} + +.footer-frame { + background-color: #00000044; + border-radius: 10px; + padding: 10px; + break-inside: avoid; + margin-bottom: 20px; +} + +.split { + column-count: 2; +} + +.half-frame { + width: 400px; + break-inside: avoid; +} + +.content-frame label { + color: #FFF; +} + +.content-frame textarea { + width: calc(100% - 40px); + margin: 0 20px; + height: 200px; + resize: none; +} + +.content-frame input { + width: calc(50% - 24px); + margin: 0 calc(25% + 10px); + margin-bottom: 20px; + appearance: textfield; +} + +.content-frame input:focus ~ label { + color: green; +} + +.content-frame select { + width: calc(50% - 24px); + margin: 0 calc(25% + 10px); + margin-bottom: 20px; +} + +.tile-frame { + column-count: 4; + column-gap: 20px; + padding: 20px; + width: calc(100% - 40px); +} + +.tile{ + background-color: var(--Mistox-Dark)\); + height: 40px; + break-inside: avoid; +} \ No newline at end of file diff --git a/src/Client/src/app/pages/main/company/connect/companyconnect.component.html b/src/Client/src/app/pages/main/company/connect/companyconnect.component.html new file mode 100644 index 0000000..12111ca --- /dev/null +++ b/src/Client/src/app/pages/main/company/connect/companyconnect.component.html @@ -0,0 +1,147 @@ +
+

Connect To Company

+
+
+ +
+
+
+ + + +
+ +
+
+ + +
+
+
+ + + + +
+ +
+
+ + +
+
+
+ + + + +
+ +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+

Job Location

+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ + +
+
+
+ + +
+
+
+ + + + +
+
+
+ + +
+
+
+ {{ newListing.name }} + +
+
+
+ city: {{ newListing.city }} +
+
+ country: {{ newListing.country }} +
+
+
+
+ state: {{ newListing.stateOrRegion }} +
+
+ postal code: {{ newListing.postalCode }} +
+
+
+ {{ newListing.description }} +
+
+
+ + +
+
+
+
\ No newline at end of file diff --git a/src/Client/src/app/pages/main/company/connect/companyconnect.component.ts b/src/Client/src/app/pages/main/company/connect/companyconnect.component.ts new file mode 100644 index 0000000..2bb7cb7 --- /dev/null +++ b/src/Client/src/app/pages/main/company/connect/companyconnect.component.ts @@ -0,0 +1,77 @@ +import { Component, ElementRef, QueryList, ViewChildren } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { FormsModule } from '@angular/forms'; +import { Router, ActivatedRoute, RouterModule } from '@angular/router'; +import { Title } from '@angular/platform-browser'; +import { CommonModule } from '@angular/common'; +import { Authentication } from 'app/services/Authentication'; +import { Company } from 'app/models/Company'; + +@Component({ + selector: 'main-company-connect', + templateUrl: './companyconnect.component.html', + styleUrls: [ './companyconnect.component.css' ], + imports: [ FormsModule, CommonModule, RouterModule ] +}) +export class CompanyConnectComponent { + + @ViewChildren('step') formSteps!: QueryList>; + currentStep: number = 0; + + public newListing: Company = new Company(); + public ErrorMsg: string = ""; + + constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) { + this.title.setTitle("Company - Connect | BoredCareers"); + }; + + ngAfterViewInit(){ + this.formSteps.forEach((step: ElementRef, i: number) => { + if (i === this.currentStep) { + step.nativeElement.style.left = '0%'; + } else if (i < this.currentStep) { + step.nativeElement.style.left = '-100%'; + } else { + step.nativeElement.style.left = '100%'; + } + }); + } + + nextStep(){ + this.currentStep += 1; + this.formSteps.forEach((step: ElementRef, i: number) => { + if (i === this.currentStep) { + step.nativeElement.style.left = '0%'; + } else if (i < this.currentStep) { + step.nativeElement.style.left = '-100%'; + } else { + step.nativeElement.style.left = '100%'; + } + }); + } + + prevStep(){ + this.currentStep -= 1; + this.formSteps.forEach((step: ElementRef, i: number) => { + if (i === this.currentStep) { + step.nativeElement.style.left = '0%'; + } else if (i < this.currentStep) { + step.nativeElement.style.left = '-100%'; + } else { + step.nativeElement.style.left = '100%'; + } + }); + } + + PostNewCompany(company: Company){ + this.http.post("api/company?newCompany=true", company).subscribe({ + next: data => { + this.router.navigate([""]); + }, + error: err => { + alert("Failed to create the job listing. Err: " + err.error); + } + }); + } + +} \ No newline at end of file diff --git a/src/Server/Controllers/CompanyController.cs b/src/Server/Controllers/CompanyController.cs index cb644a2..2424d44 100644 --- a/src/Server/Controllers/CompanyController.cs +++ b/src/Server/Controllers/CompanyController.cs @@ -17,19 +17,30 @@ namespace BoredCareers.Controllers { if (company != null) { return Ok(company); } + return NotFound("Company doesn't exist"); } - return NotFound(); + return NotFound("Not logged in"); } [HttpPost] - public async Task SetCompany([FromBody] Company company) { + public async Task SetCompany([FromBody] Company company, [FromQuery] bool newCompany = false) { if (isLoggedIn()) { - if (await isLoggedInUserEmployeeOf(company.ID)) { - await _databaseService.SetCompany(company); - return Ok(); + if (newCompany) { + Company? test = await _databaseService.GetCompany(company.ID); + if (test == null) { + await _databaseService.SetCompany(company); + return Ok(); + } + return NotFound("The company already exists"); + } else { + if (await isLoggedInUserEmployeeOf(company.ID)) { + await _databaseService.SetCompany(company); + return Ok(); + } + return NotFound("You are not an employee of company"); } } - return NotFound(); + return NotFound("Not logged in"); } [HttpDelete] @@ -39,8 +50,9 @@ namespace BoredCareers.Controllers { await _databaseService.DeleteCompany(CompanyID); return Ok(); } + return NotFound("You are not an employee of company"); } - return NotFound(); + return NotFound("Not logged in"); } } -- 2.52.0 From ce24ea478d976703c060a2189af900f384e7ea82 Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Fri, 18 Jul 2025 19:56:09 -0700 Subject: [PATCH 23/26] Better verbosity for API --- src/Server/Controllers/JobListingController.cs | 9 ++++++--- src/Server/Controllers/ResumeController.cs | 13 ++++++++----- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/Server/Controllers/JobListingController.cs b/src/Server/Controllers/JobListingController.cs index 3325908..a6c36a6 100644 --- a/src/Server/Controllers/JobListingController.cs +++ b/src/Server/Controllers/JobListingController.cs @@ -16,7 +16,7 @@ namespace BoredCareers.Controllers { if (jobListing != null) { return Ok(jobListing); } - return NotFound(); + return NotFound("Job listing not found"); } [HttpGet] @@ -32,8 +32,9 @@ namespace BoredCareers.Controllers { await _databaseService.SetJobListing(JobListing); return Ok(); } + return NotFound("You are not an employee of company"); } - return NotFound(); + return NotFound("Not logged in"); } [HttpDelete] @@ -45,9 +46,11 @@ namespace BoredCareers.Controllers { await _databaseService.DeleteJobListing(JobListingID); return Ok(); } + return NotFound("You are not an employee of company"); } + return NotFound("Job listing doesn't exist already"); } - return NotFound(); + return NotFound("Not logged in"); } } diff --git a/src/Server/Controllers/ResumeController.cs b/src/Server/Controllers/ResumeController.cs index 65b9099..02ae46a 100644 --- a/src/Server/Controllers/ResumeController.cs +++ b/src/Server/Controllers/ResumeController.cs @@ -17,14 +17,15 @@ namespace BoredCareers.Controllers { if (resume != null) { return Ok(resume); } - }else{ + return NotFound("Unable to find resume"); + } else { if (isLoggedIn()) { int accountID = getLoggedInUserID(); Resume[] resumes = await _databaseService.GetResumes(accountID); return Ok(resumes); } + return NotFound("Not logged in"); } - return NotFound(); } [HttpPost] @@ -35,21 +36,23 @@ namespace BoredCareers.Controllers { await _databaseService.SetResume(resume); return Ok(); } + return NotFound("Resume doesn't exist or you are not the owner"); } - return NotFound(); + return NotFound("Not logged in"); } [HttpDelete] public async Task DeleteResume(int ResumeID) { - if (isLoggedIn()){ + if (isLoggedIn()) { int accountID = getLoggedInUserID(); Resume? resume = await _databaseService.GetResume(ResumeID); if (resume != null && resume.AccountID == accountID) { await _databaseService.DeleteResume(ResumeID); return Ok(); } + return NotFound("Resume doesn't exist or you are not the owner"); } - return NotFound(); + return NotFound("Not logged in"); } } -- 2.52.0 From bb6189e26ecdd157a46893d98e729052f5daad5b Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Fri, 18 Jul 2025 19:56:15 -0700 Subject: [PATCH 24/26] Fix bad SQL --- src/Server/Services/DatabaseService/Company.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Server/Services/DatabaseService/Company.cs b/src/Server/Services/DatabaseService/Company.cs index 2eafd16..26aaa5f 100644 --- a/src/Server/Services/DatabaseService/Company.cs +++ b/src/Server/Services/DatabaseService/Company.cs @@ -60,10 +60,10 @@ namespace BoredCareers.Services.DatabaseService { connection.Open(); string command = @" - INSERT INTO Account + INSERT INTO Company (ID,Name,Email,EmailVerified,WebsiteURL,LogoURL,Phone,PostalCode,Country,StateOrRegion,City,Description) VALUES - (@ID,@Name,@Email,@EmailVerified,@WebsiteURL,@LogoURL,@Phone,@PostalCode,@Country,@StateOrRegion,@City,@Description); + (@ID,@Name,@Email,@EmailVerified,@WebsiteURL,@LogoURL,@Phone,@PostalCode,@Country,@StateOrRegion,@City,@Description) ON DUPLICATE KEY UPDATE Name = @Name, Email = @Email, @@ -73,7 +73,7 @@ namespace BoredCareers.Services.DatabaseService { Phone = @Phone, PostalCode = @PostalCode, Country = @Country, - StateOrRegion = @StateOrRegion; + StateOrRegion = @StateOrRegion, City = @City, Description = @Description; "; -- 2.52.0 From 73ea2ac28401b03be4b4c33c430dcfef63160d98 Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Fri, 18 Jul 2025 19:56:20 -0700 Subject: [PATCH 25/26] Update ToDo --- ToDo.yaml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ToDo.yaml b/ToDo.yaml index 80938c7..ca253bb 100755 --- a/ToDo.yaml +++ b/ToDo.yaml @@ -2,10 +2,17 @@ Server: Emails: Dont follow theme of website + When a company is created: + Send email -> verify ownership of the email + Need to timeout email reset tokens: Client: - + jobs/new: + When remote job is check'd it still asks for location information + Want to add Required skills to help with filtering + Need to fix some UI bugs. + Want to add completed job listing preview at end of carosel database: Add Applied Jobs Table \ No newline at end of file -- 2.52.0 From 81c30460e0e9386fe6cf3269fcaf1d27af2cbcd3 Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Fri, 18 Jul 2025 19:58:17 -0700 Subject: [PATCH 26/26] Fix all bad SQL Get commands --- .../Services/DatabaseService/Employee.cs | 2 +- .../Services/DatabaseService/JobListing.cs | 2 +- .../ResumeParts/SetResumeParts.cs | 20 +++++++++---------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Server/Services/DatabaseService/Employee.cs b/src/Server/Services/DatabaseService/Employee.cs index e317e89..f31261d 100644 --- a/src/Server/Services/DatabaseService/Employee.cs +++ b/src/Server/Services/DatabaseService/Employee.cs @@ -45,7 +45,7 @@ namespace BoredCareers.Services.DatabaseService { INSERT INTO Employee (ID,AccountID,CompanyID) VALUES - (@ID,@AccountID,@CompanyID); + (@ID,@AccountID,@CompanyID) ON DUPLICATE KEY UPDATE AccountID = @AccountID, CompanyID = @CompanyID; diff --git a/src/Server/Services/DatabaseService/JobListing.cs b/src/Server/Services/DatabaseService/JobListing.cs index 384fa84..1b99c8b 100644 --- a/src/Server/Services/DatabaseService/JobListing.cs +++ b/src/Server/Services/DatabaseService/JobListing.cs @@ -127,7 +127,7 @@ namespace BoredCareers.Services.DatabaseService { INSERT INTO JobListing (ID,CompanyID,Title,PostalCode,Country,StateOrRegion,City,SalaryMin,SalaryMax,JobType,Remote,Description,CreatedTime,ModifiedTime,IsDeleted) VALUES - (@ID,@CompanyID,@Title,@PostalCode,@Country,@StateOrRegion,@City,@SalaryMin,@SalaryMax,@JobType,@Remote,@Description,@CreatedTime,@ModifiedTime,@IsDeleted); + (@ID,@CompanyID,@Title,@PostalCode,@Country,@StateOrRegion,@City,@SalaryMin,@SalaryMax,@JobType,@Remote,@Description,@CreatedTime,@ModifiedTime,@IsDeleted) ON DUPLICATE KEY UPDATE CompanyID = @CompanyID, Title = @Title, diff --git a/src/Server/Services/DatabaseService/ResumeParts/SetResumeParts.cs b/src/Server/Services/DatabaseService/ResumeParts/SetResumeParts.cs index 089f385..55ff142 100644 --- a/src/Server/Services/DatabaseService/ResumeParts/SetResumeParts.cs +++ b/src/Server/Services/DatabaseService/ResumeParts/SetResumeParts.cs @@ -9,7 +9,7 @@ namespace BoredCareers.Services.DatabaseService { INSERT INTO Resume (ID,AccountID,Name,Field,Email,PhoneNumber,PostalCode,Country,StateOrRegion,City,IsActive) VALUES - (@ID,@AccountID,@Name,@Field,@Email,@PhoneNumber,@PostalCode,@Country,@StateOrRegion,@City,@IsActive); + (@ID,@AccountID,@Name,@Field,@Email,@PhoneNumber,@PostalCode,@Country,@StateOrRegion,@City,@IsActive) ON DUPLICATE KEY UPDATE AccountID = @AccountID, Name = @Name, @@ -45,7 +45,7 @@ namespace BoredCareers.Services.DatabaseService { INSERT INTO Resume (ID,ResumeID,ResumeExperienceID,JobFunction) VALUES - (@ID,@ResumeID,@ResumeExperienceID,@JobFunction); + (@ID,@ResumeID,@ResumeExperienceID,@JobFunction) ON DUPLICATE KEY UPDATE ResumeID = @ResumeID, ResumeExperienceID = @ResumeExperienceID, @@ -68,7 +68,7 @@ namespace BoredCareers.Services.DatabaseService { INSERT INTO Resume (ID,ResumeID,JobTitle,Company,PostalCode,Country,StateOrRegion,City,DateStarted,StillEmployed,DateEnded) VALUES - (@ID,@ResumeID,@JobTitle,@Company,@PostalCode,@Country,@StateOrRegion,@City,@DateStarted,@StillEmployed,@DateEnded); + (@ID,@ResumeID,@JobTitle,@Company,@PostalCode,@Country,@StateOrRegion,@City,@DateStarted,@StillEmployed,@DateEnded) ON DUPLICATE KEY UPDATE ResumeID = @ResumeID, JobTitle = @JobTitle, @@ -102,7 +102,7 @@ namespace BoredCareers.Services.DatabaseService { INSERT INTO Resume (ID,ResumeID,ResumeMilitaryID,Achievement) VALUES - (@ID,@ResumeID,@ResumeMilitaryID,@Achievement); + (@ID,@ResumeID,@ResumeMilitaryID,@Achievement) ON DUPLICATE KEY UPDATE ResumeID = @ResumeID, ResumeMilitaryID = @ResumeMilitaryID, @@ -126,7 +126,7 @@ namespace BoredCareers.Services.DatabaseService { INSERT INTO Resume (ID,ResumeID,Country,Rank,DateStarted,StillServing,DateEnded) VALUES - (@ID,@ResumeID,@Country,@Rank,@DateStarted,@StillServing,@DateEnded); + (@ID,@ResumeID,@Country,@Rank,@DateStarted,@StillServing,@DateEnded) ON DUPLICATE KEY UPDATE ResumeID = @ResumeID, Country = @Country, @@ -154,7 +154,7 @@ namespace BoredCareers.Services.DatabaseService { INSERT INTO Resume (ID,ResumeID,DegreeType,DegreeField,School,PostalCode,Country,StateOrRegion,City,DateStarted,StillStudying,DateEnded) VALUES - (@ID,@ResumeID,@DegreeType,@DegreeField,@School,@PostalCode,@Country,@StateOrRegion,@City,@DateStarted,@StillStudying,@DateEnded); + (@ID,@ResumeID,@DegreeType,@DegreeField,@School,@PostalCode,@Country,@StateOrRegion,@City,@DateStarted,@StillStudying,@DateEnded) ON DUPLICATE KEY UPDATE ResumeID = @ResumeID, DegreeType = @DegreeType, @@ -193,7 +193,7 @@ namespace BoredCareers.Services.DatabaseService { INSERT INTO Resume (ID,ResumeID,Name,Description) VALUES - (@ID,@ResumeID,@Name,@Description); + (@ID,@ResumeID,@Name,@Description) ON DUPLICATE KEY UPDATE ResumeID = @ResumeID, Name = @Name, @@ -216,7 +216,7 @@ namespace BoredCareers.Services.DatabaseService { INSERT INTO Resume (ID,ResumeID,Language,Proficiency) VALUES - (@ID,@ResumeID,@Language,@Proficiency); + (@ID,@ResumeID,@Language,@Proficiency) ON DUPLICATE KEY UPDATE ResumeID = @ResumeID, Language = @Language, @@ -239,7 +239,7 @@ namespace BoredCareers.Services.DatabaseService { INSERT INTO Resume (ID,ResumeID,Name,VerificationURL,Description) VALUES - (@ID,@ResumeID,@Name,@VerificationURL,@Description); + (@ID,@ResumeID,@Name,@VerificationURL,@Description) ON DUPLICATE KEY UPDATE ResumeID = @ResumeID, Name = @DegreeNameType, @@ -264,7 +264,7 @@ namespace BoredCareers.Services.DatabaseService { INSERT INTO Resume (ID,ResumeID,Name,URL,Description) VALUES - (@ID,@ResumeID,@Name,@URL,@Description); + (@ID,@ResumeID,@Name,@URL,@Description) ON DUPLICATE KEY UPDATE ResumeID = @ResumeID, Name = @Name, -- 2.52.0