Minimum Salary
-
+
Maximum Salary
-
+
Back
Next
@@ -113,7 +94,7 @@
Description
-
+
Back
Next
diff --git a/src/Client/src/app/pages/main/jobs/editor/jobeditor.component.ts b/src/Client/src/app/pages/main/jobs/editor/jobeditor.component.ts
index 63b61bc..b5522dc 100644
--- a/src/Client/src/app/pages/main/jobs/editor/jobeditor.component.ts
+++ b/src/Client/src/app/pages/main/jobs/editor/jobeditor.component.ts
@@ -15,31 +15,46 @@ import { Company, Employee } from 'app/models/Company';
imports: [ FormsModule, CommonModule, RouterModule ]
})
export class JobEditorComponent {
+ public ErrorMsg: string = "";
@ViewChildren('step') formSteps!: QueryList
>;
currentStep: number = 0;
- public employeeOfList: Employee[] = [];
- public selectedCompany: Company = new Company;
+ public Listing: JobListing = new JobListing();
- public newListing: JobListing = new JobListing();
- public ErrorMsg: string = "";
+ 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");
- this.http.get("api/employee").subscribe({
- next: empOf => {
- if (empOf.length === 0){
- router.navigate(["company/connect"]);
- }
- this.employeeOfList = empOf;
- },
- error: err => {
- this.ErrorMsg = err.error;
+ this.route.queryParams.subscribe(params => {
+ const CompanyID = params['CompanyID'] ? +params['CompanyID'] : null;
+ const JobID = params['JobID'] ? +params['JobID'] : null;
+ if (CompanyID !== null && JobID !== null){
+ this.router.navigate([""]);
+ }else if (CompanyID !== null ){
+ this.mode = "new";
+ this.modeID = CompanyID;
+ }else if(JobID !== null){
+ this.mode = "edit";
+ this.modeID = JobID;
+ }else if (CompanyID === null && JobID === null){
+ this.router.navigate([""]);
+ }
+
+ if (this.mode === "edit") {
+ this.http.get("api/joblisting/" + JobID).subscribe({
+ next: data => {
+ this.Listing = data;
+ },
+ error: err => {
+ this.ErrorMsg = err.error;
+ }
+ });
}
});
- };
+ }
ngAfterViewInit(){
this.formSteps.changes.subscribe(() => {
@@ -70,8 +85,8 @@ export class JobEditorComponent {
this.updateUI();
}
- PostJobListing(jobListing: JobListing){
- jobListing.companyID = this.selectedCompany.id!;
+ PostNewJob(jobListing: JobListing){
+ jobListing.companyID = this.modeID;
this.http.post("api/joblisting", jobListing).subscribe({
next: data => {
this.router.navigate([""]);
@@ -82,4 +97,23 @@ export class JobEditorComponent {
});
}
+ PostEditJob(jobListing: JobListing){
+ this.http.post("api/joblisting", jobListing).subscribe({
+ next: data => {
+ this.router.navigate([""]);
+ },
+ error: err => {
+ this.ErrorMsg = err.error;
+ }
+ });
+ }
+
+ SubmitForm(job: JobListing){
+ if (this.mode === "new"){
+ this.PostNewJob(job);
+ }else if (this.mode === "edit"){
+ this.PostEditJob(job);
+ }
+ }
+
}
\ No newline at end of file
diff --git a/src/Client/src/app/pages/main/jobs/jobs.component.html b/src/Client/src/app/pages/main/jobs/jobs.component.html
index f6bdacc..a92934d 100644
--- a/src/Client/src/app/pages/main/jobs/jobs.component.html
+++ b/src/Client/src/app/pages/main/jobs/jobs.component.html
@@ -3,7 +3,7 @@
{{ cur.title }}
- ${{ cur.salaryMax }} - ${{ cur.salaryMin }}
+ ${{ cur.salaryMin }} - ${{ cur.salaryMax }}
{{ cur.jobType }}
diff --git a/src/Client/src/app/pages/main/jobs/viewer/jobviewer.component.css b/src/Client/src/app/pages/main/jobs/viewer/jobviewer.component.css
index c357862..e9653e1 100644
--- a/src/Client/src/app/pages/main/jobs/viewer/jobviewer.component.css
+++ b/src/Client/src/app/pages/main/jobs/viewer/jobviewer.component.css
@@ -1,11 +1,91 @@
-.job-frame {
-
+.company-details {
+ background-color: #5c3030;
}
-.job-warning {
+.company-details::after {
+ content: "";
+ display: block;
+ height: 50px;
+ clear: both;
+}
+.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;
+}
+
+.content-desc h1 {
+ margin: 0;
+ font-size: 20px;
+}
+
+.content-button {
+ display: flex;
+ justify-content: center;
+}
+
+.content-button span {
+ align-content: center;
}
.job-details {
-
+ background-color: #3c3c3c;
+}
+
+.job-timestamp {
+ width: 100%;
+}
+
+.job-timestamp h1 {
+ margin: 0;
}
\ No newline at end of file
diff --git a/src/Client/src/app/pages/main/jobs/viewer/jobviewer.component.html b/src/Client/src/app/pages/main/jobs/viewer/jobviewer.component.html
index 23243a9..3da246a 100644
--- a/src/Client/src/app/pages/main/jobs/viewer/jobviewer.component.html
+++ b/src/Client/src/app/pages/main/jobs/viewer/jobviewer.component.html
@@ -1,21 +1,27 @@
-
{{ jobsCompany.name }}
-
- {{ jobsCompany.email }}
- {{ jobsCompany.websiteURL }}
-
- {{ jobsCompany.logo }}
- {{ jobsCompany.phone }}
-
- {{ jobsCompany.city }}
- {{ jobsCompany.stateOrRegion }}
- {{ jobsCompany.country }}
- {{ jobsCompany.postalCode }}
-
- {{ jobsCompany.description }}
-
+
+
+
+
{{ jobsCompany.name }}
+
+
+
+
{{ jobsCompany.city }}, {{ jobsCompany.stateOrRegion }} {{ jobsCompany.postalCode }}
+
+
+
{{ line }}
+
+
+
+
Opened: {{ selectedJob.createdTime }}
+ Modified: {{ selectedJob.modifiedTime }}
+
THIS JOB POSTING IS CLOSED
@@ -35,8 +41,5 @@
{{ selectedJob.postalCode }}
{{ selectedJob.description }}
-
- {{ selectedJob.createdTime }}
- {{ selectedJob.modifiedTime }}
\ No newline at end of file
diff --git a/src/Server/Controllers/CompanyController.cs b/src/Server/Controllers/CompanyController.cs
index c546bf8..d27bb70 100644
--- a/src/Server/Controllers/CompanyController.cs
+++ b/src/Server/Controllers/CompanyController.cs
@@ -2,19 +2,25 @@ using Microsoft.AspNetCore.Mvc;
using BoredCareers.Services.DatabaseService;
using BoredCareers.Entities;
using System.Web.Http;
+using BoredCareers.Services;
namespace BoredCareers.Controllers {
[ApiController]
[Route("api/company")]
public class CompanyController : MistoxControllerBase {
- public CompanyController(DatabaseService db) : base(db) {}
+ EmailService _emailContext;
+
+ public CompanyController(DatabaseService db, EmailService emailContext) : base(db) {
+ _emailContext = emailContext;
+ }
[HttpGet]
public async Task
GetCompany(int CompanyID) {
if (isLoggedIn()) {
Company? company = await _databaseService.GetCompany(CompanyID);
if (company != null) {
+ company.EmailToken = "";
return Ok(company);
}
return NotFound("Company doesn't exist");
@@ -59,6 +65,57 @@ namespace BoredCareers.Controllers {
return NotFound("Not logged in");
}
- }
+ [HttpGet("sendverifyemail")]
+ public async Task> SendVerify([FromQuery] int CompanyID) {
+ try {
+ string key = "v" + CompanyID;
+ // Stop from sending multiple emails quickly
+ if (_emailContext._SentEmails.ContainsKey(key)) {
+ DateTime PreviousSentTime = _emailContext._SentEmails.GetValueOrDefault(key);
+ if (PreviousSentTime.AddMinutes(5) > DateTime.Now) {
+ return NotFound("Cannot sent another verify email until 5 minutes has elapsed");
+ } else {
+ _emailContext._SentEmails.Remove(key);
+ }
+ }
+ Company? test = await _databaseService.GetCompany(CompanyID);
+ if (test != null) {
+ test.EmailToken = Guid.NewGuid().ToString();
+ await _databaseService.SetCompany(test);
+ string EmailContents = EmailService.CompanyVerifyEmailSubject;
+ EmailContents = Substitue(EmailContents, "@CompanyName", test.Name);
+ EmailContents = Substitue(EmailContents, "@ID", CompanyID.ToString());
+ EmailContents = Substitue(EmailContents, "@VerifyPassword", test.EmailToken);
+
+ string result = _emailContext.Send(test.Email, EmailService.CompanyVerifyEmailSubject, EmailContents);
+ _emailContext._SentEmails.Add(key, DateTime.Now);
+ return Redirect("/");
+ }
+ return NotFound("Account not found");
+ } catch (Exception) {
+ return NotFound("An internal server error has occured");
+ }
+ }
+
+ [HttpGet("verifyemail")]
+ public async Task> VerifyEmail([FromQuery] int CompanyID, [FromQuery] string EmailToken) {
+ try {
+ Company? test = await _databaseService.GetCompany(CompanyID);
+ if (test != null) {
+ if (test.EmailToken == EmailToken) {
+ test.EmailToken = "";
+ test.EmailVerified = true;
+ await _databaseService.SetCompany(test);
+ return Redirect("/");
+ }
+ return BadRequest("The token isn't valid");
+ }
+ return BadRequest("Account not found"); ;
+ } catch {
+ return BadRequest("An internal server error has occured");
+ }
+ }
+
+ }
}
diff --git a/src/Server/Entities/Company.cs b/src/Server/Entities/Company.cs
index c6fbcb8..f30d2e1 100644
--- a/src/Server/Entities/Company.cs
+++ b/src/Server/Entities/Company.cs
@@ -5,6 +5,7 @@ namespace BoredCareers.Entities {
public string Name { get; set; } = "";
public string Email { get; set; } = "";
public bool EmailVerified { get; set; } = false;
+ public string EmailToken { get; set; } = "";
public string WebsiteURL { get; set; } = "";
public string Logo { get; set; } = "";
public int JobsClosedSuccessful { get; set; }
diff --git a/src/Server/Services/BackgroundServices/JobCleanupService.cs b/src/Server/Services/BackgroundServices/JobCleanupService.cs
index fbd30fb..d943280 100644
--- a/src/Server/Services/BackgroundServices/JobCleanupService.cs
+++ b/src/Server/Services/BackgroundServices/JobCleanupService.cs
@@ -11,6 +11,17 @@ namespace BoredCareers.Services.TimerService {
_em = em;
}
+ public string Substitue(string message, string subString, string Replacement) {
+ for (int i = 0; i < (message.Length - subString.Length); i++) {
+ if (message.Substring(i, subString.Length) == subString) {
+ string before = message.Substring(0, i);
+ string after = message.Substring(i + subString.Length);
+ return before + Replacement + after;
+ }
+ }
+ return message;
+ }
+
protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
while (!stoppingToken.IsCancellationRequested) {
try {
@@ -37,7 +48,10 @@ namespace BoredCareers.Services.TimerService {
string[] emails = await _db.GetApplicationResponseEmailFromJobListing(listing.JobListingID);
foreach (string email in emails) {
// Send Notify Email
- _em.Send(email, EmailService.JobAutoClosedSubject, EmailService.JobAutoClosedEmail);
+ string emailbody = EmailService.JobAutoClosedBody;
+ //Substitue(emailbody, "@job", listing.JobListingID);
+
+ _em.Send(email, EmailService.JobAutoClosedSubject, emailbody);
}
}
diff --git a/src/Server/Services/DatabaseService/Company.cs b/src/Server/Services/DatabaseService/Company.cs
index 5aaad81..5e6d334 100644
--- a/src/Server/Services/DatabaseService/Company.cs
+++ b/src/Server/Services/DatabaseService/Company.cs
@@ -26,6 +26,7 @@ namespace BoredCareers.Services.DatabaseService {
string _name = reader.GetString("Name");
string _email = reader.GetString("Email");
bool _emailVerified = reader.GetBoolean("EmailVerified");
+ string _emailtoken = reader.GetString("EmailToken");
string _websiteurl = reader.GetString("WebsiteURL");
string _logo = Encoding.UTF8.GetString((byte[])reader["Logo"]);
int _jobsclosedsuccessful = reader.GetInt32("JobsClosedSuccessful");
@@ -42,6 +43,7 @@ namespace BoredCareers.Services.DatabaseService {
Name = _name,
Email = _email,
EmailVerified = _emailVerified,
+ EmailToken = _emailtoken,
WebsiteURL = _websiteurl,
Logo = _logo,
JobsAutoClosed = _jobsautoclosed,
@@ -64,13 +66,14 @@ namespace BoredCareers.Services.DatabaseService {
await connection.OpenAsync();
string command = @"
INSERT INTO Company
- (ID,Name,Email,EmailVerified,WebsiteURL,Logo,JobsClosedSuccessful,JobsAutoClosed,Phone,PostalCode,Country,StateOrRegion,City,Description)
+ (ID,Name,Email,EmailVerified,EmailToken,WebsiteURL,Logo,JobsClosedSuccessful,JobsAutoClosed,Phone,PostalCode,Country,StateOrRegion,City,Description)
VALUES
- (@ID,@Name,@Email,@EmailVerified,@WebsiteURL,@Logo,@JobsClosedSuccessful,@JobsAutoClosed,@Phone,@PostalCode,@Country,@StateOrRegion,@City,@Description)
+ (@ID,@Name,@Email,@EmailVerified,@EmailToken,@WebsiteURL,@Logo,@JobsClosedSuccessful,@JobsAutoClosed,@Phone,@PostalCode,@Country,@StateOrRegion,@City,@Description)
ON DUPLICATE KEY UPDATE
Name = @Name,
Email = @Email,
EmailVerified = @EmailVerified,
+ EmailToken = @EmailToken,
WebsiteURL = @WebsiteURL,
Logo = @Logo,
JobsClosedSuccessful = @JobsClosedSuccessful,
@@ -90,6 +93,7 @@ namespace BoredCareers.Services.DatabaseService {
cmd.Parameters.AddWithValue("@Name", company.Name);
cmd.Parameters.AddWithValue("@Email", company.Email);
cmd.Parameters.AddWithValue("@EmailVerified", company.EmailVerified);
+ cmd.Parameters.AddWithValue("@EmailToken", company.EmailToken);
cmd.Parameters.AddWithValue("@WebsiteURL", company.WebsiteURL);
cmd.Parameters.AddWithValue("@Logo", Encoding.UTF8.GetBytes(company.Logo));
cmd.Parameters.AddWithValue("@JobsClosedSuccessful", company.JobsClosedSuccessful);
diff --git a/src/Server/Services/DatabaseService/JobListing.cs b/src/Server/Services/DatabaseService/JobListing.cs
index 18fa04a..f23b28a 100644
--- a/src/Server/Services/DatabaseService/JobListing.cs
+++ b/src/Server/Services/DatabaseService/JobListing.cs
@@ -73,7 +73,8 @@ namespace BoredCareers.Services.DatabaseService {
string command = @"
SELECT *
FROM JobListing
- WHERE CompanyID = @CompanyID;
+ WHERE IsDeleted = FALSE
+ AND CompanyID = @CompanyID;
";
MySqlCommand cmd = new MySqlCommand(command, connection);
diff --git a/src/Server/Services/EmailService/CompanyVerifyEmail.cs b/src/Server/Services/EmailService/CompanyVerifyEmail.cs
new file mode 100755
index 0000000..ccaecca
--- /dev/null
+++ b/src/Server/Services/EmailService/CompanyVerifyEmail.cs
@@ -0,0 +1,52 @@
+namespace BoredCareers.Services {
+ public partial class EmailService {
+
+// @UserName
+// @VerifyPassword
+// https://mistox.com/api/account/verifyemail?UserName=@UserName&Guid=@VerifyPassword
+
+ public static string CompanyVerifyEmailSubject = "Verify Your Email Address";
+ public static string CompanyVerifyEmailBody = @"
+
+
+
+
+
+ Verify Your Email
+
+
+
+
+
+
+
+
+ Verify Email Request
+
+
+
+
+ Hi @CompanyName,
+ Thank you for making an account with us:
+ In order to start using your account we need to verify your email address by clicking the link below:
+
+ Verify Email
+
+ If you didn't create an account please ignore this email.
+ Best regards
+
+
+
+
+ If you have any questions, feel free to contact support .
+
+
+
+
+
+
+
+";
+
+ }
+}
\ No newline at end of file
diff --git a/src/Server/Services/EmailService/JobAutoCloseEmail.cs b/src/Server/Services/EmailService/JobAutoCloseEmail.cs
index a1055f3..00aeb87 100755
--- a/src/Server/Services/EmailService/JobAutoCloseEmail.cs
+++ b/src/Server/Services/EmailService/JobAutoCloseEmail.cs
@@ -6,7 +6,7 @@ namespace BoredCareers.Services {
// https://mistox.com/api/account/verifyemail?UserName=@UserName&Guid=@VerifyPassword
public static string JobAutoClosedSubject = "Verify Your Email Address";
- public static string JobAutoClosedEmail = @"
+ public static string JobAutoClosedBody = @"