Merge pull request 'working' (#27) from working into main
Docker Build and Release Upload / build (push) Successful in 1m28s
Docker Build and Release Upload / build (push) Successful in 1m28s
Reviewed-on: #27
This commit was merged in pull request #27.
This commit is contained in:
@@ -21,6 +21,9 @@ Server:
|
|||||||
Need to update notification email
|
Need to update notification email
|
||||||
Create page to notify cx that their work email has been verified
|
Create page to notify cx that their work email has been verified
|
||||||
|
|
||||||
|
Server.csproj:
|
||||||
|
Find a way to keep all the libraries up to date
|
||||||
|
|
||||||
Client:
|
Client:
|
||||||
jobs/editor:
|
jobs/editor:
|
||||||
Job Listing Skills exists but isn't implimented in the UI
|
Job Listing Skills exists but isn't implimented in the UI
|
||||||
@@ -45,14 +48,14 @@ Client:
|
|||||||
Setup QueryParam's for Edit and New
|
Setup QueryParam's for Edit and New
|
||||||
Edit employees not implimented yet
|
Edit employees not implimented yet
|
||||||
|
|
||||||
|
resume/editor:
|
||||||
|
Not fully tested yet
|
||||||
|
|
||||||
Company:
|
Company:
|
||||||
Need to impliment Add employee
|
Need to impliment Add employee
|
||||||
Need to impliment Remove employee
|
Need to impliment Remove employee
|
||||||
Edit Company -> Dont allow edit of company email due to it being verified
|
Edit Company -> Dont allow edit of company email due to it being verified
|
||||||
|
|
||||||
All:
|
|
||||||
Make sure im using the new NG format for for and if
|
|
||||||
|
|
||||||
|
|
||||||
database:
|
database:
|
||||||
Add Applied Jobs Table
|
Add Applied Jobs Table
|
||||||
@@ -6,6 +6,7 @@ USE `boredcareers`;
|
|||||||
CREATE TABLE IF NOT EXISTS `Resume` (
|
CREATE TABLE IF NOT EXISTS `Resume` (
|
||||||
`ID` int NOT NULL AUTO_INCREMENT,
|
`ID` int NOT NULL AUTO_INCREMENT,
|
||||||
`AccountID` int NOT NULL,
|
`AccountID` int NOT NULL,
|
||||||
|
`Title` varchar(100) NOT NULL,
|
||||||
`Name` varchar(100) NOT NULL,
|
`Name` varchar(100) NOT NULL,
|
||||||
`Field` varchar(100) DEFAULT NULL,
|
`Field` varchar(100) DEFAULT NULL,
|
||||||
`Email` varchar(255) NOT NULL,
|
`Email` varchar(255) NOT NULL,
|
||||||
@@ -47,6 +48,7 @@ CREATE TABLE IF NOT EXISTS `Resume` (
|
|||||||
CREATE TABLE IF NOT EXISTS `ResumeMilitary` (
|
CREATE TABLE IF NOT EXISTS `ResumeMilitary` (
|
||||||
`ID` int NOT NULL AUTO_INCREMENT,
|
`ID` int NOT NULL AUTO_INCREMENT,
|
||||||
`ResumeID` int NOT NULL,
|
`ResumeID` int NOT NULL,
|
||||||
|
`Veteran` boolean DEFAULT 0,
|
||||||
`Country` char(2) NOT NULL,
|
`Country` char(2) NOT NULL,
|
||||||
`Rank` varchar(50) NOT NULL,
|
`Rank` varchar(50) NOT NULL,
|
||||||
`DateStarted` date NOT NULL,
|
`DateStarted` date NOT NULL,
|
||||||
|
|||||||
@@ -1,25 +1,30 @@
|
|||||||
<div class="top-bar">
|
<div class="top-bar">
|
||||||
<div class="top-bar-buttons">
|
<div class="top-bar-buttons">
|
||||||
<a class="nav-button" routerLink="/jobs" routerLinkActive="active">JOB BOARD</a>
|
<a class="nav-button" routerLink="/jobs" routerLinkActive="active">JOB BOARD</a>
|
||||||
|
@if (auth.isLoggedIn){
|
||||||
<a class="nav-button" routerLink="/resumes" routerLinkActive="active">RESUMES</a>
|
<a class="nav-button" routerLink="/resumes" routerLinkActive="active">RESUMES</a>
|
||||||
<a class="nav-button" routerLink="/company" routerLinkActive="active">COMPANIES</a>
|
<a class="nav-button" routerLink="/company" routerLinkActive="active">COMPANIES</a>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
<a class="top-bar-logo" routerLink="">
|
<a class="top-bar-logo" routerLink="">
|
||||||
<img class="top-bar-logo" style="margin: 0;" src="img/logo-full.png" />
|
<img class="top-bar-logo" style="margin: 0;" src="img/logo-full.png" />
|
||||||
</a>
|
</a>
|
||||||
<div *ngIf="auth.isLoggedIn" class="top-bar-buttons flex-right">
|
@if (auth.isLoggedIn){
|
||||||
|
<div class="top-bar-buttons flex-right">
|
||||||
<a class="nav-button nav-button-login" href="https://auth.mistox.com/"><span>{{ auth.loggedInUser.userName.toUpperCase() }}</span></a>
|
<a class="nav-button nav-button-login" href="https://auth.mistox.com/"><span>{{ auth.loggedInUser.userName.toUpperCase() }}</span></a>
|
||||||
<a class="nav-button nav-button-login" href="/api/account/logout"><span>LOGOUT</span></a>
|
<a class="nav-button nav-button-login" href="/api/account/logout"><span>LOGOUT</span></a>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="!auth.isLoggedIn" class="top-bar-buttons flex-right">
|
} @else {
|
||||||
|
<div class="top-bar-buttons flex-right">
|
||||||
<!-- Testing Login -->
|
@if (devMode){
|
||||||
<a *ngIf="devMode" class="nav-button nav-button-login" href="https://auth.mistox.com/account/login?returnURL=http://localhost:5000/"><span>Testing Login</span></a>
|
<a class="nav-button nav-button-login" href="https://auth.mistox.com/account/login?returnURL=http://localhost:5000/"><span>Testing Login</span></a>
|
||||||
<!-- Testing Login -->
|
<a class="nav-button nav-button-login" href="https://auth.mistox.com/account/register?returnURL=http://localhost:5000/"><span>REGISTER</span></a>
|
||||||
|
} @else {
|
||||||
<a class="nav-button nav-button-login" href="https://auth.mistox.com/account/login?returnURL=https://boredcareers.com/"><span>LOGIN</span></a>
|
<a class="nav-button nav-button-login" href="https://auth.mistox.com/account/login?returnURL=https://boredcareers.com/"><span>LOGIN</span></a>
|
||||||
<a class="nav-button nav-button-login" href="https://auth.mistox.com/account/register?returnURL=https://boredcareers.com/"><span>REGISTER</span></a>
|
<a class="nav-button nav-button-login" href="https://auth.mistox.com/account/register?returnURL=https://boredcareers.com/"><span>REGISTER</span></a>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { JobEditorComponent } from './pages/jobs/editor/jobeditor.component';
|
|||||||
import { CompanyEditorComponent } from './pages/company/editor/editor.component';
|
import { CompanyEditorComponent } from './pages/company/editor/editor.component';
|
||||||
import { JobViewerComponent } from './pages/jobs/viewer/jobviewer.component';
|
import { JobViewerComponent } from './pages/jobs/viewer/jobviewer.component';
|
||||||
import { CompanyComponent } from './pages/company/company.component';
|
import { CompanyComponent } from './pages/company/company.component';
|
||||||
|
import { ResumesEditorComponent } from './pages/resumes/editor/editor.component';
|
||||||
|
|
||||||
export const routes: Routes = [
|
export const routes: Routes = [
|
||||||
|
|
||||||
@@ -15,6 +16,7 @@ export const routes: Routes = [
|
|||||||
|
|
||||||
// Resumes
|
// Resumes
|
||||||
{ path: "resumes", component: ResumesComponent },
|
{ path: "resumes", component: ResumesComponent },
|
||||||
|
{ path: "resumes/editor", component: ResumesEditorComponent },
|
||||||
|
|
||||||
// Jobs
|
// Jobs
|
||||||
{ path: "jobs", component: JobsComponent },
|
{ path: "jobs", component: JobsComponent },
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
|
|
||||||
export class Resume {
|
export class Resume {
|
||||||
public id: number | null = null;
|
public id: number | null = null;
|
||||||
public accountID: number = 0;
|
public accountID: number | null = null;
|
||||||
|
|
||||||
|
public title: string = "";
|
||||||
public name: string = "";
|
public name: string = "";
|
||||||
public field: string = "";
|
public field: string = "";
|
||||||
public email: string = "";
|
public email: string = "";
|
||||||
@@ -17,11 +20,13 @@ export class Resume {
|
|||||||
public languages: ResumeLanguage[] = [];
|
public languages: ResumeLanguage[] = [];
|
||||||
public certification: ResumeCertification[] = [];
|
public certification: ResumeCertification[] = [];
|
||||||
public projects: ResumeProject[] = [];
|
public projects: ResumeProject[] = [];
|
||||||
|
public trackUUID: string = crypto.randomUUID();
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ResumeExperience {
|
export class ResumeExperience {
|
||||||
public id: number | null = null;
|
public id: number | null = null;
|
||||||
public resumeID: number = 0;
|
public resumeID: number | null = null;
|
||||||
|
|
||||||
public jobTitle: string = "";
|
public jobTitle: string = "";
|
||||||
public company: string = "";
|
public company: string = "";
|
||||||
public postalCode: string = "";
|
public postalCode: string = "";
|
||||||
@@ -32,37 +37,46 @@ export class ResumeExperience {
|
|||||||
public stillEmployed: boolean = false;
|
public stillEmployed: boolean = false;
|
||||||
public dateEnded: Date = new Date();
|
public dateEnded: Date = new Date();
|
||||||
public experienceBullets: ResumeExperienceBullet[] = [];
|
public experienceBullets: ResumeExperienceBullet[] = [];
|
||||||
|
public trackUUID: string = crypto.randomUUID();
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ResumeExperienceBullet {
|
export class ResumeExperienceBullet {
|
||||||
public id: number | null = null;
|
public id: number | null = null;
|
||||||
public resumeID: number = 0;
|
public resumeID: number | null = null;
|
||||||
public resumeExperienceID: number = 0;
|
public resumeExperienceID: number | null = null;
|
||||||
|
|
||||||
public jobFunction: string = "";
|
public jobFunction: string = "";
|
||||||
|
public trackUUID: string = crypto.randomUUID();
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ResumeMilitary {
|
export class ResumeMilitary {
|
||||||
public id: number | null = null;
|
public id: number | null = null;
|
||||||
public resumeID: number = 0;
|
public resumeID: number | null = null;
|
||||||
|
|
||||||
|
public veteran: boolean = false;
|
||||||
public country: string = "";
|
public country: string = "";
|
||||||
public rank: string = "";
|
public rank: string = "";
|
||||||
public dateStarted: Date = new Date();
|
public dateStarted: Date = new Date();
|
||||||
public stillServing: boolean = false;
|
public stillServing: boolean = false;
|
||||||
public dateEnded: Date = new Date();
|
public dateEnded: Date = new Date();
|
||||||
public millitaryBullets: ResumeMilitaryBullet[] = [];
|
public millitaryBullets: ResumeMilitaryBullet[] = [];
|
||||||
|
public trackUUID: string = crypto.randomUUID();
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ResumeMilitaryBullet {
|
export class ResumeMilitaryBullet {
|
||||||
public id: number | null = null;
|
public id: number | null = null;
|
||||||
public resumeID: number = 0;
|
public resumeID: number | null = null;
|
||||||
public resumeMilitaryID: number = 0;
|
public resumeMilitaryID: number | null = null;
|
||||||
|
|
||||||
public achievement: string = "";
|
public achievement: string = "";
|
||||||
public description: string = "";
|
public description: string = "";
|
||||||
|
public trackUUID: string = crypto.randomUUID();
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ResumeEducation {
|
export class ResumeEducation {
|
||||||
public id: number | null = null;
|
public id: number | null = null;
|
||||||
public resumeID: number = 0;
|
public resumeID: number | null = null;
|
||||||
|
|
||||||
public degreeType: string = "";
|
public degreeType: string = "";
|
||||||
public degreeField: string = "";
|
public degreeField: string = "";
|
||||||
public school: string = "";
|
public school: string = "";
|
||||||
@@ -73,34 +87,43 @@ export class ResumeEducation {
|
|||||||
public dateStarted: Date = new Date();
|
public dateStarted: Date = new Date();
|
||||||
public stillStudying: boolean = false;
|
public stillStudying: boolean = false;
|
||||||
public dateEnded: Date = new Date();
|
public dateEnded: Date = new Date();
|
||||||
|
public trackUUID: string = crypto.randomUUID();
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ResumeSkill {
|
export class ResumeSkill {
|
||||||
public id: number | null = null;
|
public id: number | null = null;
|
||||||
public resumeID: number = 0;
|
public resumeID: number | null = null;
|
||||||
|
|
||||||
public name: string = "";
|
public name: string = "";
|
||||||
public description: string = "";
|
public description: string = "";
|
||||||
|
public trackUUID: string = crypto.randomUUID();
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ResumeLanguage {
|
export class ResumeLanguage {
|
||||||
public id: number | null = null;
|
public id: number | null = null;
|
||||||
public resumeID: number = 0;
|
public resumeID: number | null = null;
|
||||||
|
|
||||||
public language: string = "";
|
public language: string = "";
|
||||||
public proficiency: string = "";
|
public proficiency: string = "";
|
||||||
|
public trackUUID: string = crypto.randomUUID();
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ResumeCertification {
|
export class ResumeCertification {
|
||||||
public id: number | null = null;
|
public id: number | null = null;
|
||||||
public resumeID: number = 0;
|
public resumeID: number | null = null;
|
||||||
|
|
||||||
public name: string = "";
|
public name: string = "";
|
||||||
public verificationURL: string = "";
|
public verificationURL: string = "";
|
||||||
public description: string = "";
|
public description: string = "";
|
||||||
|
public trackUUID: string = crypto.randomUUID();
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ResumeProject {
|
export class ResumeProject {
|
||||||
public id: number | null = null;
|
public id: number | null = null;
|
||||||
public resumeID: number = 0;
|
public resumeID: number | null = null;
|
||||||
|
|
||||||
public name: string = "";
|
public name: string = "";
|
||||||
public url: string = "";
|
public url: string = "";
|
||||||
public description: string = "";
|
public description: string = "";
|
||||||
|
public trackUUID: string = crypto.randomUUID();
|
||||||
}
|
}
|
||||||
@@ -28,6 +28,11 @@ export class CompanyComponent {
|
|||||||
|
|
||||||
constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) {
|
constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) {
|
||||||
this.title.setTitle("Companies | BoredCareers");
|
this.title.setTitle("Companies | BoredCareers");
|
||||||
|
|
||||||
|
if (!auth.isLoggedIn){
|
||||||
|
router.navigate(["/"]);
|
||||||
|
}
|
||||||
|
|
||||||
http.get<Employee[]>("api/employee/").subscribe({
|
http.get<Employee[]>("api/employee/").subscribe({
|
||||||
next: data => {
|
next: data => {
|
||||||
this.Employers = data;
|
this.Employers = data;
|
||||||
|
|||||||
@@ -25,6 +25,10 @@ export class CompanyEditorComponent {
|
|||||||
constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) {
|
constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) {
|
||||||
this.title.setTitle("Company - Editor | BoredCareers");
|
this.title.setTitle("Company - Editor | BoredCareers");
|
||||||
|
|
||||||
|
if (!auth.isLoggedIn){
|
||||||
|
router.navigate(["/"]);
|
||||||
|
}
|
||||||
|
|
||||||
// Query param CompanyID -> Edit
|
// Query param CompanyID -> Edit
|
||||||
// Query param null -> New
|
// Query param null -> New
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -27,6 +27,10 @@ export class JobEditorComponent {
|
|||||||
constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) {
|
constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) {
|
||||||
this.title.setTitle("Jobs - Editor | BoredCareers");
|
this.title.setTitle("Jobs - Editor | BoredCareers");
|
||||||
|
|
||||||
|
if (!auth.isLoggedIn){
|
||||||
|
router.navigate(["/"]);
|
||||||
|
}
|
||||||
|
|
||||||
this.route.queryParams.subscribe(params => {
|
this.route.queryParams.subscribe(params => {
|
||||||
const CompanyID = params['CompanyID'] ? +params['CompanyID'] : null;
|
const CompanyID = params['CompanyID'] ? +params['CompanyID'] : null;
|
||||||
const JobID = params['JobID'] ? +params['JobID'] : null;
|
const JobID = params['JobID'] ? +params['JobID'] : null;
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
.resume-section {
|
||||||
|
background-color: #DDDDDD;
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resume-sub-section {
|
||||||
|
border: 1px solid #666666;
|
||||||
|
margin: 5px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
<form (ngSubmit)="SubmitForm(resume)">
|
||||||
|
|
||||||
|
<!-- Resume Header -->
|
||||||
|
<div class="resume-section">
|
||||||
|
<input name="resumetitle" [(ngModel)]="resume.title" type="text" placeholder="Resume 1" />
|
||||||
|
<input name="resumename" [(ngModel)]="resume.name" type="text" placeholder="John Doe" />
|
||||||
|
<input name="resumefield" [(ngModel)]="resume.field" type="text" placeholder="Data Scientist" />
|
||||||
|
<input name="resumeemail" [(ngModel)]="resume.email" type="email" placeholder="no-reply@mistox.com" />
|
||||||
|
<input name="resumephoneNumber" [(ngModel)]="resume.phoneNumber" type="tel" placeholder="+1 800-000-0000" />
|
||||||
|
<input name="resumepostalCode" [(ngModel)]="resume.postalCode" type="text" placeholder="92020" />
|
||||||
|
<input name="resumestateOrRegion" [(ngModel)]="resume.stateOrRegion" type="text" placeholder="CA" />
|
||||||
|
<input name="resumecity" [(ngModel)]="resume.city" type="text" placeholder="San Diego" />
|
||||||
|
<h1>Public: </h1><input name="active" [(ngModel)]="resume.isActive" type="checkbox" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Experience -->
|
||||||
|
<div class="resume-section">
|
||||||
|
<button type="button" (click)="addExperience()">ADD Experience</button>
|
||||||
|
@for(experience of resume.experience; track experience.trackUUID ){
|
||||||
|
<div class="resume-sub-section">
|
||||||
|
<input name="experiencejobTitle" [(ngModel)]="experience.jobTitle" type="text" placeholder="Data Entry Clerk" />
|
||||||
|
<input name="experiencecompany" [(ngModel)]="experience.company" type="text" placeholder="San Diego Gas Electric" />
|
||||||
|
<input name="experiencepostalCode" [(ngModel)]="experience.postalCode" type="text" placeholder="92020" />
|
||||||
|
<input name="experiencecountry" [(ngModel)]="experience.country" type="text" placeholder="US" />
|
||||||
|
<input name="experiencestateOrRegion" [(ngModel)]="experience.stateOrRegion" type="text" placeholder="CA" />
|
||||||
|
<input name="experiencecity" [(ngModel)]="experience.city" type="text" placeholder="San Diego" />
|
||||||
|
<input name="experiencedateStarted" [(ngModel)]="experience.dateStarted" type="date" />
|
||||||
|
<input name="experiencestillEmployed" [(ngModel)]="experience.stillEmployed" type="checkbox" />
|
||||||
|
@if(!experience.stillEmployed){
|
||||||
|
<input name="experiencedateEnded" [(ngModel)]="experience.dateEnded" type="date" />
|
||||||
|
}
|
||||||
|
<button type="button" (click)="addJobFunction(experience)">Add jobFunction</button>
|
||||||
|
@for(bullet of experience.experienceBullets; track bullet.trackUUID){
|
||||||
|
<div>
|
||||||
|
<textarea name="bulletjobFunction" [(ngModel)]="bullet.jobFunction" placeholder="Processed database transactions" ></textarea>
|
||||||
|
<button type="button" (click)="delJobFunction(experience, bullet)">DEL jobFunction</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<button type="button" (click)="delExperience(experience)">DEL Experience</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Military -->
|
||||||
|
<div class="resume-section">
|
||||||
|
<h1>Is Veteran: </h1><input name="veteran" [(ngModel)]="resume.military.veteran" type="checkbox" />
|
||||||
|
@if(resume.military.veteran){
|
||||||
|
<input name="militarycountry" [(ngModel)]="resume.military.country" type="text" placeholder="US" />
|
||||||
|
<input name="militaryrank" [(ngModel)]="resume.military.rank" type="text" placeholder="PVT" />
|
||||||
|
<input name="militarydateStarted" [(ngModel)]="resume.military.dateStarted" type="date" />
|
||||||
|
<h1>Still Serving: </h1><input name="stillServing" [(ngModel)]="resume.military.stillServing" type="checkbox" />
|
||||||
|
@if (!resume.military.stillServing){
|
||||||
|
<input name="dateEnded" [(ngModel)]="resume.military.dateEnded" type="date" />
|
||||||
|
}
|
||||||
|
<button type="button" (click)="addMillitaryBullet()">Add Millitary Task</button>
|
||||||
|
@for(military of resume.military.millitaryBullets; track military.trackUUID ){
|
||||||
|
<div>
|
||||||
|
<input name="militaryachievement" [(ngModel)]="military.achievement" type="text" placeholder="Deployed Kuwait" />
|
||||||
|
<textarea name="militarydescription" [(ngModel)]="military.description" placeholder="Delivered goods line-hall" ></textarea>
|
||||||
|
<button type="button" (click)="delMillitaryBullet(military)">DEL Military Task</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Education -->
|
||||||
|
<div class="resume-section">
|
||||||
|
<button type="button" (click)="addEducation()">ADD Education</button>
|
||||||
|
@for(education of resume.education; track education.trackUUID){
|
||||||
|
<div>
|
||||||
|
<input name="educationdegreeType" [(ngModel)]="education.degreeType" type="text" placeholder="Masters" />
|
||||||
|
<input name="educationdegreeField" [(ngModel)]="education.degreeField" type="text" placeholder="Computer Science" />
|
||||||
|
<input name="educationschool" [(ngModel)]="education.school" type="text" placeholder="WGU" />
|
||||||
|
<input name="educationpostalCode" [(ngModel)]="education.postalCode" type="text" placeholder="84107" />
|
||||||
|
<input name="educationcountry" [(ngModel)]="education.country" type="text" placeholder="US" />
|
||||||
|
<input name="educationstateOrRegion" [(ngModel)]="education.stateOrRegion" type="text" placeholder="UT" />
|
||||||
|
<input name="educationcity" [(ngModel)]="education.city" type="text" placeholder="Salt Lake City" />
|
||||||
|
<input name="educationdateStarted" [(ngModel)]="education.dateStarted" type="date" />
|
||||||
|
<input name="educationstillStudying" [(ngModel)]="education.stillStudying" type="checkbox" />
|
||||||
|
@if (!education.stillStudying){
|
||||||
|
<input name="educationdateEnded" [(ngModel)]="education.dateEnded" type="date" />
|
||||||
|
}
|
||||||
|
<button type="button" (click)="delEducation(education)">DEL Education</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Skill -->
|
||||||
|
<div class="resume-section">
|
||||||
|
<button type="button" (click)="addSkill()">ADD Skill</button>
|
||||||
|
@for(skill of resume.skills; track skill.trackUUID){
|
||||||
|
<div>
|
||||||
|
<input name="skillname" [(ngModel)]="skill.name" type="text" placeholder="Angular JS" />
|
||||||
|
<textarea name="skilldescription" [(ngModel)]="skill.description" placeholder="Built this entire website using Angular JS"></textarea>
|
||||||
|
<button type="button" (click)="delSkill(skill)">DEL Skill</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Language -->
|
||||||
|
<div class="resume-section">
|
||||||
|
<button type="button" (click)="addLanguage()">ADD Language</button>
|
||||||
|
@for(language of resume.languages; track language.trackUUID){
|
||||||
|
<div>
|
||||||
|
<input name="languagelanguage" [(ngModel)]="language.language" type="text" placeholder="Spanish" />
|
||||||
|
<input name="languageproficiency" [(ngModel)]="language.proficiency" type="text" placeholder="casual speaking" />
|
||||||
|
<button type="button" (click)="delLanguage(language)">DEL Language</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Certification -->
|
||||||
|
<div class="resume-section">
|
||||||
|
<button type="button" (click)="addCert()">ADD Certification</button>
|
||||||
|
@for(cert of resume.certification; track cert.trackUUID){
|
||||||
|
<div>
|
||||||
|
<input name="certname" [(ngModel)]="cert.name" type="text" placeholder="Comptia A+" />
|
||||||
|
<input name="certverificationURL" [(ngModel)]="cert.verificationURL" type="text" placeholder="https://certmaster.com/certid" />
|
||||||
|
<textarea name="certdescription" [(ngModel)]="cert.description" placeholder="Into to information technology"></textarea>
|
||||||
|
<button type="button" (click)="delCert(cert)">DEL Certification</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Project -->
|
||||||
|
<div class="resume-section">
|
||||||
|
<button type="button" (click)="addProject()">ADD Project</button>
|
||||||
|
@for(proj of resume.projects; track proj.trackUUID){
|
||||||
|
<div>
|
||||||
|
<input name="projname" [(ngModel)]="proj.name" type="text" placeholder="boredcareers" />
|
||||||
|
<input name="projurl" [(ngModel)]="proj.url" type="text" placeholder="mistox.com" />
|
||||||
|
<textarea name="projdescription" [(ngModel)]="proj.description" placeholder="the project that your currently viewing"></textarea>
|
||||||
|
<button type="button" (click)="delProject(proj)">DEL Project</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if (isNewResume){
|
||||||
|
<button type="submit">CREATE NEW RESUME</button>
|
||||||
|
} @else {
|
||||||
|
<button type="submit">UPDATE RESUME</button>
|
||||||
|
}
|
||||||
|
|
||||||
|
</form>
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
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 { Resume, ResumeCertification, ResumeEducation, ResumeExperience, ResumeExperienceBullet, ResumeLanguage, ResumeMilitaryBullet, ResumeProject, ResumeSkill } from 'app/models/Resume';
|
||||||
|
import { Authentication } from 'app/services/Authentication';
|
||||||
|
import { HomeComponent } from "app/pages/home/home.component";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'main-resume-editor',
|
||||||
|
templateUrl: './editor.component.html',
|
||||||
|
styleUrls: [ './editor.component.css' ],
|
||||||
|
imports: [FormsModule, CommonModule, RouterModule]
|
||||||
|
})
|
||||||
|
export class ResumesEditorComponent {
|
||||||
|
|
||||||
|
public resume: Resume = new Resume;
|
||||||
|
public isNewResume: boolean = true;
|
||||||
|
|
||||||
|
public ErrorMsg: string = "";
|
||||||
|
|
||||||
|
constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) {
|
||||||
|
this.title.setTitle("Resume - Editor | BoredCareers");
|
||||||
|
if (!auth.isLoggedIn){
|
||||||
|
router.navigate(["/"]);
|
||||||
|
}
|
||||||
|
this.route.queryParams.subscribe(params => {
|
||||||
|
|
||||||
|
const ResumeID = params['ResumeID'] ? +params['ResumeID'] : null;
|
||||||
|
if (ResumeID !== null){
|
||||||
|
this.http.get<Resume>("api/resume?ResumeID=" + ResumeID).subscribe({
|
||||||
|
next: data => {
|
||||||
|
this.resume = data;
|
||||||
|
this.isNewResume = false;
|
||||||
|
},
|
||||||
|
error: err => {
|
||||||
|
this.ErrorMsg = err.error;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
SubmitForm(resume: Resume){
|
||||||
|
resume.accountID = this.auth.loggedInUser.id;
|
||||||
|
this.http.post("api/resume", resume).subscribe({
|
||||||
|
next: data => {
|
||||||
|
this.router.navigate(["/"]);
|
||||||
|
},
|
||||||
|
error: err => {
|
||||||
|
this.ErrorMsg = err.error;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
addExperience(){
|
||||||
|
this.resume.experience.push( new ResumeExperience );
|
||||||
|
}
|
||||||
|
delExperience(self: ResumeExperience){
|
||||||
|
for(let i=0; i<this.resume.experience.length; i++){
|
||||||
|
let cur = this.resume.experience[i];
|
||||||
|
if (cur.trackUUID === self.trackUUID){
|
||||||
|
this.resume.experience.splice( i, 1 );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addJobFunction(self: ResumeExperience){
|
||||||
|
self.experienceBullets.push( new ResumeExperienceBullet );
|
||||||
|
}
|
||||||
|
delJobFunction(self: ResumeExperience, me: ResumeExperienceBullet){
|
||||||
|
for(let i=0; i<self.experienceBullets.length; i++){
|
||||||
|
let cur = self.experienceBullets[i];
|
||||||
|
if (cur.trackUUID === me.trackUUID){
|
||||||
|
self.experienceBullets.splice( i, 1 );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addMillitaryBullet(){
|
||||||
|
this.resume.military.millitaryBullets.push( new ResumeMilitaryBullet );
|
||||||
|
}
|
||||||
|
delMillitaryBullet(self: ResumeMilitaryBullet){
|
||||||
|
for(let i=0; i<this.resume.military.millitaryBullets.length; i++){
|
||||||
|
let cur = this.resume.military.millitaryBullets[i];
|
||||||
|
if (cur.trackUUID === self.trackUUID){
|
||||||
|
this.resume.military.millitaryBullets.splice( i, 1 );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addEducation(){
|
||||||
|
this.resume.education.push( new ResumeEducation );
|
||||||
|
}
|
||||||
|
delEducation(self: ResumeEducation){
|
||||||
|
for(let i=0; i<this.resume.education.length; i++){
|
||||||
|
let cur = this.resume.education[i];
|
||||||
|
if (cur.trackUUID === self.trackUUID){
|
||||||
|
this.resume.education.splice( i, 1 );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addSkill(){
|
||||||
|
this.resume.skills.push( new ResumeSkill );
|
||||||
|
}
|
||||||
|
delSkill(self: ResumeSkill){
|
||||||
|
for(let i=0; i<this.resume.skills.length; i++){
|
||||||
|
let cur = this.resume.skills[i];
|
||||||
|
if (cur.trackUUID === self.trackUUID){
|
||||||
|
this.resume.skills.splice( i, 1 );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addLanguage(){
|
||||||
|
this.resume.languages.push( new ResumeLanguage );
|
||||||
|
}
|
||||||
|
delLanguage(self: ResumeLanguage){
|
||||||
|
for(let i=0; i<this.resume.languages.length; i++){
|
||||||
|
let cur = this.resume.languages[i];
|
||||||
|
if (cur.trackUUID === self.trackUUID){
|
||||||
|
this.resume.languages.splice( i, 1 );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addCert(){
|
||||||
|
this.resume.certification.push( new ResumeCertification );
|
||||||
|
}
|
||||||
|
delCert(self: ResumeCertification){
|
||||||
|
for(let i=0; i<this.resume.certification.length; i++){
|
||||||
|
let cur = this.resume.certification[i];
|
||||||
|
if (cur.trackUUID === self.trackUUID){
|
||||||
|
this.resume.certification.splice( i, 1 );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addProject(){
|
||||||
|
this.resume.projects.push( new ResumeProject );
|
||||||
|
}
|
||||||
|
delProject(self: ResumeProject){
|
||||||
|
for(let i=0; i<this.resume.projects.length; i++){
|
||||||
|
let cur = this.resume.projects[i];
|
||||||
|
if (cur.trackUUID === self.trackUUID){
|
||||||
|
this.resume.projects.splice( i, 1 );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,6 +1,11 @@
|
|||||||
<!-- My Resumes -->
|
<div class="top-bar">
|
||||||
@if (auth.isLoggedIn){
|
@for(resume of myResumes; track myResumes.length){
|
||||||
<div class="jobs-frame">
|
<button (click)="changeSelectedResume(5)">{{ resume.title }}</button>
|
||||||
|
|
||||||
</div>
|
|
||||||
}
|
}
|
||||||
|
<button routerLink="/resumes/editor" >NEW RESUME</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- My Resumes -->
|
||||||
|
<div class="jobs-frame">
|
||||||
|
|
||||||
|
</div>
|
||||||
@@ -15,14 +15,19 @@ import { Authentication } from 'app/services/Authentication';
|
|||||||
})
|
})
|
||||||
export class ResumesComponent {
|
export class ResumesComponent {
|
||||||
|
|
||||||
public ResumePage: Resume[] = [];
|
public myResumes: Resume[] = [];
|
||||||
|
public currentResume: Resume | null = null;
|
||||||
|
|
||||||
constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) {
|
constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) {
|
||||||
this.title.setTitle("Resumes | BoredCareers");
|
this.title.setTitle("Resumes | BoredCareers");
|
||||||
|
|
||||||
|
if (!auth.isLoggedIn){
|
||||||
|
router.navigate(["/"]);
|
||||||
|
}
|
||||||
|
|
||||||
this.http.get<Resume[]>("api/resume").subscribe({
|
this.http.get<Resume[]>("api/resume").subscribe({
|
||||||
next: data => {
|
next: data => {
|
||||||
this.ResumePage = data;
|
this.myResumes = data;
|
||||||
},
|
},
|
||||||
error: err => {
|
error: err => {
|
||||||
console.log("Error fetching resumes: " + err.error);
|
console.log("Error fetching resumes: " + err.error);
|
||||||
@@ -30,4 +35,15 @@ export class ResumesComponent {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
changeSelectedResume(ResumeID: number){
|
||||||
|
this.http.get<Resume>("api/resume?ResumeID=" + ResumeID).subscribe({
|
||||||
|
next: data => {
|
||||||
|
this.currentResume = data;
|
||||||
|
},
|
||||||
|
error: err => {
|
||||||
|
console.log("Error fetching resume ID: " + err.error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Injectable } from "@angular/core";
|
import { Injectable } from "@angular/core";
|
||||||
import { Account } from "../models/Account";
|
import { Account } from "../models/Account";
|
||||||
import { BehaviorSubject, Observable } from "rxjs";
|
import { BehaviorSubject, Observable } from "rxjs";
|
||||||
import { HttpClient, HttpHeaders, HttpParams } from "@angular/common/http";
|
import { HttpClient } from "@angular/common/http";
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class Authentication{
|
export class Authentication{
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ namespace BoredCareers.Entities {
|
|||||||
public class Resume {
|
public class Resume {
|
||||||
public int? ID { get; set; } // PK
|
public int? ID { get; set; } // PK
|
||||||
public int AccountID { get; set; } // FK
|
public int AccountID { get; set; } // FK
|
||||||
|
public string Title { get; set; } = "";
|
||||||
public string Name { get; set; } = "";
|
public string Name { get; set; } = "";
|
||||||
public string Field { get; set; } = "";
|
public string Field { get; set; } = "";
|
||||||
public string Email { get; set; } = "";
|
public string Email { get; set; } = "";
|
||||||
@@ -45,6 +46,7 @@ namespace BoredCareers.Entities {
|
|||||||
public class ResumeMilitary {
|
public class ResumeMilitary {
|
||||||
public int? ID { get; set; } // PK
|
public int? ID { get; set; } // PK
|
||||||
public int ResumeID { get; set; } // FK
|
public int ResumeID { get; set; } // FK
|
||||||
|
public bool Veteran { get; set; } = false;
|
||||||
public string Country { get; set; } = ""; // 2 Letter Country Code
|
public string Country { get; set; } = ""; // 2 Letter Country Code
|
||||||
public string Rank { get; set; } = "";
|
public string Rank { get; set; } = "";
|
||||||
public DateTime DateStarted { get; set; } = new DateTime();
|
public DateTime DateStarted { get; set; } = new DateTime();
|
||||||
|
|||||||
@@ -175,6 +175,7 @@ builder.Services.AddRateLimiter(options => {
|
|||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
|
||||||
builder.Services.AddHostedService<JobCleanupService>();
|
builder.Services.AddHostedService<JobCleanupService>();
|
||||||
|
ResumeService.init();
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
///// ASPNET Core Function /////
|
///// ASPNET Core Function /////
|
||||||
|
|||||||
@@ -8,15 +8,18 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
|
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="9.0.3" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="9.0.3" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="9.0.3" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="9.0.3" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.3" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.3" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.WebApiCompatShim" Version="2.3.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.WebApiCompatShim" Version="2.3.0" />
|
||||||
<PackageReference Include="MySql.Data" Version="9.2.0" />
|
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
|
||||||
<PackageReference Include="Stripe.net" Version="48.2.0" />
|
<PackageReference Include="Stripe.net" Version="48.2.0" />
|
||||||
|
<PackageReference Include="MySql.Data" Version="9.2.0" />
|
||||||
|
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
||||||
|
<PackageReference Include="HtmlSanitizer" Version="9.0.886" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ namespace BoredCareers.Services.DatabaseService {
|
|||||||
|
|
||||||
int _id = reader.GetInt32("ID");
|
int _id = reader.GetInt32("ID");
|
||||||
int _accountid = reader.GetInt32("AccountID");
|
int _accountid = reader.GetInt32("AccountID");
|
||||||
|
string _title = reader.GetString("Title");
|
||||||
string _name = reader.GetString("Name");
|
string _name = reader.GetString("Name");
|
||||||
string _field = reader.GetString("Field");
|
string _field = reader.GetString("Field");
|
||||||
string _email = reader.GetString("Email");
|
string _email = reader.GetString("Email");
|
||||||
@@ -40,6 +41,7 @@ namespace BoredCareers.Services.DatabaseService {
|
|||||||
resumes.Add( new Resume() {
|
resumes.Add( new Resume() {
|
||||||
ID = _id,
|
ID = _id,
|
||||||
AccountID = _accountid,
|
AccountID = _accountid,
|
||||||
|
Title = _title,
|
||||||
Name = _name,
|
Name = _name,
|
||||||
Field = _field,
|
Field = _field,
|
||||||
Email = _email,
|
Email = _email,
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ namespace BoredCareers.Services.DatabaseService {
|
|||||||
if (reader == null) { break; }
|
if (reader == null) { break; }
|
||||||
int _id = reader.GetInt32("ID");
|
int _id = reader.GetInt32("ID");
|
||||||
int _accountid = reader.GetInt32("AccountID");
|
int _accountid = reader.GetInt32("AccountID");
|
||||||
|
string _title = reader.GetString("Title");
|
||||||
string _name = reader.GetString("Name");
|
string _name = reader.GetString("Name");
|
||||||
string _field = reader.GetString("Field");
|
string _field = reader.GetString("Field");
|
||||||
string _email = reader.GetString("Email");
|
string _email = reader.GetString("Email");
|
||||||
@@ -22,6 +23,7 @@ namespace BoredCareers.Services.DatabaseService {
|
|||||||
return new Resume() {
|
return new Resume() {
|
||||||
ID = _id,
|
ID = _id,
|
||||||
AccountID = _accountid,
|
AccountID = _accountid,
|
||||||
|
Title = _title,
|
||||||
Name = _name,
|
Name = _name,
|
||||||
Field = _field,
|
Field = _field,
|
||||||
Email = _email,
|
Email = _email,
|
||||||
@@ -112,6 +114,7 @@ namespace BoredCareers.Services.DatabaseService {
|
|||||||
if (reader == null) { break; }
|
if (reader == null) { break; }
|
||||||
int _id = reader.GetInt32("ID");
|
int _id = reader.GetInt32("ID");
|
||||||
int _resumeid = reader.GetInt32("ResumeID");
|
int _resumeid = reader.GetInt32("ResumeID");
|
||||||
|
bool _veteran = reader.GetBoolean("Veteran");
|
||||||
string _country = reader.GetString("Country");
|
string _country = reader.GetString("Country");
|
||||||
string _rank = reader.GetString("Rank");
|
string _rank = reader.GetString("Rank");
|
||||||
DateTime _datestarted = reader.GetDateTime("DateStarted");
|
DateTime _datestarted = reader.GetDateTime("DateStarted");
|
||||||
@@ -120,6 +123,7 @@ namespace BoredCareers.Services.DatabaseService {
|
|||||||
military = new ResumeMilitary() {
|
military = new ResumeMilitary() {
|
||||||
ID = _id,
|
ID = _id,
|
||||||
ResumeID = _resumeid,
|
ResumeID = _resumeid,
|
||||||
|
Veteran = _veteran,
|
||||||
Country = _country,
|
Country = _country,
|
||||||
Rank = _rank,
|
Rank = _rank,
|
||||||
DateStarted = _datestarted,
|
DateStarted = _datestarted,
|
||||||
|
|||||||
@@ -7,11 +7,12 @@ namespace BoredCareers.Services.DatabaseService {
|
|||||||
public async Task SetResume(MySqlConnection connection, Resume resume) {
|
public async Task SetResume(MySqlConnection connection, Resume resume) {
|
||||||
string command = @"
|
string command = @"
|
||||||
INSERT INTO Resume
|
INSERT INTO Resume
|
||||||
(ID,AccountID,Name,Field,Email,PhoneNumber,PostalCode,Country,StateOrRegion,City,IsActive)
|
(ID,AccountID,Title,Name,Field,Email,PhoneNumber,PostalCode,Country,StateOrRegion,City,IsActive)
|
||||||
VALUES
|
VALUES
|
||||||
(@ID,@AccountID,@Name,@Field,@Email,@PhoneNumber,@PostalCode,@Country,@StateOrRegion,@City,@IsActive)
|
(@ID,@AccountID,@Title,@Name,@Field,@Email,@PhoneNumber,@PostalCode,@Country,@StateOrRegion,@City,@IsActive)
|
||||||
ON DUPLICATE KEY UPDATE
|
ON DUPLICATE KEY UPDATE
|
||||||
AccountID = @AccountID,
|
AccountID = @AccountID,
|
||||||
|
Title = @Title,
|
||||||
Name = @Name,
|
Name = @Name,
|
||||||
Field = @Field,
|
Field = @Field,
|
||||||
Email = @Email,
|
Email = @Email,
|
||||||
@@ -26,6 +27,7 @@ namespace BoredCareers.Services.DatabaseService {
|
|||||||
MySqlCommand cmd = new MySqlCommand(command, connection);
|
MySqlCommand cmd = new MySqlCommand(command, connection);
|
||||||
cmd.Parameters.AddWithValue("@ID", resume.ID);
|
cmd.Parameters.AddWithValue("@ID", resume.ID);
|
||||||
cmd.Parameters.AddWithValue("@AccountID", resume.AccountID);
|
cmd.Parameters.AddWithValue("@AccountID", resume.AccountID);
|
||||||
|
cmd.Parameters.AddWithValue("@Title", resume.Title);
|
||||||
cmd.Parameters.AddWithValue("@Name", resume.Name);
|
cmd.Parameters.AddWithValue("@Name", resume.Name);
|
||||||
cmd.Parameters.AddWithValue("@Field", resume.Field);
|
cmd.Parameters.AddWithValue("@Field", resume.Field);
|
||||||
cmd.Parameters.AddWithValue("@Email", resume.Email);
|
cmd.Parameters.AddWithValue("@Email", resume.Email);
|
||||||
@@ -124,11 +126,12 @@ namespace BoredCareers.Services.DatabaseService {
|
|||||||
public async Task SetResumeMilitary(MySqlConnection connection, ResumeMilitary military) {
|
public async Task SetResumeMilitary(MySqlConnection connection, ResumeMilitary military) {
|
||||||
string command = @"
|
string command = @"
|
||||||
INSERT INTO Resume
|
INSERT INTO Resume
|
||||||
(ID,ResumeID,Country,Rank,DateStarted,StillServing,DateEnded)
|
(ID,ResumeID,Veteran,Country,Rank,DateStarted,StillServing,DateEnded)
|
||||||
VALUES
|
VALUES
|
||||||
(@ID,@ResumeID,@Country,@Rank,@DateStarted,@StillServing,@DateEnded)
|
(@ID,@ResumeID,@Veteran,@Country,@Rank,@DateStarted,@StillServing,@DateEnded)
|
||||||
ON DUPLICATE KEY UPDATE
|
ON DUPLICATE KEY UPDATE
|
||||||
ResumeID = @ResumeID,
|
ResumeID = @ResumeID,
|
||||||
|
Veteran = @Veteran,
|
||||||
Country = @Country,
|
Country = @Country,
|
||||||
Rank = @Rank,
|
Rank = @Rank,
|
||||||
DateStarted = @DateStarted,
|
DateStarted = @DateStarted,
|
||||||
@@ -139,6 +142,7 @@ namespace BoredCareers.Services.DatabaseService {
|
|||||||
MySqlCommand cmd = new MySqlCommand(command, connection);
|
MySqlCommand cmd = new MySqlCommand(command, connection);
|
||||||
cmd.Parameters.AddWithValue("@ID", military.ID);
|
cmd.Parameters.AddWithValue("@ID", military.ID);
|
||||||
cmd.Parameters.AddWithValue("@ResumeID", military.ResumeID);
|
cmd.Parameters.AddWithValue("@ResumeID", military.ResumeID);
|
||||||
|
cmd.Parameters.AddWithValue("@Veteran", military.Veteran);
|
||||||
cmd.Parameters.AddWithValue("@Country", military.Country);
|
cmd.Parameters.AddWithValue("@Country", military.Country);
|
||||||
cmd.Parameters.AddWithValue("@Rank", military.Rank);
|
cmd.Parameters.AddWithValue("@Rank", military.Rank);
|
||||||
cmd.Parameters.AddWithValue("@DateStarted", military.DateStarted.ToUniversalTime());
|
cmd.Parameters.AddWithValue("@DateStarted", military.DateStarted.ToUniversalTime());
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
using Ganss.Xss;
|
||||||
|
|
||||||
|
namespace BoredCareers.Services {
|
||||||
|
public class ResumeService {
|
||||||
|
|
||||||
|
static HtmlSanitizer _self = new HtmlSanitizer();
|
||||||
|
|
||||||
|
public static void init() {
|
||||||
|
// Clear default allowed tags and attributes
|
||||||
|
_self.AllowedAttributes.Clear();
|
||||||
|
_self.AllowedSchemes.Clear();
|
||||||
|
_self.AllowedAtRules.Clear();
|
||||||
|
_self.AllowedClasses.Clear();
|
||||||
|
|
||||||
|
// Allowed HTML Tags
|
||||||
|
_self.AllowedTags.Clear();
|
||||||
|
string[] safeTags = [
|
||||||
|
"b", "strong", "i", "em", "u", "small", "mark", "del", "ins", "sub", "sup",
|
||||||
|
"p", "br", "hr", "div", "span",
|
||||||
|
"section", "article", "header", "footer", "aside", "main", "nav",
|
||||||
|
"ul", "ol", "li", "dl", "dt", "dd",
|
||||||
|
"h1", "h2", "h3", "h4", "h5", "h6",
|
||||||
|
"blockquote", "q", "cite",
|
||||||
|
"code", "pre", "samp", "kbd", "var",
|
||||||
|
"table", "thead", "tbody", "tfoot", "tr", "td", "th",
|
||||||
|
];
|
||||||
|
foreach (string cur in safeTags) {
|
||||||
|
_self.AllowedTags.Add(cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow inline styles only
|
||||||
|
_self.AllowedAttributes.Add("style");
|
||||||
|
string[] safeCssProperties = [
|
||||||
|
"align-content", "align-items", "align-self", "all",
|
||||||
|
"animation", "animation-delay", "animation-direction", "animation-duration",
|
||||||
|
"animation-fill-mode", "animation-iteration-count", "animation-name", "animation-play-state",
|
||||||
|
"animation-timing-function", "backface-visibility", "background-color", "background-clip",
|
||||||
|
"background-origin", "background-position", "background-repeat", "background-size",
|
||||||
|
"border", "border-bottom", "border-bottom-color", "border-bottom-left-radius",
|
||||||
|
"border-bottom-right-radius", "border-bottom-style", "border-bottom-width", "border-color",
|
||||||
|
"border-image-outset", "border-image-repeat", "border-image-slice", "border-image-source",
|
||||||
|
"border-image-width", "border-left", "border-left-color", "border-left-style",
|
||||||
|
"border-left-width", "border-radius", "border-right", "border-right-color",
|
||||||
|
"border-right-style", "border-right-width", "border-spacing", "border-style",
|
||||||
|
"border-top", "border-top-color", "border-top-left-radius", "border-top-right-radius",
|
||||||
|
"border-top-style", "border-top-width", "border-width", "bottom",
|
||||||
|
"box-decoration-break", "box-shadow", "box-sizing", "caption-side",
|
||||||
|
"clear", "color", "column-count", "column-fill",
|
||||||
|
"column-gap", "column-rule-color", "column-rule-style", "column-rule-width",
|
||||||
|
"column-span", "column-width", "columns", "counter-increment",
|
||||||
|
"counter-reset", "direction", "display", "empty-cells",
|
||||||
|
"flex", "flex-basis", "flex-direction", "flex-flow",
|
||||||
|
"flex-grow", "flex-shrink", "flex-wrap", "float",
|
||||||
|
"font-family", "font-feature-settings", "font-kerning", "font-language-override",
|
||||||
|
"font-size", "font-size-adjust", "font-stretch", "font-style",
|
||||||
|
"font-synthesis", "font-variant", "font-variant-alternates", "font-variant-caps",
|
||||||
|
"font-variant-east-asian", "font-variant-ligatures", "font-variant-numeric", "font-variant-position",
|
||||||
|
"font-weight", "grid", "grid-area", "grid-auto-columns",
|
||||||
|
"grid-auto-flow", "grid-auto-rows", "grid-column", "grid-column-end",
|
||||||
|
"grid-column-gap", "grid-column-start", "grid-gap", "grid-row",
|
||||||
|
"grid-row-end", "grid-row-gap", "grid-row-start", "grid-template",
|
||||||
|
"grid-template-areas", "grid-template-columns", "grid-template-rows", "height",
|
||||||
|
"hyphens", "image-rendering", "isolation", "justify-content",
|
||||||
|
"left", "letter-spacing", "line-height", "list-style-position",
|
||||||
|
"list-style-type", "margin", "margin-bottom", "margin-left",
|
||||||
|
"margin-right", "margin-top", "max-height", "max-width",
|
||||||
|
"min-height", "min-width", "object-fit", "object-position",
|
||||||
|
"opacity", "order", "orphans", "outline-color",
|
||||||
|
"outline-offset", "outline-style", "outline-width", "overflow",
|
||||||
|
"overflow-wrap", "overflow-x", "overflow-y", "padding",
|
||||||
|
"padding-bottom", "padding-left", "padding-right", "padding-top",
|
||||||
|
"page-break-after", "page-break-before", "page-break-inside", "perspective",
|
||||||
|
"perspective-origin", "pointer-events", "position", "quotes",
|
||||||
|
"resize", "right", "scroll-behavior", "table-layout",
|
||||||
|
"tab-size", "text-align", "text-align-last", "text-combine-upright",
|
||||||
|
"text-indent", "text-justify", "text-orientation", "text-overflow",
|
||||||
|
"text-shadow", "text-transform", "text-underline-position", "top",
|
||||||
|
"transform", "transform-origin", "transform-style", "transition",
|
||||||
|
"transition-delay", "transition-duration", "transition-property", "transition-timing-function",
|
||||||
|
"unicode-bidi", "user-select", "vertical-align", "visibility",
|
||||||
|
"white-space", "widows", "width", "word-break",
|
||||||
|
"word-spacing", "word-wrap", "writing-mode", "z-index"
|
||||||
|
];
|
||||||
|
foreach (string cur in safeCssProperties) {
|
||||||
|
_self.AllowedCssProperties.Add(cur);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string RemoveJavascript(string InputHTML) {
|
||||||
|
return _self.Sanitize(InputHTML);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user