Merge pull request 'working' (#31) from working into main
Docker Build and Release Upload / build (push) Successful in 1m24s

Reviewed-on: #31
This commit was merged in pull request #31.
This commit is contained in:
2025-08-20 04:18:48 +00:00
15 changed files with 53 additions and 163 deletions
+1 -20
View File
@@ -1,13 +1,4 @@
Server:
Emails:
Dont follow theme of website
When a company is created:
Send email -> verify ownership of the email
Resume:
Block API Access as much as possible [ Disallow AI keyword filters ]
Auth:
Make sure autorenew works
@@ -21,13 +12,9 @@ Server:
Need to update notification email
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:
jobs/editor:
Job Listing Skills exists but isn't implimented in the UI
Tab doesnt do anything
Want to add completed job listing preview at end of carosel
Resume:
@@ -41,23 +28,17 @@ Client:
Mark ghost listings to allow users to be informed and put companies on blast
company/editor:
Need to lookup company before making a new one
Tab key does nothing
Keyboard Tab key does nothing
Format phone number for database
Check DataType's for email and phone.
Setup QueryParam's for Edit and New
Edit employees not implimented yet
resume/editor:
Not fully tested yet
When adding new fields the fields above it glitch out and disappear
There is no data validation
Company:
Need to impliment Add employee
Need to impliment Remove employee
Edit Company -> Dont allow edit of company email due to it being verified
database:
Add Applied Jobs Table
@@ -41,7 +41,7 @@
<img [src]="newListing.logo" />
<!-- Need to fix for image file upload -->
<div id="FileUploadPlaceholder" ></div>
<input type="file" (change)="onFileSelected($event)" accept="image/*" />
<input name="file" type="file" (change)="onFileSelected($event)" accept="image/*" />
<button type="button" (click)="prevStep()">Back</button>
<button type="button" (click)="nextStep()">Next</button>
@@ -64,7 +64,7 @@
</div>
<div class="half-frame">
<label>Company Phone Number</label>
<input class="input-field" name="email" [(ngModel)]="newListing.phone" type="text" placeholder="+1 800-000-0000" />
<input class="input-field" name="phone" [(ngModel)]="newListing.phone" type="text" placeholder="+1 800-000-0000" />
</div>
</div>
<button type="button" (click)="prevStep()">Back</button>
@@ -156,7 +156,11 @@
</div>
<div class="content-frame">
<button type="button" (click)="prevStep()">Back</button>
<button type="submit">CREATE COMPANY</button>
@if(isNewCompany){
<button type="submit">CREATE COMPANY</button>
}@else{
<button type="submit">UPDATE COMPANY</button>
}
</div>
<div class="footer-frame">
<span>Does everything look good</span><br />
@@ -19,6 +19,7 @@ export class CompanyEditorComponent {
currentStep: number = 0;
public newListing: Company = new Company();
public isNewCompany: boolean = true;
public ErrorMsg: string = "";
MaxFileMB: number = 3;
@@ -30,8 +31,20 @@ export class CompanyEditorComponent {
};
ngOnInit(){
// Query param CompanyID -> Edit
// Query param null -> New
this.route.queryParams.subscribe(params => {
const CompanyID = params['CompanyID'] ? +params['CompanyID'] : null;
if (CompanyID !== null){
this.http.get<Company>("api/company?CompanyID=" + CompanyID).subscribe({
next: data => {
this.newListing = data;
this.isNewCompany = false;
},
error: err => {
this.ErrorMsg = err.error;
}
});
}
});
}
ngAfterViewInit(){
@@ -158,9 +171,9 @@ export class CompanyEditorComponent {
return;
}
this.http.post("api/company?newCompany=true", company).subscribe({
this.http.post("api/company", company).subscribe({
next: data => {
this.router.navigate([""]);
this.router.navigate(["/company"]);
},
error: err => {
this.ErrorMsg = err.error;
@@ -108,7 +108,11 @@
<div class="center">
<div class="content-frame">
<button type="button" (click)="prevStep()">Back</button>
<button type="submit">CREATE JOB LISTING</button>
@if (isNewListing){
<button type="submit">CREATE LISTING</button>
}@else{
<button type="submit">UPDATE LISTING</button>
}
</div>
</div>
</div>
@@ -20,9 +20,9 @@ export class JobEditorComponent {
currentStep: number = 0;
public Listing: JobListing = new JobListing();
public isNewListing: boolean = true;
public mode: string = "";
public modeID: number = 0;
constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) {
this.title.setTitle("Jobs - Editor | BoredCareers");
@@ -39,10 +39,11 @@ export class JobEditorComponent {
this.router.navigate([""]);
}else if (CompanyID !== null ){
this.mode = "new";
this.modeID = CompanyID;
this.Listing.companyID = CompanyID;
}else if(JobID !== null){
this.mode = "edit";
this.modeID = JobID;
this.Listing.id = JobID;
this.isNewListing = false;
}else if (CompanyID === null && JobID === null){
this.router.navigate([""]);
}
@@ -90,14 +91,9 @@ export class JobEditorComponent {
}
SubmitForm(jobListing: JobListing){
if (this.mode === "new"){
jobListing.companyID = this.modeID;
} else if (this.mode === "edit"){
jobListing.id = this.modeID;
}
this.http.post("api/joblisting", jobListing).subscribe({
next: data => {
this.router.navigate([""]);
this.router.navigate(["/company"]);
},
error: err => {
this.ErrorMsg = err.error;
@@ -84,7 +84,7 @@ export class ResumesEditorComponent {
resume.accountID = this.auth.loggedInUser.id;
this.http.post("api/resume", resume).subscribe({
next: data => {
this.router.navigate(["/"]);
this.router.navigate(["/resumes"]);
},
error: err => {
this.ErrorMsg = err.error;
@@ -1,7 +1,6 @@
using Microsoft.AspNetCore.Mvc;
using BoredCareers.Services.DatabaseService;
using BoredCareers.Entities;
using System.Web.Http;
namespace BoredCareers.Controllers {
[ApiController]
@@ -1,7 +1,6 @@
using Microsoft.AspNetCore.Mvc;
using BoredCareers.Services.DatabaseService;
using BoredCareers.Entities;
using System.Web.Http;
using System.Text.Json;
using System.Text;
+15 -16
View File
@@ -1,7 +1,6 @@
using Microsoft.AspNetCore.Mvc;
using BoredCareers.Services.DatabaseService;
using BoredCareers.Entities;
using System.Web.Http;
using BoredCareers.Services;
namespace BoredCareers.Controllers {
@@ -29,25 +28,25 @@ namespace BoredCareers.Controllers {
}
[HttpPost]
public async Task<IActionResult> SetCompany([FromBody] Company company, [FromQuery] bool newCompany = false) {
public async Task<IActionResult> SetCompany([FromBody] Company company) {
if (isLoggedIn()) {
if (newCompany) {
Company? test = await _databaseService.GetCompany(Convert.ToInt32(company.ID));
if (test == null) {
company.ID = await _databaseService.SetCompany(company);
Company? test = await _databaseService.GetCompany(Convert.ToInt32(company.ID));
if (test == null) {
company.ID = await _databaseService.SetCompany(company);
await _databaseService.SetEmployee(new Employee() {
AccountID = getLoggedInUserID(),
AccountName = getLoggedInUser().UserName,
AccountEmail = getLoggedInUser().Email,
Company = company
});
return Ok();
}
return NotFound("The company already exists");
await _databaseService.SetEmployee(new Employee() {
AccountID = getLoggedInUserID(),
AccountName = getLoggedInUser().UserName,
AccountEmail = getLoggedInUser().Email,
Company = company
});
await SendVerify(Convert.ToInt32(company.ID));
return Ok();
} else {
if (await isLoggedInUserEmployeeOf(Convert.ToInt32(company.ID))) {
if (company.Email != test.Email) {
company.EmailVerified = false;
}
await _databaseService.SetCompany(company);
return Ok();
}
@@ -1,7 +1,6 @@
using Microsoft.AspNetCore.Mvc;
using BoredCareers.Services.DatabaseService;
using BoredCareers.Entities;
using System.Web.Http;
namespace BoredCareers.Controllers {
[ApiController]
@@ -1,7 +1,6 @@
using Microsoft.AspNetCore.Mvc;
using BoredCareers.Services.DatabaseService;
using BoredCareers.Entities;
using System.Web.Http;
namespace BoredCareers.Controllers {
[ApiController]
@@ -1,7 +1,6 @@
using Microsoft.AspNetCore.Mvc;
using BoredCareers.Services.DatabaseService;
using BoredCareers.Entities;
using System.Web.Http;
namespace BoredCareers.Controllers {
[ApiController]
-1
View File
@@ -175,7 +175,6 @@ builder.Services.AddRateLimiter(options => {
////////////////////////////////
builder.Services.AddHostedService<JobCleanupService>();
ResumeService.init();
////////////////////////////////
///// ASPNET Core Function /////
+2 -10
View File
@@ -8,18 +8,10 @@
</PropertyGroup>
<ItemGroup>
<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.Authentication.JwtBearer" Version="9.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.WebApiCompatShim" Version="2.3.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.8" />
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
<PackageReference Include="MySql.Data" Version="9.4.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="HtmlSanitizer" Version="9.0.886" />
</ItemGroup>
<ItemGroup>
-93
View File
@@ -1,93 +0,0 @@
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);
}
}
}