Merge pull request 'working' (#36) from working into main
Docker Build and Release Upload / build (push) Successful in 2m4s

Reviewed-on: #36
This commit was merged in pull request #36.
This commit is contained in:
2025-08-27 00:31:03 +00:00
26 changed files with 931 additions and 23 deletions
+11 -1
View File
@@ -12,9 +12,10 @@ 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
Verify that each resume section belongs to the resume it was created for:
Client: Client:
jobs/editor: jobs/editor:
Job Listing Skills exists but isn't implimented in the UI
Want to add completed job listing preview at end of carosel Want to add completed job listing preview at end of carosel
Resume: Resume:
@@ -27,6 +28,11 @@ Client:
Allow users to look up jobs and apply [ Boost visibility | Completely manual ] Allow users to look up jobs and apply [ Boost visibility | Completely manual ]
Mark ghost listings to allow users to be informed and put companies on blast Mark ghost listings to allow users to be informed and put companies on blast
resume/viewer:
CSS is broken
Company needs to be able to add notes to resume
Company needs to be able to add a rating to the resume
company/editor: company/editor:
Keyboard Tab key does nothing Keyboard Tab key does nothing
Format phone number for database Format phone number for database
@@ -36,6 +42,10 @@ Client:
resume/editor: resume/editor:
There is no data validation There is no data validation
application/viewer:
need to make look better for companies to sort
need to show notes and rating properly
Company: Company:
Need to impliment Add employee Need to impliment Add employee
Need to impliment Remove employee Need to impliment Remove employee
+6
View File
@@ -8,15 +8,21 @@ 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'; import { ResumesEditorComponent } from './pages/resumes/editor/editor.component';
import { AppViewerComponent } from './pages/applicationviewer/appviewer.component';
import { ResumesViewerComponent } from './pages/resumes/viewer/viewer.component';
export const routes: Routes = [ export const routes: Routes = [
// Home // Home
{ path: "", component: HomeComponent }, { path: "", component: HomeComponent },
// Application
{ path: "application/viewer", component: AppViewerComponent },
// Resumes // Resumes
{ path: "resumes", component: ResumesComponent }, { path: "resumes", component: ResumesComponent },
{ path: "resumes/editor", component: ResumesEditorComponent }, { path: "resumes/editor", component: ResumesEditorComponent },
{ path: "resumes/viewer", component: ResumesViewerComponent },
// Jobs // Jobs
{ path: "jobs", component: JobsComponent }, { path: "jobs", component: JobsComponent },
-1
View File
@@ -20,7 +20,6 @@ export class App {
this.devMode = isDevMode(); this.devMode = isDevMode();
this.route.queryParams.subscribe(params => { this.route.queryParams.subscribe(params => {
this.loginToken = params['LoginToken']; this.loginToken = params['LoginToken'];
console.log("LoginToken : " + this.loginToken);
if (this.loginToken){ if (this.loginToken){
this.http.post( "api/account/loginticket", JSON.stringify(this.loginToken), { headers: {'Content-Type': 'application/json'} } ).subscribe({ this.http.post( "api/account/loginticket", JSON.stringify(this.loginToken), { headers: {'Content-Type': 'application/json'} } ).subscribe({
next: async() => { next: async() => {
+1
View File
@@ -9,4 +9,5 @@ export class Application {
public hasBeenViewed: boolean = false; public hasBeenViewed: boolean = false;
public rating: number = 0; public rating: number = 0;
public notes: string = ""; public notes: string = "";
public trackUUID: string = crypto.randomUUID();
} }
+1
View File
@@ -13,4 +13,5 @@ export class Company {
public stateOrRegion: string = ""; public stateOrRegion: string = "";
public city: string = ""; public city: string = "";
public description: string = ""; public description: string = "";
public trackUUID: string = crypto.randomUUID();
} }
+1
View File
@@ -6,4 +6,5 @@ export class Employee {
public accountName: string = ""; public accountName: string = "";
public accountEmail: string = ""; public accountEmail: string = "";
public company: Company = new Company; public company: Company = new Company;
public trackUUID: string = crypto.randomUUID();
} }
+3 -1
View File
@@ -15,11 +15,13 @@ export class JobListing {
public createdTime: Date = new Date(); public createdTime: Date = new Date();
public modifiedTime: Date = new Date(); public modifiedTime: Date = new Date();
public isDeleted: boolean = false; public isDeleted: boolean = false;
public trackUUID: string = crypto.randomUUID();
} }
export class JobListingSkills { export class JobListingSkills {
public id: number | null = null; public id: number | null = null;
public jobListingID: number = 0; public jobListingID: number = 0;
public name: string = ""; public name: string = "";
public Description: string = ""; public description: string = "";
public trackUUID: string = crypto.randomUUID();
} }
@@ -0,0 +1,134 @@
button {
height: 45px;
border-radius: 5px;
margin: 10px;
text-align: center;
padding: 15px 20px;
transition: 0.5s;
background-color: #00000000;
border: 1px solid var(--Mistox-Black);
color: var(--Mistox-Black);
text-decoration: none;
font: inherit;
}
button:hover {
background-color: #00000044;
color: var(--Mistox-Light);
}
.top-bar {
width: 100%;
height: 60px;
}
.content-frame {
background-color: #3c3c3c;
width: calc(100% - 40px);
height: calc(100vh - 400px);
border-radius: 20px;
margin: 10px;
overflow: scroll;
padding: 10px;
color: var(--Mistox-White);
}
.center-item {
display: flex;
width: 100%;
justify-content: center;
}
.content-edit {
position: absolute;
right: 20px;
}
.center-item img {
width: 300px;
}
.content-name {
width: 300px;
text-align: center;
font-size: 30px;
}
.content-name h1 {
margin: 0;
}
.content-link {
display: flex;
width: 300px;
justify-content: center;
}
.content-link a {
text-decoration: none;
color: var(--Mistox-White);
margin-top: auto;
}
.content-desc {
border: solid 1px red;
border-radius: 5px;
padding: 20px;
margin: 0 100px;
margin-bottom: 50px;
}
.content-desc h1 {
margin: 0;
font-size: 20px;
color: #ddd;
}
.content-button {
display: flex;
justify-content: center;
}
.content-button span {
align-content: center;
}
.split-frame {
display: flex;
width: 100%;
}
.half-frame {
width: 50%;
border-right: solid 1px var(--Mistox-Black);
border-left: solid 1px var(--Mistox-Black);
}
.half-frame h2 {
text-align: center;
}
.job-tile {
display: flex;
background-color: var(--Mistox-Black);
justify-content: end;
align-items: center;
border-radius: 10px;
margin: 0 5px;
margin-bottom: 10px;
}
.center-text {
display: flex;
flex: 1;
justify-content: center;
}
.job-tile h1 {
margin: 0;
}
.job-tile button {
color: white;
border-color: white;
}
@@ -0,0 +1,15 @@
<div>
@for (application of List; track application.trackUUID){
<div>
<h1>{{ application.responseEmail }}</h1>
<h1>{{ application.notes }}</h1>
<h1>{{ application.hasBeenViewed }}</h1>
<h1>{{ application.rating }}</h1>
<h1>{{ application.responseStatus }}</h1>
<h1>Date Applied: </h1><h1>{{ application.dateApplied }}</h1>
<button type="button" (click)="viewResume(application)" >VIEW RESUME</button>
</div>
}
</div>
@@ -0,0 +1,48 @@
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 'app/services/Authentication';
import { Application } from 'app/models/Application';
@Component({
selector: 'App-Viewer',
templateUrl: './appviewer.component.html',
styleUrls: [ './appviewer.component.css' ],
imports: [ FormsModule, CommonModule, RouterModule ]
})
export class AppViewerComponent {
public ErrorMsg: string = "";
public List: Application[] = [];
constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) {
this.title.setTitle("Applications | BoredCareers");
if (!auth.isLoggedIn){
router.navigate(["/"]);
}
};
ngOnInit(){
this.route.queryParams.subscribe(params => {
const JobListingID = params['JobID'] ? +params['JobID'] : null;
if (JobListingID !== null){
this.http.get<Application[]>("api/application?JobListingID=" + JobListingID).subscribe({
next: data => {
this.List = data;
},
error: err => {
this.ErrorMsg = err.error;
}
});
}
});
}
viewResume(app: Application) {
window.open('/resumes/viewer?ResumeID=' + app.resumeID, '_blank');
}
}
@@ -46,6 +46,7 @@
<div class="center-text"> <div class="center-text">
<h1>{{ listing.title }}</h1> <h1>{{ listing.title }}</h1>
</div> </div>
<button [routerLink]="['/application/viewer']" [queryParams]="{ JobID: listing.id }" >VIEW LISTING</button>
<button [routerLink]="['/jobs/viewer']" [queryParams]="{ JobID: listing.id }" >VIEW LISTING</button> <button [routerLink]="['/jobs/viewer']" [queryParams]="{ JobID: listing.id }" >VIEW LISTING</button>
<button [routerLink]="['/jobs/editor']" [queryParams]="{ JobID: listing.id }" >EDIT LISTING</button> <button [routerLink]="['/jobs/editor']" [queryParams]="{ JobID: listing.id }" >EDIT LISTING</button>
<button (click)="RemoveJobListing(listing.id!)">DELETE LISTING</button> <button (click)="RemoveJobListing(listing.id!)">DELETE LISTING</button>
@@ -60,11 +60,11 @@
<div class="split"> <div class="split">
<div class="half-frame"> <div class="half-frame">
<label>Company Email</label> <label>Company Email</label>
<input class="input-field" name="email" [(ngModel)]="newListing.email" type="text" placeholder="Questions@mistox.com" /> <input class="input-field" name="email" [(ngModel)]="newListing.email" type="text" (ngModelChange)="validateEmail(newListing.email)" placeholder="Questions@mistox.com" />
</div> </div>
<div class="half-frame"> <div class="half-frame">
<label>Company Phone Number</label> <label>Company Phone Number</label>
<input class="input-field" name="phone" [(ngModel)]="newListing.phone" type="text" placeholder="+1 800-000-0000" /> <input class="input-field" name="phone" [(ngModel)]="newListing.phone" type="tel" (ngModelChange)="validatePhone(newListing.phone)" placeholder="+1 800-000-0000" />
</div> </div>
</div> </div>
<button type="button" (click)="prevStep()">Back</button> <button type="button" (click)="prevStep()">Back</button>
@@ -6,6 +6,7 @@ import { Title } from '@angular/platform-browser';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { Authentication } from 'app/services/Authentication'; import { Authentication } from 'app/services/Authentication';
import { Company } from 'app/models/Company'; import { Company } from 'app/models/Company';
import { Validation } from 'app/services/Validation';
@Component({ @Component({
selector: 'main-company-editor', selector: 'main-company-editor',
@@ -23,7 +24,7 @@ export class CompanyEditorComponent {
public ErrorMsg: string = ""; public ErrorMsg: string = "";
MaxFileMB: number = 3; MaxFileMB: number = 3;
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, public validator: Validation ) {
this.title.setTitle("Company - Editor | BoredCareers"); this.title.setTitle("Company - Editor | BoredCareers");
if (!auth.isLoggedIn){ if (!auth.isLoggedIn){
router.navigate(["/"]); router.navigate(["/"]);
@@ -54,6 +55,18 @@ export class CompanyEditorComponent {
this.updateUI(0); this.updateUI(0);
} }
validatePhone(input: string){
let result = this.validator.validatePhoneNumber(input);
this.newListing.phone = result[1];
}
validateEmail(input: string){
let result = this.validator.validateEmail(input);
if (result[0]){
this.newListing.email = result[1];
}
}
@HostListener('window:keydown', ['$event']) @HostListener('window:keydown', ['$event'])
handleGlobalKeyDown(event: KeyboardEvent){ handleGlobalKeyDown(event: KeyboardEvent){
if ( event.key === 'Tab' ){ if ( event.key === 'Tab' ){
@@ -122,51 +135,73 @@ export class CompanyEditorComponent {
PostNewCompany(company: Company){ PostNewCompany(company: Company){
if (this.isNullOrEmpty(company.name)){ if (this.isNullOrEmpty(company.name)){
this.ErrorMsg = "Comany name is blank";
this.focusFrame(0, 0); this.focusFrame(0, 0);
return; return;
} }
if (this.isNullOrEmpty(company.websiteURL)){ if (this.isNullOrEmpty(company.websiteURL)){
this.ErrorMsg = "Website URL is blank";
this.focusFrame(1, 0); this.focusFrame(1, 0);
return; return;
} }
if (this.isNullOrEmpty(company.logo)){ if (this.isNullOrEmpty(company.logo)){
this.ErrorMsg = "Logo is blank";
this.focusFrame(2, 0); this.focusFrame(2, 0);
return; return;
} }
if (this.isNullOrEmpty(company.email)){ if (this.isNullOrEmpty(company.email)){
this.ErrorMsg = "Email is blank";
this.focusFrame(3, 0);
return;
}
if (this.validator.validateEmail(company.email)[0]){
this.ErrorMsg = "Email is invalid";
this.focusFrame(3, 0); this.focusFrame(3, 0);
return; return;
} }
if (this.isNullOrEmpty(company.phone)){ if (this.isNullOrEmpty(company.phone)){
this.ErrorMsg = "Phone number is blank";
this.focusFrame(3, 1);
return;
}
if (this.validator.validatePhoneNumber(company.phone)[0]){
this.ErrorMsg = "Phone number is invalid";
this.focusFrame(3, 1); this.focusFrame(3, 1);
return; return;
} }
if (this.isNullOrEmpty(company.city)){ if (this.isNullOrEmpty(company.city)){
this.ErrorMsg = "City is blank";
this.focusFrame(4, 0); this.focusFrame(4, 0);
return; return;
} }
if (this.isNullOrEmpty(company.country)){ if (this.isNullOrEmpty(company.country)){
this.ErrorMsg = "Country is blank";
this.focusFrame(4, 1); this.focusFrame(4, 1);
return; return;
} }
if (this.isNullOrEmpty(company.stateOrRegion)){ if (this.isNullOrEmpty(company.stateOrRegion)){
this.ErrorMsg = "State or Region is blank";
this.focusFrame(4, 2); this.focusFrame(4, 2);
return; return;
} }
if (this.isNullOrEmpty(company.postalCode)){ if (this.isNullOrEmpty(company.postalCode)){
this.ErrorMsg = "Postal Code is blank";
this.focusFrame(4, 3); this.focusFrame(4, 3);
return; return;
} }
if (this.isNullOrEmpty(company.description)){ if (this.isNullOrEmpty(company.description)){
this.ErrorMsg = "Description is blank";
this.focusFrame(5, 0); this.focusFrame(5, 0);
return; return;
} }
@@ -91,6 +91,27 @@
</div> </div>
</div> </div>
<!-- Skills -->
<div #step class="sub-frame">
<div class="center">
<div class="content-frame">
<label>Skills</label>
<button type="button" (click)="addSkill()">+</button>
</div>
@for(skill of Listing.skills; track skill.trackUUID){
<div class="content-frame">
<input [name]="'skillname' + skill.trackUUID" [(ngModel)]="skill.name" type="text" />
<textarea [name]="'skilldescription' + skill.trackUUID" [(ngModel)]="skill.description" type="text"></textarea>
<button type="button" (click)="remSkill(skill)">-</button>
</div>
}
<div class="content-frame">
<button type="button" (click)="prevStep()">Back</button>
<button type="button" (click)="nextStep()">Next</button>
</div>
</div>
</div>
<!-- Description --> <!-- Description -->
<div #step class="sub-frame"> <div #step class="sub-frame">
<div class="center"> <div class="center">
@@ -4,7 +4,7 @@ import { FormsModule } from '@angular/forms';
import { Router, ActivatedRoute, RouterModule } from '@angular/router'; import { Router, ActivatedRoute, RouterModule } from '@angular/router';
import { Title } from '@angular/platform-browser'; import { Title } from '@angular/platform-browser';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { JobListing } from 'app/models/JobListing'; import { JobListing, JobListingSkills } from 'app/models/JobListing';
import { Authentication } from 'app/services/Authentication'; import { Authentication } from 'app/services/Authentication';
@Component({ @Component({
@@ -51,6 +51,9 @@ export class JobEditorComponent {
if (this.mode === "edit") { if (this.mode === "edit") {
this.http.get<JobListing>("api/joblisting/" + JobID).subscribe({ this.http.get<JobListing>("api/joblisting/" + JobID).subscribe({
next: data => { next: data => {
data.skills.forEach(element => {
element.trackUUID = crypto.randomUUID();
});
this.Listing = data; this.Listing = data;
}, },
error: err => { error: err => {
@@ -80,6 +83,20 @@ export class JobEditorComponent {
}); });
} }
addSkill(){
this.Listing.skills.push(new JobListingSkills);
}
remSkill(self: JobListingSkills){
for(let i=0; i<this.Listing.skills.length; i++){
let cur = this.Listing.skills[i];
if (cur.trackUUID === self.trackUUID){
this.Listing.skills.splice( i, 1 );
break;
}
}
}
nextStep(){ nextStep(){
this.currentStep += 1; this.currentStep += 1;
this.updateUI(); this.updateUI();
@@ -47,7 +47,24 @@
<h1>{{ selectedJob.country }}</h1> <h1>{{ selectedJob.country }}</h1>
<h1>{{ selectedJob.postalCode }}</h1> <h1>{{ selectedJob.postalCode }}</h1>
<div>
<h1>Required Skills</h1>
@for(skill of selectedJob.skills; track skill.trackUUID){
<div>
<h1>{{ skill.name }}</h1>
<h1>{{ skill.description }}</h1>
</div>
}
</div>
<h1>{{ selectedJob.description }}</h1> <h1>{{ selectedJob.description }}</h1>
<div>
@for(resume of myResumes; track resume.trackUUID){
<div>
<button type="button" (click)="applyWithResume(resume)">APPLY USING RESUME: {{ resume.name }}</button>
</div>
}
</div>
</div> </div>
} }
</div> </div>
@@ -7,6 +7,8 @@ import { CommonModule } from '@angular/common';
import { Authentication } from 'app/services/Authentication'; import { Authentication } from 'app/services/Authentication';
import { JobListing } from 'app/models/JobListing'; import { JobListing } from 'app/models/JobListing';
import { Company } from 'app/models/Company'; import { Company } from 'app/models/Company';
import { Resume } from 'app/models/Resume';
import { Application } from 'app/models/Application';
@Component({ @Component({
selector: 'main-jobs-viewer', selector: 'main-jobs-viewer',
@@ -17,9 +19,12 @@ import { Company } from 'app/models/Company';
export class JobViewerComponent { export class JobViewerComponent {
public selectedJob: JobListing | null = null; public selectedJob: JobListing | null = null;
public myResumes: Resume[] = [];
public jobsCompany: Company | null = null; public jobsCompany: Company | null = null;
public ErrorMsg: string = ""; public ErrorMsg: string = "";
JobListingID: number = -1;
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 - Viewer | BoredCareers"); this.title.setTitle("Jobs - Viewer | BoredCareers");
}; };
@@ -27,7 +32,8 @@ export class JobViewerComponent {
ngOnInit(){ ngOnInit(){
this.route.queryParams.subscribe(params => { this.route.queryParams.subscribe(params => {
const JobID = params['JobID']; const JobID = params['JobID'];
if (JobID){ if (JobID) {
this.JobListingID = JobID;
this.http.get<JobListing>( "api/joblisting/" + JobID ).subscribe({ this.http.get<JobListing>( "api/joblisting/" + JobID ).subscribe({
next: data => { next: data => {
this.selectedJob = data; this.selectedJob = data;
@@ -51,6 +57,41 @@ export class JobViewerComponent {
} }
}); });
this.http.get<Resume[]>("api/resume").subscribe({
next: data => {
this.myResumes = data;
},
error: err => {
console.log("Error fetching resumes: " + err.error);
}
});
}
applyWithResume(resume: Resume) {
var application = new Application;
if (this.auth.loggedInUser.id != null){
application.accountID = this.auth.loggedInUser.id;
}
if (resume.id != null){
application.resumeID = resume.id;
}
application.jobListingID = this.JobListingID;
application.hasBeenViewed = false;
application.responseEmail = resume.email;
this.http.post("api/application", application).subscribe({
next: data => {
this.router.navigate(["/"]);
},
error: err => {
this.ErrorMsg = err.error;
}
});
} }
} }
@@ -23,8 +23,8 @@
</div> </div>
</div> </div>
<div class="header-right"> <div class="header-right">
<input [name]="'resumeemail' + resume.trackUUID" [(ngModel)]="resume.email" type="email" placeholder="Email Address" /> <input [name]="'resumeemail' + resume.trackUUID" [(ngModel)]="resume.email" type="email" (ngModelChange)="validateEmail(resume.email)" placeholder="Email Address" />
<input [name]="'resumephoneNumber' + resume.trackUUID" [(ngModel)]="resume.phoneNumber" type="tel" placeholder="Phone number" /> <input [name]="'resumephoneNumber' + resume.trackUUID" [(ngModel)]="resume.phoneNumber" (ngModelChange)="validatePhone(resume.phoneNumber)" type="tel" placeholder="Phone number" />
</div> </div>
</div> </div>
@@ -6,6 +6,7 @@ import { Title } from '@angular/platform-browser';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { Resume, ResumeCertification, ResumeEducation, ResumeExperience, ResumeExperienceBullet, ResumeLanguage, ResumeMilitary, ResumeMilitaryBullet, ResumeProject, ResumeSkill } from 'app/models/Resume'; import { Resume, ResumeCertification, ResumeEducation, ResumeExperience, ResumeExperienceBullet, ResumeLanguage, ResumeMilitary, ResumeMilitaryBullet, ResumeProject, ResumeSkill } from 'app/models/Resume';
import { Authentication } from 'app/services/Authentication'; import { Authentication } from 'app/services/Authentication';
import { Validation } from 'app/services/Validation';
@Component({ @Component({
selector: 'main-resume-editor', selector: 'main-resume-editor',
@@ -20,7 +21,7 @@ export class ResumesEditorComponent {
public ErrorMsg: string = ""; public ErrorMsg: string = "";
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, public validator: Validation ) {
this.title.setTitle("Resume - Editor | BoredCareers"); this.title.setTitle("Resume - Editor | BoredCareers");
if (!this.auth.isLoggedIn){ if (!this.auth.isLoggedIn){
this.router.navigate(["/"]); this.router.navigate(["/"]);
@@ -75,11 +76,6 @@ export class ResumesEditorComponent {
}); });
} }
// Pagnation //
////////////////////////////////
////////////////////////////////
SubmitForm(resume: Resume){ SubmitForm(resume: Resume){
resume.accountID = this.auth.loggedInUser.id; resume.accountID = this.auth.loggedInUser.id;
this.http.post("api/resume", resume).subscribe({ this.http.post("api/resume", resume).subscribe({
@@ -92,6 +88,20 @@ export class ResumesEditorComponent {
}); });
} }
validatePhone(input: string){
let result = this.validator.validatePhoneNumber(input);
if (result[0]){
this.resume.phoneNumber = result[1];
}
}
validateEmail(input: string){
let result = this.validator.validateEmail(input);
if (result[0]){
this.resume.email = result[1];
}
}
PrintResume(){ PrintResume(){
const divToPrint = document.getElementsByClassName("paper")[0]; const divToPrint = document.getElementsByClassName("paper")[0];
@@ -0,0 +1,105 @@
input, textarea {
border: 1px solid #444;
background-color: transparent;
}
textarea {
resize: vertical;
}
h1 {
margin: 0;
font-size: 15px;
}
.paper {
width: 800px;
aspect-ratio: 17 / 22;
background: white;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
margin: auto;
margin-top: 50px;
border: 1px solid #ddd;
}
.spacer {
margin: 0 10px;
}
.spacer-title {
display: flex;
margin: 10px 0;
}
.columns {
columns: 2;
column-gap: 10px;
}
.resume-header {
width: 70vw;
background: white;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
margin: auto;
margin-top: 50px;
border: 1px solid #ddd;
}
.resume-section {
margin-bottom: 10px;
}
.resume-sub-section {
border: 1px solid #666666;
break-inside: avoid;
padding: 10px;
}
.title-text {
margin: 0;
height: 20px;
}
.header-left {
width: 50%;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
}
.header-right {
width: 50%;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-end;
}
.header-location input{
width: 80px;
}
.Add {
position: relative;
float: right;
width: 20px;
height: 20px;
background-color: #0F0;
border: none;
bottom: 20px;
}
.Del {
position: relative;
float: right;
width: 20px;
height: 20px;
background-color: #F00;
border: none;
}
.flex-two-row {
display: flex;
flex: 1;
}
@@ -0,0 +1,301 @@
<div class="resume-header">
<div>
<input [name]="'resumetitle' + resume.trackUUID" [(ngModel)]="resume.title" type="text" placeholder="Resume Name" />
</div>
<h1>Public: </h1><input [name]="'active' + resume.trackUUID" [(ngModel)]="resume.isActive" type="checkbox" />
<h1>Is Veteran: </h1><input [name]="'veteran' + resume.military?.trackUUID" type="checkbox" [checked]="resume.military !== null" />
</div>
<div class="paper">
<div class="spacer">
<!-- Resume Header -->
<div class="resume-section spacer-title">
<div class="header-left">
<input [name]="'resumename' + resume.trackUUID" [(ngModel)]="resume.name" type="text" placeholder="Full Name" />
<input [name]="'resumefield' + resume.trackUUID" [(ngModel)]="resume.field" type="text" placeholder="Career Field" />
<div class="header-location">
<input [name]="'resumecity' + resume.trackUUID" [(ngModel)]="resume.city" type="text" placeholder="City" />
<input [name]="'resumestateOrRegion' + resume.trackUUID" [(ngModel)]="resume.stateOrRegion" type="text" placeholder="State" />
<input [name]="'resumecountry' + resume.trackUUID" [(ngModel)]="resume.country" type="text" placeholder="Country" />
<input [name]="'resumepostalCode' + resume.trackUUID" [(ngModel)]="resume.postalCode" type="text" placeholder="Postal Code" />
</div>
</div>
<div class="header-right">
<input [name]="'resumeemail' + resume.trackUUID" [(ngModel)]="resume.email" type="email" placeholder="Email Address" />
<input [name]="'resumephoneNumber' + resume.trackUUID" [(ngModel)]="resume.phoneNumber" type="tel" placeholder="Phone number" />
</div>
</div>
<div class="columns">
<!-- Experience -->
<div class="resume-section">
<h1 class="title-text">Experience</h1>
@for(experience of resume.experiences; track experience.trackUUID ){
<div class="resume-sub-section">
<input [name]="'experiencejobTitle' + experience.trackUUID" [(ngModel)]="experience.jobTitle" type="text" placeholder="Job Title" />
<input [name]="'experiencecompany' + experience.trackUUID" [(ngModel)]="experience.company" type="text" placeholder="Company" />
<input [name]="'experiencecity' + experience.trackUUID" [(ngModel)]="experience.city" type="text" placeholder="City" />
<input [name]="'experiencestateOrRegion' + experience.trackUUID" [(ngModel)]="experience.stateOrRegion" type="text" placeholder="State" />
<input [name]="'experiencecountry' + experience.trackUUID" [(ngModel)]="experience.country" type="text" placeholder="Country" />
<input [name]="'experiencepostalCode' + experience.trackUUID" [(ngModel)]="experience.postalCode" type="text" placeholder="Postal Code" />
<input [name]="'experiencestillEmployed' + experience.trackUUID" [(ngModel)]="experience.stillEmployed" type="checkbox" />
<input [name]="'experiencedateStarted' + experience.trackUUID" [(ngModel)]="experience.dateStarted" type="date" />
@if(!experience.stillEmployed){
<input [name]="'experiencedateEnded' + experience.trackUUID" [(ngModel)]="experience.dateEnded" type="date" />
}
@for(bullet of experience.experienceBullets; track bullet.trackUUID){
<div>
<textarea [name]="'bulletjobFunction' + bullet.trackUUID" [(ngModel)]="bullet.jobFunction" placeholder="Job Task / Function" ></textarea>
</div>
}
</div>
}
</div>
<!-- Military -->
@if(resume.military !== null){
<div class="resume-section">
<h1 class="title-text">Military</h1>
<input [name]="'militarycountry' + resume.military.trackUUID" [(ngModel)]="resume.military.country" type="text" placeholder="Country" />
<input [name]="'militaryrank' + resume.military.trackUUID" [(ngModel)]="resume.military.rank" type="text" placeholder="Rank" />
<h1>Still Serving: </h1><input [name]="'stillServing' + resume.military.trackUUID" [(ngModel)]="resume.military.stillServing" type="checkbox" />
<input [name]="'militarydateStarted' + resume.military.trackUUID" [(ngModel)]="resume.military.dateStarted" type="date" />
@if (!resume.military.stillServing){
<input [name]="'dateEnded' + resume.military.trackUUID" [(ngModel)]="resume.military.dateEnded" type="date" />
}
@for(military of resume.military.militaryBullets; track military.trackUUID ){
<div class="resume-sub-section">
<input [name]="'militaryachievement' + military.trackUUID" [(ngModel)]="military.achievement" type="text" placeholder="Achievement" />
<textarea [name]="'militarydescription' + military.trackUUID" [(ngModel)]="military.description" placeholder="Description" ></textarea>
</div>
}
</div>
}
<!-- Education -->
<div class="resume-section">
<h1 class="title-text">Education</h1>
@for(education of resume.educations; track education.trackUUID){
<div class="resume-sub-section">
<input [name]="'educationschool' + education.trackUUID" [(ngModel)]="education.school" type="text" placeholder="School" />
<input [name]="'educationdegreeType' + education.trackUUID" [(ngModel)]="education.degreeType" type="text" placeholder="Type" />
<input [name]="'educationdegreeField' + education.trackUUID" [(ngModel)]="education.degreeField" type="text" placeholder="Field" />
<input [name]="'educationcity' + education.trackUUID" [(ngModel)]="education.city" type="text" placeholder="City" />
<input [name]="'educationstateOrRegion' + education.trackUUID" [(ngModel)]="education.stateOrRegion" type="text" placeholder="State" />
<input [name]="'educationcountry' + education.trackUUID" [(ngModel)]="education.country" type="text" placeholder="Country" />
<input [name]="'educationpostalCode' + education.trackUUID" [(ngModel)]="education.postalCode" type="text" placeholder="Postal Code" />
<input [name]="'educationstillStudying' + education.trackUUID" [(ngModel)]="education.stillStudying" type="checkbox" />
<input [name]="'educationdateStarted' + education.trackUUID" [(ngModel)]="education.dateStarted" type="date" />
@if (!education.stillStudying){
<input [name]="'educationdateEnded' + education.trackUUID" [(ngModel)]="education.dateEnded" type="date" />
}
</div>
}
</div>
<div class="resume-header">
<div>
<input [name]="'resumetitle' + resume.trackUUID" [(ngModel)]="resume.title" type="text" placeholder="Resume Name" />
</div>
<h1>Public: </h1><input [name]="'active' + resume.trackUUID" [(ngModel)]="resume.isActive" type="checkbox" />
<h1>Is Veteran: </h1><input [name]="'veteran' + resume.military?.trackUUID" type="checkbox" [checked]="resume.military !== null" />
</div>
<div class="paper">
<div class="spacer">
<!-- Resume Header -->
<div class="resume-section spacer-title">
<div class="header-left">
<input [name]="'resumename' + resume.trackUUID" [(ngModel)]="resume.name" type="text" placeholder="Full Name" />
<input [name]="'resumefield' + resume.trackUUID" [(ngModel)]="resume.field" type="text" placeholder="Career Field" />
<div class="header-location">
<input [name]="'resumecity' + resume.trackUUID" [(ngModel)]="resume.city" type="text" placeholder="City" />
<input [name]="'resumestateOrRegion' + resume.trackUUID" [(ngModel)]="resume.stateOrRegion" type="text" placeholder="State" />
<input [name]="'resumecountry' + resume.trackUUID" [(ngModel)]="resume.country" type="text" placeholder="Country" />
<input [name]="'resumepostalCode' + resume.trackUUID" [(ngModel)]="resume.postalCode" type="text" placeholder="Postal Code" />
</div>
</div>
<div class="header-right">
<input [name]="'resumeemail' + resume.trackUUID" [(ngModel)]="resume.email" type="email" placeholder="Email Address" />
<input [name]="'resumephoneNumber' + resume.trackUUID" [(ngModel)]="resume.phoneNumber" type="tel" placeholder="Phone number" />
</div>
</div>
<div class="columns">
<!-- Experience -->
<div class="resume-section">
<h1 class="title-text">Experience</h1>
@for(experience of resume.experiences; track experience.trackUUID ){
<div class="resume-sub-section">
<input [name]="'experiencejobTitle' + experience.trackUUID" [(ngModel)]="experience.jobTitle" type="text" placeholder="Job Title" />
<input [name]="'experiencecompany' + experience.trackUUID" [(ngModel)]="experience.company" type="text" placeholder="Company" />
<input [name]="'experiencecity' + experience.trackUUID" [(ngModel)]="experience.city" type="text" placeholder="City" />
<input [name]="'experiencestateOrRegion' + experience.trackUUID" [(ngModel)]="experience.stateOrRegion" type="text" placeholder="State" />
<input [name]="'experiencecountry' + experience.trackUUID" [(ngModel)]="experience.country" type="text" placeholder="Country" />
<input [name]="'experiencepostalCode' + experience.trackUUID" [(ngModel)]="experience.postalCode" type="text" placeholder="Postal Code" />
<input [name]="'experiencestillEmployed' + experience.trackUUID" [(ngModel)]="experience.stillEmployed" type="checkbox" />
<input [name]="'experiencedateStarted' + experience.trackUUID" [(ngModel)]="experience.dateStarted" type="date" />
@if(!experience.stillEmployed){
<input [name]="'experiencedateEnded' + experience.trackUUID" [(ngModel)]="experience.dateEnded" type="date" />
}
@for(bullet of experience.experienceBullets; track bullet.trackUUID){
<div>
<textarea [name]="'bulletjobFunction' + bullet.trackUUID" [(ngModel)]="bullet.jobFunction" placeholder="Job Task / Function" ></textarea>
</div>
}
</div>
}
</div>
<!-- Military -->
@if(resume.military !== null){
<div class="resume-section">
<h1 class="title-text">Military</h1>
<input [name]="'militarycountry' + resume.military.trackUUID" [(ngModel)]="resume.military.country" type="text" placeholder="Country" />
<input [name]="'militaryrank' + resume.military.trackUUID" [(ngModel)]="resume.military.rank" type="text" placeholder="Rank" />
<h1>Still Serving: </h1><input [name]="'stillServing' + resume.military.trackUUID" [(ngModel)]="resume.military.stillServing" type="checkbox" />
<input [name]="'militarydateStarted' + resume.military.trackUUID" [(ngModel)]="resume.military.dateStarted" type="date" />
@if (!resume.military.stillServing){
<input [name]="'dateEnded' + resume.military.trackUUID" [(ngModel)]="resume.military.dateEnded" type="date" />
}
@for(military of resume.military.militaryBullets; track military.trackUUID ){
<div class="resume-sub-section">
<input [name]="'militaryachievement' + military.trackUUID" [(ngModel)]="military.achievement" type="text" placeholder="Achievement" />
<textarea [name]="'militarydescription' + military.trackUUID" [(ngModel)]="military.description" placeholder="Description" ></textarea>
</div>
}
</div>
}
<!-- Education -->
<div class="resume-section">
<h1 class="title-text">Education</h1>
@for(education of resume.educations; track education.trackUUID){
<div class="resume-sub-section">
<input [name]="'educationschool' + education.trackUUID" [(ngModel)]="education.school" type="text" placeholder="School" />
<input [name]="'educationdegreeType' + education.trackUUID" [(ngModel)]="education.degreeType" type="text" placeholder="Type" />
<input [name]="'educationdegreeField' + education.trackUUID" [(ngModel)]="education.degreeField" type="text" placeholder="Field" />
<input [name]="'educationcity' + education.trackUUID" [(ngModel)]="education.city" type="text" placeholder="City" />
<input [name]="'educationstateOrRegion' + education.trackUUID" [(ngModel)]="education.stateOrRegion" type="text" placeholder="State" />
<input [name]="'educationcountry' + education.trackUUID" [(ngModel)]="education.country" type="text" placeholder="Country" />
<input [name]="'educationpostalCode' + education.trackUUID" [(ngModel)]="education.postalCode" type="text" placeholder="Postal Code" />
<input [name]="'educationstillStudying' + education.trackUUID" [(ngModel)]="education.stillStudying" type="checkbox" />
<input [name]="'educationdateStarted' + education.trackUUID" [(ngModel)]="education.dateStarted" type="date" />
@if (!education.stillStudying){
<input [name]="'educationdateEnded' + education.trackUUID" [(ngModel)]="education.dateEnded" type="date" />
}
</div>
}
</div>
<!-- Skill -->
<div class="resume-section">
<h1 class="title-text">Skills</h1>
@for(skill of resume.skills; track skill.trackUUID){
<div class="resume-sub-section flex-two-row">
<div>
<input [name]="'skillname' + skill.trackUUID" [(ngModel)]="skill.name" type="text" placeholder="Skill" />
</div>
<textarea [name]="'skilldescription' + skill.trackUUID" [(ngModel)]="skill.description" placeholder="Description"></textarea>
</div>
}
</div>
<!-- Language -->
<div class="resume-section">
<h1 class="title-text">Languages</h1>
@for(language of resume.languages; track language.trackUUID){
<div class="resume-sub-section flex-two-row">
<input [name]="'languagelanguage' + language.trackUUID" [(ngModel)]="language.language" type="text" placeholder="Language" />
<input [name]="'languageproficiency' + language.trackUUID" [(ngModel)]="language.proficiency" type="text" placeholder="Proficiency" />
</div>
}
</div>
<!-- Certification -->
<div class="resume-section">
<h1 class="title-text">Certifications</h1>
@for(cert of resume.certifications; track cert.trackUUID){
<div class="resume-sub-section flex-two-row">
<div>
<input [name]="'certname' + cert.trackUUID" [(ngModel)]="cert.name" type="text" placeholder="Certification Name" />
<input [name]="'certverificationURL' + cert.trackUUID" [(ngModel)]="cert.verificationURL" type="text" placeholder="Verification URL" />
</div>
<textarea [name]="'certdescription' + cert.trackUUID" [(ngModel)]="cert.description" placeholder="Description"></textarea>
</div>
}
</div>
<!-- Project -->
<div class="resume-section">
<h1 class="title-text">Projects</h1>
@for(proj of resume.projects; track proj.trackUUID){
<div class="resume-sub-section flex-two-row">
<div>
<input [name]="'projname' + proj.trackUUID" [(ngModel)]="proj.name" type="text" placeholder="Project Name" />
<input [name]="'projurl' + proj.trackUUID" [(ngModel)]="proj.url" type="text" placeholder="Reference URL" />
</div>
<textarea [name]="'projdescription' + proj.trackUUID" [(ngModel)]="proj.description" placeholder="Description"></textarea>
</div>
}
</div>
</div>
</div>
</div>
<!-- Skill -->
<div class="resume-section">
<h1 class="title-text">Skills</h1>
@for(skill of resume.skills; track skill.trackUUID){
<div class="resume-sub-section flex-two-row">
<div>
<input [name]="'skillname' + skill.trackUUID" [(ngModel)]="skill.name" type="text" placeholder="Skill" />
</div>
<textarea [name]="'skilldescription' + skill.trackUUID" [(ngModel)]="skill.description" placeholder="Description"></textarea>
</div>
}
</div>
<!-- Language -->
<div class="resume-section">
<h1 class="title-text">Languages</h1>
@for(language of resume.languages; track language.trackUUID){
<div class="resume-sub-section flex-two-row">
<input [name]="'languagelanguage' + language.trackUUID" [(ngModel)]="language.language" type="text" placeholder="Language" />
<input [name]="'languageproficiency' + language.trackUUID" [(ngModel)]="language.proficiency" type="text" placeholder="Proficiency" />
</div>
}
</div>
<!-- Certification -->
<div class="resume-section">
<h1 class="title-text">Certifications</h1>
@for(cert of resume.certifications; track cert.trackUUID){
<div class="resume-sub-section flex-two-row">
<div>
<input [name]="'certname' + cert.trackUUID" [(ngModel)]="cert.name" type="text" placeholder="Certification Name" />
<input [name]="'certverificationURL' + cert.trackUUID" [(ngModel)]="cert.verificationURL" type="text" placeholder="Verification URL" />
</div>
<textarea [name]="'certdescription' + cert.trackUUID" [(ngModel)]="cert.description" placeholder="Description"></textarea>
</div>
}
</div>
<!-- Project -->
<div class="resume-section">
<h1 class="title-text">Projects</h1>
@for(proj of resume.projects; track proj.trackUUID){
<div class="resume-sub-section flex-two-row">
<div>
<input [name]="'projname' + proj.trackUUID" [(ngModel)]="proj.name" type="text" placeholder="Project Name" />
<input [name]="'projurl' + proj.trackUUID" [(ngModel)]="proj.url" type="text" placeholder="Reference URL" />
</div>
<textarea [name]="'projdescription' + proj.trackUUID" [(ngModel)]="proj.description" placeholder="Description"></textarea>
</div>
}
</div>
</div>
</div>
</div>
@@ -0,0 +1,92 @@
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 } from 'app/models/Resume';
import { Authentication } from 'app/services/Authentication';
import { Validation } from 'app/services/Validation';
@Component({
selector: 'main-resume-viewer',
templateUrl: './viewer.component.html',
styleUrls: [ './viewer.component.css' ],
imports: [FormsModule, CommonModule, RouterModule]
})
export class ResumesViewerComponent {
public resume: Resume = new Resume;
public ErrorMsg: string = "";
constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication, public validator: Validation ) {
this.title.setTitle("Resume - Viewer | BoredCareers");
if (!this.auth.isLoggedIn){
this.router.navigate(["/"]);
}
};
ngOnInit(){
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 => {
data.trackUUID = crypto.randomUUID();
data.certifications.forEach(element => {
element.trackUUID = crypto.randomUUID();
});
data.educations.forEach(element => {
element.trackUUID = crypto.randomUUID();
});
data.experiences.forEach(element => {
element.trackUUID = crypto.randomUUID();
element.experienceBullets.forEach(subelement => {
subelement.trackUUID = crypto.randomUUID();
});
});
data.languages.forEach(element => {
element.trackUUID = crypto.randomUUID();
});
if (data.military){
data.military.trackUUID = crypto.randomUUID();
data.military.militaryBullets.forEach(element => {
element.trackUUID = crypto.randomUUID();
});
}
data.projects.forEach(element => {
element.trackUUID = crypto.randomUUID();
});
data.skills.forEach(element => {
element.trackUUID = crypto.randomUUID();
});
this.resume = data;
},
error: err => {
this.ErrorMsg = err.error;
}
});
}
});
}
PrintResume(){
const divToPrint = document.getElementsByClassName("paper")[0];
const printContents = divToPrint.innerHTML;
const originalContents = document.body.innerHTML; // Store original body content
// Temporarily replace the body content with the div's content
document.body.innerHTML = printContents;
// Trigger the print dialog
window.print();
// Restore the original body content
document.body.innerHTML = originalContents;
}
}
+35
View File
@@ -0,0 +1,35 @@
import { Injectable } from "@angular/core";
@Injectable({ providedIn: 'root' })
export class Validation {
constructor(){ }
validatePhoneNumber(input: string): [boolean, string] {
var sanitized = input.replace(/\D/g, '');
if (sanitized.length < 10){
let formatted = sanitized.replace(/(\d{3})(?=\d{3})/g, '$1-').replace(/(\d{4})(?=\d{1,4}$)/, '$1-');
return [false, formatted];
} else if (sanitized.length === 10) {
let result = `(${sanitized.slice(0, 3)})${sanitized.slice(3, 6)}-${sanitized.slice(6, 10)}`;
return [true, result];
} else if (sanitized.length > 10 && sanitized.length < 14) {
let countryCode = sanitized.slice(0, sanitized.length - 10);
let areaCode = sanitized.slice(sanitized.length - 10, sanitized.length - 7);
let firstPart = sanitized.slice(sanitized.length - 7, sanitized.length - 4);
let secondPart = sanitized.slice(sanitized.length - 4);
let result = `+${countryCode} (${areaCode})${firstPart}-${secondPart}`;
return [true, result];
}else{
return [false, input];
}
}
emailRegex: RegExp = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;
validateEmail(input: string): [boolean, string] {
const corrected = input.trim().toLowerCase();
const success = this.emailRegex.test(corrected);
return [success, corrected];
}
}
@@ -10,13 +10,19 @@ namespace BoredCareers.Controllers {
public ApplicationController(DatabaseService db) : base(db) {} public ApplicationController(DatabaseService db) : base(db) {}
[HttpGet] [HttpGet]
public async Task<IActionResult> GetApplication(int ApplicationID) { public async Task<IActionResult> GetApplication(int? ApplicationID, int? JobListingID) {
if (isLoggedIn()) { if (isLoggedIn()) {
Application? application = await _databaseService.GetApplication(ApplicationID); if (ApplicationID != null) {
if (application != null) { Application? application = await _databaseService.GetApplication(Convert.ToInt32(ApplicationID));
return Ok(application); if (application != null) {
return Ok(application);
}
return NotFound("Application doesn't exist");
} else if (JobListingID != null) {
Application[] applications = await _databaseService.GetApplicationsFromJobListing(Convert.ToInt32(JobListingID));
return Ok(applications);
} }
return NotFound("Application doesn't exist"); return NotFound("No query selector supplied");
} }
return NotFound("Not logged in"); return NotFound("Not logged in");
} }
@@ -228,6 +228,8 @@ namespace BoredCareers.Services.DatabaseService {
Description = @Description, Description = @Description,
ModifiedTime = @ModifiedTime, ModifiedTime = @ModifiedTime,
IsDeleted = @IsDeleted; IsDeleted = @IsDeleted;
SELECT LAST_INSERT_ID();
"; ";
MySqlCommand cmd = new MySqlCommand(command, connection); MySqlCommand cmd = new MySqlCommand(command, connection);
@@ -247,9 +249,17 @@ namespace BoredCareers.Services.DatabaseService {
cmd.Parameters.AddWithValue("@ModifiedTime", DateTime.UtcNow); cmd.Parameters.AddWithValue("@ModifiedTime", DateTime.UtcNow);
cmd.Parameters.AddWithValue("@IsDeleted", jobListing.IsDeleted); cmd.Parameters.AddWithValue("@IsDeleted", jobListing.IsDeleted);
await cmd.ExecuteNonQueryAsync(); object? result = await cmd.ExecuteScalarAsync();
int jobListingID = 0;
if (jobListing.ID != null && jobListing.ID != 0) {
jobListingID = Convert.ToInt32(jobListing.ID);
} else {
cmd.CommandText = "";
jobListingID = Convert.ToInt32(result);
}
foreach (JobListingSkill cur in jobListing.Skills) { foreach (JobListingSkill cur in jobListing.Skills) {
cur.JobListingID = jobListingID;
await SetJobListingSkills(cur); await SetJobListingSkills(cur);
} }
} }
@@ -43,7 +43,7 @@ namespace BoredCareers.Services.DatabaseService {
using( MySqlConnection connection = GetConnection() ) { using( MySqlConnection connection = GetConnection() ) {
await connection.OpenAsync(); await connection.OpenAsync();
string command = @" string command = @"
INSERT INTO JobListing INSERT INTO JobListingSkill
(ID,JobListingID,Name,Description) (ID,JobListingID,Name,Description)
VALUES VALUES
(@ID,@JobListingID,@Name,@Description) (@ID,@JobListingID,@Name,@Description)