diff --git a/ToDo.yaml b/ToDo.yaml index 060e44a..855e616 100755 --- a/ToDo.yaml +++ b/ToDo.yaml @@ -21,6 +21,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 @@ -45,14 +48,14 @@ Client: Setup QueryParam's for Edit and New Edit employees not implimented yet + resume/editor: + Not fully tested yet + Company: Need to impliment Add employee Need to impliment Remove employee 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: Add Applied Jobs Table \ No newline at end of file diff --git a/database/mistox.sql b/database/mistox.sql index dee3b06..035a927 100755 --- a/database/mistox.sql +++ b/database/mistox.sql @@ -6,6 +6,7 @@ USE `boredcareers`; CREATE TABLE IF NOT EXISTS `Resume` ( `ID` int NOT NULL AUTO_INCREMENT, `AccountID` int NOT NULL, + `Title` varchar(100) NOT NULL, `Name` varchar(100) NOT NULL, `Field` varchar(100) DEFAULT NULL, `Email` varchar(255) NOT NULL, @@ -47,6 +48,7 @@ CREATE TABLE IF NOT EXISTS `Resume` ( CREATE TABLE IF NOT EXISTS `ResumeMilitary` ( `ID` int NOT NULL AUTO_INCREMENT, `ResumeID` int NOT NULL, + `Veteran` boolean DEFAULT 0, `Country` char(2) NOT NULL, `Rank` varchar(50) NOT NULL, `DateStarted` date NOT NULL, diff --git a/src/Client/src/app/app.html b/src/Client/src/app/app.html index cc27886..0d023ef 100644 --- a/src/Client/src/app/app.html +++ b/src/Client/src/app/app.html @@ -1,25 +1,30 @@
JOB BOARD - RESUMES - COMPANIES + @if (auth.isLoggedIn){ + RESUMES + COMPANIES + }
-
- - -
-
- - - - - - - -
+ @if (auth.isLoggedIn){ +
+ + +
+ } @else { +
+ @if (devMode){ + + + } @else { + + + } +
+ }
diff --git a/src/Client/src/app/app.routes.ts b/src/Client/src/app/app.routes.ts index df088d1..b221d22 100644 --- a/src/Client/src/app/app.routes.ts +++ b/src/Client/src/app/app.routes.ts @@ -7,6 +7,7 @@ import { JobEditorComponent } from './pages/jobs/editor/jobeditor.component'; import { CompanyEditorComponent } from './pages/company/editor/editor.component'; import { JobViewerComponent } from './pages/jobs/viewer/jobviewer.component'; import { CompanyComponent } from './pages/company/company.component'; +import { ResumesEditorComponent } from './pages/resumes/editor/editor.component'; export const routes: Routes = [ @@ -15,6 +16,7 @@ export const routes: Routes = [ // Resumes { path: "resumes", component: ResumesComponent }, + { path: "resumes/editor", component: ResumesEditorComponent }, // Jobs { path: "jobs", component: JobsComponent }, diff --git a/src/Client/src/app/models/Resume.ts b/src/Client/src/app/models/Resume.ts index c917a5a..92826d8 100644 --- a/src/Client/src/app/models/Resume.ts +++ b/src/Client/src/app/models/Resume.ts @@ -1,6 +1,9 @@ + export class Resume { public id: number | null = null; - public accountID: number = 0; + public accountID: number | null = null; + + public title: string = ""; public name: string = ""; public field: string = ""; public email: string = ""; @@ -17,11 +20,13 @@ export class Resume { public languages: ResumeLanguage[] = []; public certification: ResumeCertification[] = []; public projects: ResumeProject[] = []; + public trackUUID: string = crypto.randomUUID(); } export class ResumeExperience { public id: number | null = null; - public resumeID: number = 0; + public resumeID: number | null = null; + public jobTitle: string = ""; public company: string = ""; public postalCode: string = ""; @@ -32,37 +37,46 @@ export class ResumeExperience { public stillEmployed: boolean = false; public dateEnded: Date = new Date(); public experienceBullets: ResumeExperienceBullet[] = []; + public trackUUID: string = crypto.randomUUID(); } export class ResumeExperienceBullet { public id: number | null = null; - public resumeID: number = 0; - public resumeExperienceID: number = 0; + public resumeID: number | null = null; + public resumeExperienceID: number | null = null; + public jobFunction: string = ""; + public trackUUID: string = crypto.randomUUID(); } export class ResumeMilitary { public id: number | null = null; - public resumeID: number = 0; + public resumeID: number | null = null; + + public veteran: boolean = false; public country: string = ""; public rank: string = ""; public dateStarted: Date = new Date(); public stillServing: boolean = false; public dateEnded: Date = new Date(); public millitaryBullets: ResumeMilitaryBullet[] = []; + public trackUUID: string = crypto.randomUUID(); } export class ResumeMilitaryBullet { public id: number | null = null; - public resumeID: number = 0; - public resumeMilitaryID: number = 0; + public resumeID: number | null = null; + public resumeMilitaryID: number | null = null; + public achievement: string = ""; public description: string = ""; + public trackUUID: string = crypto.randomUUID(); } export class ResumeEducation { public id: number | null = null; - public resumeID: number = 0; + public resumeID: number | null = null; + public degreeType: string = ""; public degreeField: string = ""; public school: string = ""; @@ -73,34 +87,43 @@ export class ResumeEducation { public dateStarted: Date = new Date(); public stillStudying: boolean = false; public dateEnded: Date = new Date(); + public trackUUID: string = crypto.randomUUID(); } export class ResumeSkill { public id: number | null = null; - public resumeID: number = 0; + public resumeID: number | null = null; + public name: string = ""; public description: string = ""; + public trackUUID: string = crypto.randomUUID(); } export class ResumeLanguage { public id: number | null = null; - public resumeID: number = 0; + public resumeID: number | null = null; + public language: string = ""; public proficiency: string = ""; + public trackUUID: string = crypto.randomUUID(); } export class ResumeCertification { public id: number | null = null; - public resumeID: number = 0; + public resumeID: number | null = null; + public name: string = ""; public verificationURL: string = ""; public description: string = ""; + public trackUUID: string = crypto.randomUUID(); } export class ResumeProject { public id: number | null = null; - public resumeID: number = 0; + public resumeID: number | null = null; + public name: string = ""; public url: string = ""; public description: string = ""; + public trackUUID: string = crypto.randomUUID(); } \ No newline at end of file diff --git a/src/Client/src/app/pages/company/company.component.ts b/src/Client/src/app/pages/company/company.component.ts index d2955c9..45ce872 100644 --- a/src/Client/src/app/pages/company/company.component.ts +++ b/src/Client/src/app/pages/company/company.component.ts @@ -28,6 +28,11 @@ export class CompanyComponent { constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) { this.title.setTitle("Companies | BoredCareers"); + + if (!auth.isLoggedIn){ + router.navigate(["/"]); + } + http.get("api/employee/").subscribe({ next: data => { this.Employers = data; diff --git a/src/Client/src/app/pages/company/editor/editor.component.ts b/src/Client/src/app/pages/company/editor/editor.component.ts index 3c21b7c..9a89e66 100644 --- a/src/Client/src/app/pages/company/editor/editor.component.ts +++ b/src/Client/src/app/pages/company/editor/editor.component.ts @@ -25,6 +25,10 @@ export class CompanyEditorComponent { constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) { this.title.setTitle("Company - Editor | BoredCareers"); + if (!auth.isLoggedIn){ + router.navigate(["/"]); + } + // Query param CompanyID -> Edit // Query param null -> New }; diff --git a/src/Client/src/app/pages/jobs/editor/jobeditor.component.ts b/src/Client/src/app/pages/jobs/editor/jobeditor.component.ts index 6033f17..a02bd83 100644 --- a/src/Client/src/app/pages/jobs/editor/jobeditor.component.ts +++ b/src/Client/src/app/pages/jobs/editor/jobeditor.component.ts @@ -27,6 +27,10 @@ export class JobEditorComponent { constructor( private http: HttpClient, private router: Router, private route: ActivatedRoute, private title: Title, public auth: Authentication ) { this.title.setTitle("Jobs - Editor | BoredCareers"); + if (!auth.isLoggedIn){ + router.navigate(["/"]); + } + this.route.queryParams.subscribe(params => { const CompanyID = params['CompanyID'] ? +params['CompanyID'] : null; const JobID = params['JobID'] ? +params['JobID'] : null; diff --git a/src/Client/src/app/pages/resumes/editor/editor.component.css b/src/Client/src/app/pages/resumes/editor/editor.component.css new file mode 100644 index 0000000..0daf73e --- /dev/null +++ b/src/Client/src/app/pages/resumes/editor/editor.component.css @@ -0,0 +1,10 @@ +.resume-section { + background-color: #DDDDDD; + margin: 10px; +} + +.resume-sub-section { + border: 1px solid #666666; + margin: 5px; + padding: 10px; +} \ No newline at end of file diff --git a/src/Client/src/app/pages/resumes/editor/editor.component.html b/src/Client/src/app/pages/resumes/editor/editor.component.html new file mode 100644 index 0000000..9cc4cc0 --- /dev/null +++ b/src/Client/src/app/pages/resumes/editor/editor.component.html @@ -0,0 +1,145 @@ +
+ + +
+ + + + + + + + +

Public:

+
+ + +
+ + @for(experience of resume.experience; track experience.trackUUID ){ +
+ + + + + + + + + @if(!experience.stillEmployed){ + + } + + @for(bullet of experience.experienceBullets; track bullet.trackUUID){ +
+ + +
+ } + +
+ } +
+ + +
+

Is Veteran:

+ @if(resume.military.veteran){ + + + +

Still Serving:

+ @if (!resume.military.stillServing){ + + } + + @for(military of resume.military.millitaryBullets; track military.trackUUID ){ +
+ + + +
+ } + } +
+ + +
+ + @for(education of resume.education; track education.trackUUID){ +
+ + + + + + + + + + @if (!education.stillStudying){ + + } + +
+ } +
+ + +
+ + @for(skill of resume.skills; track skill.trackUUID){ +
+ + + +
+ } +
+ + +
+ + @for(language of resume.languages; track language.trackUUID){ +
+ + + +
+ } +
+ + + +
+ + @for(cert of resume.certification; track cert.trackUUID){ +
+ + + + +
+ } +
+ + +
+ + @for(proj of resume.projects; track proj.trackUUID){ +
+ + + + +
+ } +
+ + @if (isNewResume){ + + } @else { + + } + +
\ No newline at end of file diff --git a/src/Client/src/app/pages/resumes/editor/editor.component.ts b/src/Client/src/app/pages/resumes/editor/editor.component.ts new file mode 100644 index 0000000..bbbbd10 --- /dev/null +++ b/src/Client/src/app/pages/resumes/editor/editor.component.ts @@ -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("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 + @for(resume of myResumes; track myResumes.length){ + + } + +
+ - @if (auth.isLoggedIn){ -
- -
- } \ No newline at end of file +
+ +
\ No newline at end of file diff --git a/src/Client/src/app/pages/resumes/resumes.component.ts b/src/Client/src/app/pages/resumes/resumes.component.ts index 4783dd1..63f24e5 100644 --- a/src/Client/src/app/pages/resumes/resumes.component.ts +++ b/src/Client/src/app/pages/resumes/resumes.component.ts @@ -15,14 +15,19 @@ import { Authentication } from 'app/services/Authentication'; }) 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 ) { this.title.setTitle("Resumes | BoredCareers"); + if (!auth.isLoggedIn){ + router.navigate(["/"]); + } + this.http.get("api/resume").subscribe({ next: data => { - this.ResumePage = data; + this.myResumes = data; }, error: err => { console.log("Error fetching resumes: " + err.error); @@ -30,4 +35,15 @@ export class ResumesComponent { }); }; + changeSelectedResume(ResumeID: number){ + this.http.get("api/resume?ResumeID=" + ResumeID).subscribe({ + next: data => { + this.currentResume = data; + }, + error: err => { + console.log("Error fetching resume ID: " + err.error); + } + }); + } + } \ No newline at end of file diff --git a/src/Client/src/app/services/Authentication.ts b/src/Client/src/app/services/Authentication.ts index 4e693e0..ed676de 100644 --- a/src/Client/src/app/services/Authentication.ts +++ b/src/Client/src/app/services/Authentication.ts @@ -1,7 +1,7 @@ import { Injectable } from "@angular/core"; import { Account } from "../models/Account"; import { BehaviorSubject, Observable } from "rxjs"; -import { HttpClient, HttpHeaders, HttpParams } from "@angular/common/http"; +import { HttpClient } from "@angular/common/http"; @Injectable({ providedIn: 'root' }) export class Authentication{ diff --git a/src/Server/Entities/Resume.cs b/src/Server/Entities/Resume.cs index b093c3d..8457400 100644 --- a/src/Server/Entities/Resume.cs +++ b/src/Server/Entities/Resume.cs @@ -2,6 +2,7 @@ namespace BoredCareers.Entities { public class Resume { public int? ID { get; set; } // PK public int AccountID { get; set; } // FK + public string Title { get; set; } = ""; public string Name { get; set; } = ""; public string Field { get; set; } = ""; public string Email { get; set; } = ""; @@ -45,6 +46,7 @@ namespace BoredCareers.Entities { public class ResumeMilitary { public int? ID { get; set; } // PK public int ResumeID { get; set; } // FK + public bool Veteran { get; set; } = false; public string Country { get; set; } = ""; // 2 Letter Country Code public string Rank { get; set; } = ""; public DateTime DateStarted { get; set; } = new DateTime(); diff --git a/src/Server/Program.cs b/src/Server/Program.cs index b4435a7..4301875 100755 --- a/src/Server/Program.cs +++ b/src/Server/Program.cs @@ -175,6 +175,7 @@ builder.Services.AddRateLimiter(options => { //////////////////////////////// builder.Services.AddHostedService(); +ResumeService.init(); //////////////////////////////// ///// ASPNET Core Function ///// diff --git a/src/Server/Server.csproj b/src/Server/Server.csproj index c14307e..0225aff 100755 --- a/src/Server/Server.csproj +++ b/src/Server/Server.csproj @@ -8,15 +8,18 @@ - - - + + + + + + diff --git a/src/Server/Services/DatabaseService/Resume.cs b/src/Server/Services/DatabaseService/Resume.cs index 86eda81..35cf14e 100644 --- a/src/Server/Services/DatabaseService/Resume.cs +++ b/src/Server/Services/DatabaseService/Resume.cs @@ -27,6 +27,7 @@ namespace BoredCareers.Services.DatabaseService { int _id = reader.GetInt32("ID"); int _accountid = reader.GetInt32("AccountID"); + string _title = reader.GetString("Title"); string _name = reader.GetString("Name"); string _field = reader.GetString("Field"); string _email = reader.GetString("Email"); @@ -40,6 +41,7 @@ namespace BoredCareers.Services.DatabaseService { resumes.Add( new Resume() { ID = _id, AccountID = _accountid, + Title = _title, Name = _name, Field = _field, Email = _email, diff --git a/src/Server/Services/DatabaseService/ResumeParts/GetResumeParts.cs b/src/Server/Services/DatabaseService/ResumeParts/GetResumeParts.cs index 603bdcc..016556d 100644 --- a/src/Server/Services/DatabaseService/ResumeParts/GetResumeParts.cs +++ b/src/Server/Services/DatabaseService/ResumeParts/GetResumeParts.cs @@ -10,6 +10,7 @@ namespace BoredCareers.Services.DatabaseService { if (reader == null) { break; } int _id = reader.GetInt32("ID"); int _accountid = reader.GetInt32("AccountID"); + string _title = reader.GetString("Title"); string _name = reader.GetString("Name"); string _field = reader.GetString("Field"); string _email = reader.GetString("Email"); @@ -22,6 +23,7 @@ namespace BoredCareers.Services.DatabaseService { return new Resume() { ID = _id, AccountID = _accountid, + Title = _title, Name = _name, Field = _field, Email = _email, @@ -112,6 +114,7 @@ namespace BoredCareers.Services.DatabaseService { if (reader == null) { break; } int _id = reader.GetInt32("ID"); int _resumeid = reader.GetInt32("ResumeID"); + bool _veteran = reader.GetBoolean("Veteran"); string _country = reader.GetString("Country"); string _rank = reader.GetString("Rank"); DateTime _datestarted = reader.GetDateTime("DateStarted"); @@ -120,6 +123,7 @@ namespace BoredCareers.Services.DatabaseService { military = new ResumeMilitary() { ID = _id, ResumeID = _resumeid, + Veteran = _veteran, Country = _country, Rank = _rank, DateStarted = _datestarted, diff --git a/src/Server/Services/DatabaseService/ResumeParts/SetResumeParts.cs b/src/Server/Services/DatabaseService/ResumeParts/SetResumeParts.cs index 55ff142..85c993d 100644 --- a/src/Server/Services/DatabaseService/ResumeParts/SetResumeParts.cs +++ b/src/Server/Services/DatabaseService/ResumeParts/SetResumeParts.cs @@ -7,11 +7,12 @@ namespace BoredCareers.Services.DatabaseService { public async Task SetResume(MySqlConnection connection, Resume resume) { string command = @" 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 - (@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 AccountID = @AccountID, + Title = @Title, Name = @Name, Field = @Field, Email = @Email, @@ -26,6 +27,7 @@ namespace BoredCareers.Services.DatabaseService { MySqlCommand cmd = new MySqlCommand(command, connection); cmd.Parameters.AddWithValue("@ID", resume.ID); cmd.Parameters.AddWithValue("@AccountID", resume.AccountID); + cmd.Parameters.AddWithValue("@Title", resume.Title); cmd.Parameters.AddWithValue("@Name", resume.Name); cmd.Parameters.AddWithValue("@Field", resume.Field); cmd.Parameters.AddWithValue("@Email", resume.Email); @@ -124,11 +126,12 @@ namespace BoredCareers.Services.DatabaseService { public async Task SetResumeMilitary(MySqlConnection connection, ResumeMilitary military) { string command = @" INSERT INTO Resume - (ID,ResumeID,Country,Rank,DateStarted,StillServing,DateEnded) + (ID,ResumeID,Veteran,Country,Rank,DateStarted,StillServing,DateEnded) VALUES - (@ID,@ResumeID,@Country,@Rank,@DateStarted,@StillServing,@DateEnded) + (@ID,@ResumeID,@Veteran,@Country,@Rank,@DateStarted,@StillServing,@DateEnded) ON DUPLICATE KEY UPDATE ResumeID = @ResumeID, + Veteran = @Veteran, Country = @Country, Rank = @Rank, DateStarted = @DateStarted, @@ -139,6 +142,7 @@ namespace BoredCareers.Services.DatabaseService { MySqlCommand cmd = new MySqlCommand(command, connection); cmd.Parameters.AddWithValue("@ID", military.ID); cmd.Parameters.AddWithValue("@ResumeID", military.ResumeID); + cmd.Parameters.AddWithValue("@Veteran", military.Veteran); cmd.Parameters.AddWithValue("@Country", military.Country); cmd.Parameters.AddWithValue("@Rank", military.Rank); cmd.Parameters.AddWithValue("@DateStarted", military.DateStarted.ToUniversalTime()); diff --git a/src/Server/Services/ResumeService.cs b/src/Server/Services/ResumeService.cs new file mode 100644 index 0000000..92686f6 --- /dev/null +++ b/src/Server/Services/ResumeService.cs @@ -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); + } + } +} \ No newline at end of file