()
25 | .ForMember(dest => dest.JobTitle, opt => opt.MapFrom(src => src.Job.Title));
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/backend/backend/backend.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net7.0
5 | enable
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | all
16 | runtime; build; native; contentfiles; analyzers; buildtransitive
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/frontend/src/components/companies/CompaniesGrid.component.tsx:
--------------------------------------------------------------------------------
1 | import "./companies-grid.scss";
2 | import { Box } from "@mui/material";
3 | import { DataGrid } from "@mui/x-data-grid";
4 | import { GridColDef } from "@mui/x-data-grid/models";
5 | import moment from "moment";
6 | import React from "react";
7 | import { ICompany } from "../../types/global.typing";
8 |
9 |
10 | const column: GridColDef[] = [
11 | { field: "id", headerName: "ID", width: 100 },
12 | { field: "name", headerName: "Name", width: 200 },
13 | { field: "size", headerName: "Size", width: 150 },
14 | {
15 | field: "createdAt",
16 | headerName: "Creation Time",
17 | width: 200,
18 | renderCell: (params) => moment(params.row.createdAt).format("YYYY-MM-DD"),
19 | },
20 | ];
21 |
22 | interface ICompaniesGridProps {
23 | data: ICompany[];
24 | }
25 |
26 | const CompaniesGrid = ({ data }: ICompaniesGridProps) => {
27 | return (
28 |
29 | row.id} rowHeight={50} />
30 |
31 | );
32 | };
33 |
34 | export default CompaniesGrid;
35 |
--------------------------------------------------------------------------------
/frontend/src/components/jobs/JobsGrid.component.tsx:
--------------------------------------------------------------------------------
1 | import "./jobs-grid.scss";
2 | import { Box } from "@mui/material";
3 | import { DataGrid } from "@mui/x-data-grid";
4 | import { GridColDef } from "@mui/x-data-grid/models";
5 | import moment from "moment";
6 | import React from "react";
7 | import { IJob } from "../../types/global.typing";
8 |
9 | const column: GridColDef[] = [
10 | { field: "id", headerName: "ID", width: 100 },
11 | { field: "title", headerName: "Title", width: 500 },
12 | { field: "level", headerName: "Level", width: 150 },
13 | { field: "companyName", headerName: "Company Name", width: 150 },
14 | {
15 | field: "createdAt",
16 | headerName: "Creation Time",
17 | width: 150,
18 | renderCell: (params) => moment(params.row.createdAt).fromNow(),
19 | },
20 | ];
21 |
22 | interface IJobsGridProps {
23 | data: IJob[];
24 | }
25 |
26 | const JobsGrid = ({ data }: IJobsGridProps) => {
27 | return (
28 |
29 | row.id} rowHeight={50} />
30 |
31 | );
32 | };
33 |
34 | export default JobsGrid;
35 |
--------------------------------------------------------------------------------
/frontend/src/pages/home/Home.page.tsx:
--------------------------------------------------------------------------------
1 | import "./home.scss";
2 |
3 | const Home = () => {
4 | return (
5 |
6 |
Welcome To Website
7 |
8 |
9 |
10 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Impedit fugiat iusto explicabo voluptatum,
11 | blanditiis libero eum tempora excepturi inventore labore nesciunt cupiditate commodi beatae. Neque, totam
12 | tempore. Esse itaque vitae, reiciendis dolores provident placeat sequi nam pariatur praesentium quaerat
13 | autem libero quasi dolorem sapiente aliquid odio dolore maxime repellendus vel incidunt minima? Dolore sequi
14 | ea laudantium fuga autem officia, cum fugit rem voluptates, vel quis aperiam consectetur dolor perspiciatis
15 | labore. Blanditiis hic eaque natus accusantium officiis quam accusamus. Aperiam sed ullam in. Nisi inventore
16 | iste est placeat corrupti? Minima, mollitia hic dolorem porro molestiae nulla itaque incidunt veritatis
17 | sunt. Soluta!
18 |
19 |
20 | );
21 | };
22 |
23 | export default Home;
24 |
--------------------------------------------------------------------------------
/backend/backend.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.4.33213.308
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "backend", "backend\backend.csproj", "{64F7A085-74C7-4BA2-ACCB-55A897DBFBF1}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {64F7A085-74C7-4BA2-ACCB-55A897DBFBF1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {64F7A085-74C7-4BA2-ACCB-55A897DBFBF1}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {64F7A085-74C7-4BA2-ACCB-55A897DBFBF1}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {64F7A085-74C7-4BA2-ACCB-55A897DBFBF1}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {160C4B15-69B2-4622-B35E-3AA6DBF0D77B}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/backend/backend/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/launchsettings.json",
3 | "iisSettings": {
4 | "windowsAuthentication": false,
5 | "anonymousAuthentication": true,
6 | "iisExpress": {
7 | "applicationUrl": "http://localhost:25591",
8 | "sslPort": 44374
9 | }
10 | },
11 | "profiles": {
12 | "http": {
13 | "commandName": "Project",
14 | "dotnetRunMessages": true,
15 | "launchBrowser": true,
16 | "launchUrl": "swagger",
17 | "applicationUrl": "http://localhost:5115",
18 | "environmentVariables": {
19 | "ASPNETCORE_ENVIRONMENT": "Development"
20 | }
21 | },
22 | "https": {
23 | "commandName": "Project",
24 | "dotnetRunMessages": true,
25 | "launchBrowser": true,
26 | "launchUrl": "swagger",
27 | "applicationUrl": "https://localhost:7129;http://localhost:5115",
28 | "environmentVariables": {
29 | "ASPNETCORE_ENVIRONMENT": "Development"
30 | }
31 | },
32 | "IIS Express": {
33 | "commandName": "IISExpress",
34 | "launchBrowser": true,
35 | "launchUrl": "swagger",
36 | "environmentVariables": {
37 | "ASPNETCORE_ENVIRONMENT": "Development"
38 | }
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/backend/backend/Program.cs:
--------------------------------------------------------------------------------
1 | using backend.Core.AutoMapperConfig;
2 | using backend.Core.Context;
3 | using Microsoft.EntityFrameworkCore;
4 | using System.Text.Json.Serialization;
5 |
6 | var builder = WebApplication.CreateBuilder(args);
7 |
8 | // DB Configuration
9 | builder.Services.AddDbContext(options =>
10 | {
11 | options.UseSqlServer(builder.Configuration.GetConnectionString("local"));
12 | });
13 |
14 | // Automapper Configuration
15 | builder.Services.AddAutoMapper(typeof(AutoMapperConfigProfile));
16 |
17 | builder.Services
18 | .AddControllers()
19 | .AddJsonOptions(options =>
20 | {
21 | options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
22 | });
23 |
24 | // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
25 | builder.Services.AddEndpointsApiExplorer();
26 | builder.Services.AddSwaggerGen();
27 |
28 | var app = builder.Build();
29 |
30 | // Configure the HTTP request pipeline.
31 | if (app.Environment.IsDevelopment())
32 | {
33 | app.UseSwagger();
34 | app.UseSwaggerUI();
35 | }
36 |
37 | app.UseCors(options =>
38 | {
39 | options
40 | .AllowAnyOrigin()
41 | .AllowAnyMethod()
42 | .AllowAnyHeader();
43 | });
44 |
45 | app.UseHttpsRedirection();
46 |
47 | app.UseAuthorization();
48 |
49 | app.MapControllers();
50 |
51 | app.Run();
52 |
--------------------------------------------------------------------------------
/backend/backend/Core/Context/ApplicationDbContext.cs:
--------------------------------------------------------------------------------
1 | using backend.Core.Entities;
2 | using Microsoft.EntityFrameworkCore;
3 |
4 | namespace backend.Core.Context
5 | {
6 | public class ApplicationDbContext : DbContext
7 | {
8 | public ApplicationDbContext(DbContextOptions options) : base(options)
9 | {
10 | }
11 |
12 | public DbSet Companies { get; set; }
13 | public DbSet Jobs { get; set; }
14 | public DbSet Candidates { get; set; }
15 |
16 | protected override void OnModelCreating(ModelBuilder modelBuilder)
17 | {
18 | base.OnModelCreating(modelBuilder);
19 |
20 | modelBuilder.Entity()
21 | .HasOne(job => job.Company)
22 | .WithMany(company => company.Jobs)
23 | .HasForeignKey(job => job.CompanyId);
24 |
25 | modelBuilder.Entity()
26 | .HasOne(candidate => candidate.Job)
27 | .WithMany(job => job.Candidates)
28 | .HasForeignKey(candidate => candidate.JobId);
29 |
30 | modelBuilder.Entity()
31 | .Property(company => company.Size)
32 | .HasConversion();
33 |
34 | modelBuilder.Entity()
35 | .Property(job => job.Level)
36 | .HasConversion();
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/frontend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "frontend",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@emotion/react": "^11.10.6",
7 | "@emotion/styled": "^11.10.6",
8 | "@mui/icons-material": "^5.11.11",
9 | "@mui/material": "^5.11.14",
10 | "@mui/x-data-grid": "^6.0.3",
11 | "@testing-library/jest-dom": "^5.16.5",
12 | "@testing-library/react": "^13.4.0",
13 | "@testing-library/user-event": "^13.5.0",
14 | "@types/jest": "^27.5.2",
15 | "@types/node": "^16.18.20",
16 | "@types/react": "^18.0.29",
17 | "@types/react-dom": "^18.0.11",
18 | "axios": "^1.3.4",
19 | "moment": "^2.29.4",
20 | "react": "^18.2.0",
21 | "react-dom": "^18.2.0",
22 | "react-router-dom": "^6.9.0",
23 | "react-scripts": "5.0.1",
24 | "sass": "^1.60.0",
25 | "typescript": "^4.9.5",
26 | "web-vitals": "^2.1.4"
27 | },
28 | "scripts": {
29 | "start": "react-scripts start",
30 | "build": "react-scripts build",
31 | "test": "react-scripts test",
32 | "eject": "react-scripts eject"
33 | },
34 | "eslintConfig": {
35 | "extends": [
36 | "react-app",
37 | "react-app/jest"
38 | ]
39 | },
40 | "browserslist": {
41 | "production": [
42 | ">0.2%",
43 | "not dead",
44 | "not op_mini all"
45 | ],
46 | "development": [
47 | "last 1 chrome version",
48 | "last 1 firefox version",
49 | "last 1 safari version"
50 | ]
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/frontend/src/pages/jobs/Jobs.page.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from "react";
2 | import "./jobs.scss";
3 | import httpModule from "../../helpers/http.module";
4 | import { IJob } from "../../types/global.typing";
5 | import { Button, CircularProgress } from "@mui/material";
6 | import { Add } from "@mui/icons-material";
7 | import { useNavigate } from "react-router-dom";
8 | import JobsGrid from "../../components/jobs/JobsGrid.component";
9 |
10 | const Jobs = () => {
11 | const [jobs, setJobs] = useState([]);
12 | const [loading, setLoading] = useState(false);
13 | const redirect = useNavigate();
14 |
15 | useEffect(() => {
16 | setLoading(true);
17 | httpModule
18 | .get("/Job/Get")
19 | .then((response) => {
20 | setJobs(response.data);
21 | setLoading(false);
22 | })
23 | .catch((error) => {
24 | alert("Error");
25 | console.log(error);
26 | setLoading(false);
27 | });
28 | }, []);
29 |
30 | return (
31 |
32 |
33 |
Jobs
34 |
redirect("/jobs/add")}>
35 |
36 |
37 |
38 | {loading ?
: jobs.length === 0 ?
No Job :
}
39 |
40 | );
41 | };
42 |
43 | export default Jobs;
44 |
--------------------------------------------------------------------------------
/frontend/src/components/candidates/CandidatesGrid.component.tsx:
--------------------------------------------------------------------------------
1 | import './candidates-grid.scss';
2 | import { Box } from "@mui/material";
3 | import { DataGrid } from "@mui/x-data-grid";
4 | import { GridColDef } from "@mui/x-data-grid/models";
5 | import moment from "moment";
6 | import React from "react";
7 | import { baseUrl } from "../../constants/url.constants";
8 | import { ICandidate } from "../../types/global.typing";
9 | import { PictureAsPdf } from "@mui/icons-material";
10 |
11 | const column: GridColDef[] = [
12 | { field: "id", headerName: "ID", width: 100 },
13 | { field: "firstName", headerName: "First Name", width: 120 },
14 | { field: "lastName", headerName: "Last Name", width: 120 },
15 | { field: "email", headerName: "Email", width: 150 },
16 | { field: "phone", headerName: "Phone", width: 150 },
17 | { field: "coverLetter", headerName: "C V", width: 500 },
18 |
19 | {
20 | field: "resumeUrl",
21 | headerName: "Download",
22 | width: 150,
23 | renderCell: (params) => (
24 |
25 |
26 |
27 | ),
28 | },
29 | ];
30 |
31 | interface ICandidatesGridProps {
32 | data: ICandidate[];
33 | }
34 |
35 | const CandidatesGrid = ({ data }: ICandidatesGridProps) => {
36 | return (
37 |
38 | row.id} rowHeight={50} />
39 |
40 | );
41 | };
42 |
43 | export default CandidatesGrid;
44 |
--------------------------------------------------------------------------------
/backend/backend/Controllers/JobController.cs:
--------------------------------------------------------------------------------
1 | using AutoMapper;
2 | using backend.Core.Context;
3 | using backend.Core.Dtos.Job;
4 | using backend.Core.Entities;
5 | using Microsoft.AspNetCore.Http;
6 | using Microsoft.AspNetCore.Mvc;
7 | using Microsoft.EntityFrameworkCore;
8 |
9 | namespace backend.Controllers
10 | {
11 | [Route("api/[controller]")]
12 | [ApiController]
13 | public class JobController : ControllerBase
14 | {
15 | private ApplicationDbContext _context { get; }
16 | private IMapper _mapper { get; }
17 |
18 | public JobController(ApplicationDbContext context, IMapper mapper)
19 | {
20 | _context = context;
21 | _mapper = mapper;
22 | }
23 |
24 | // CRUD
25 |
26 | // Create
27 | [HttpPost]
28 | [Route("Create")]
29 | public async Task CreateJob([FromBody] JobCreateDto dto)
30 | {
31 | var newJob = _mapper.Map(dto);
32 | await _context.Jobs.AddAsync(newJob);
33 | await _context.SaveChangesAsync();
34 |
35 | return Ok("Job Created Successfully");
36 | }
37 |
38 | // Read
39 | [HttpGet]
40 | [Route("Get")]
41 | public async Task>> GetJobs()
42 | {
43 | var jobs = await _context.Jobs.Include(job => job.Company).OrderByDescending(q => q.CreatedAt).ToListAsync();
44 | var convertdJobs = _mapper.Map>(jobs);
45 |
46 | return Ok(convertdJobs);
47 | }
48 |
49 | // Read (Get Job By ID)
50 |
51 | // Update
52 |
53 | // Delete
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/backend/backend/Migrations/20230324222318_update-enum-to-string.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore.Migrations;
2 |
3 | #nullable disable
4 |
5 | namespace backend.Migrations
6 | {
7 | ///
8 | public partial class updateenumtostring : Migration
9 | {
10 | ///
11 | protected override void Up(MigrationBuilder migrationBuilder)
12 | {
13 | migrationBuilder.AlterColumn(
14 | name: "Level",
15 | table: "Jobs",
16 | type: "nvarchar(max)",
17 | nullable: false,
18 | oldClrType: typeof(int),
19 | oldType: "int");
20 |
21 | migrationBuilder.AlterColumn(
22 | name: "Size",
23 | table: "Companies",
24 | type: "nvarchar(max)",
25 | nullable: false,
26 | oldClrType: typeof(int),
27 | oldType: "int");
28 | }
29 |
30 | ///
31 | protected override void Down(MigrationBuilder migrationBuilder)
32 | {
33 | migrationBuilder.AlterColumn(
34 | name: "Level",
35 | table: "Jobs",
36 | type: "int",
37 | nullable: false,
38 | oldClrType: typeof(string),
39 | oldType: "nvarchar(max)");
40 |
41 | migrationBuilder.AlterColumn(
42 | name: "Size",
43 | table: "Companies",
44 | type: "int",
45 | nullable: false,
46 | oldClrType: typeof(string),
47 | oldType: "nvarchar(max)");
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/frontend/src/pages/candidates/Candidates.page.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from "react";
2 | import "./candidates.scss";
3 | import httpModule from "../../helpers/http.module";
4 | import { ICandidate } from "../../types/global.typing";
5 | import { Button, CircularProgress } from "@mui/material";
6 | import { Add } from "@mui/icons-material";
7 | import { useNavigate } from "react-router-dom";
8 | import CandidatesGrid from "../../components/candidates/CandidatesGrid.component";
9 |
10 | const Candidates = () => {
11 | const [candidates, setCandidates] = useState([]);
12 | const [loading, setLoading] = useState(false);
13 | const redirect = useNavigate();
14 |
15 | useEffect(() => {
16 | setLoading(true);
17 | httpModule
18 | .get("/Candidate/Get")
19 | .then((response) => {
20 | setCandidates(response.data);
21 | setLoading(false);
22 | })
23 | .catch((error) => {
24 | alert("Error");
25 | console.log(error);
26 | setLoading(false);
27 | });
28 | }, []);
29 |
30 | return (
31 |
32 |
33 |
Candidates
34 |
redirect("/candidates/add")}>
35 |
36 |
37 |
38 | {loading ? (
39 |
40 | ) : candidates.length === 0 ? (
41 |
No Candidate
42 | ) : (
43 |
44 | )}
45 |
46 | );
47 | };
48 |
49 | export default Candidates;
50 |
--------------------------------------------------------------------------------
/frontend/src/pages/companies/Companies.page.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from "react";
2 | import "./companies.scss";
3 | import httpModule from "../../helpers/http.module";
4 | import { ICompany } from "../../types/global.typing";
5 | import { Button, CircularProgress } from "@mui/material";
6 | import { Add } from "@mui/icons-material";
7 | import { useNavigate } from "react-router-dom";
8 | import CompaniesGrid from "../../components/companies/CompaniesGrid.component";
9 |
10 | const Companies = () => {
11 | const [companies, setCompanies] = useState([]);
12 | const [loading, setLoading] = useState(false);
13 | const redirect = useNavigate();
14 |
15 | useEffect(() => {
16 | setLoading(true);
17 | httpModule
18 | .get("/Company/Get")
19 | .then((response) => {
20 | setCompanies(response.data);
21 | setLoading(false);
22 | })
23 | .catch((error) => {
24 | alert("Error");
25 | console.log(error);
26 | setLoading(false);
27 | });
28 | }, []);
29 |
30 | // console.log(companies);
31 |
32 | return (
33 |
34 |
35 |
Companies
36 |
redirect("/companies/add")}>
37 |
38 |
39 |
40 | {loading ? (
41 |
42 | ) : companies.length === 0 ? (
43 |
No Company
44 | ) : (
45 |
46 | )}
47 |
48 | );
49 | };
50 |
51 | export default Companies;
52 |
--------------------------------------------------------------------------------
/frontend/src/components/navbar/navbar.scss:
--------------------------------------------------------------------------------
1 | @import "../../mixins";
2 |
3 | .navbar {
4 | @include d-flex(row, space-between, center);
5 | color: #fff;
6 | background-color: rgb(52, 51, 51);
7 | width: 100%;
8 | height: 60px;
9 | padding: 0 2rem;
10 |
11 | .brand {
12 | flex: 1;
13 | }
14 |
15 | .menu {
16 | ul {
17 | @include d-flex(row, flex-start, center);
18 | gap: 1rem;
19 |
20 | li {
21 | a {
22 | color: #fff;
23 | cursor: pointer;
24 | }
25 | }
26 | }
27 | }
28 |
29 | .hamburger {
30 | display: none;
31 | cursor: pointer;
32 | }
33 |
34 | .toggle {
35 | margin-left: 1rem;
36 | cursor: pointer;
37 | svg {
38 | color: var(--blue);
39 | }
40 | }
41 | }
42 |
43 | @media (max-width: 600px) {
44 | .navbar {
45 | padding: 0 1rem;
46 |
47 | .menu {
48 | @include d-flex(column, flex-start, center);
49 | color: #fff;
50 | background-color: rgb(52, 51, 51);
51 | width: 240px;
52 | height: 100vh;
53 | position: fixed;
54 | top: 0;
55 | left: -240px;
56 | z-index: 100;
57 | transition: all 0.3s ease-in-out;
58 |
59 | &.open {
60 | left: 0;
61 | }
62 | ul {
63 | @include d-flex(column, center, center);
64 | gap: 2rem;
65 | height: 100%;
66 | li {
67 | a {
68 | color: #fff;
69 | cursor: pointer;
70 | }
71 | }
72 | }
73 | }
74 |
75 | .hamburger {
76 | display: block;
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/backend/backend/Controllers/CompanyController.cs:
--------------------------------------------------------------------------------
1 | using AutoMapper;
2 | using backend.Core.Context;
3 | using backend.Core.Dtos.Company;
4 | using backend.Core.Entities;
5 | using Microsoft.AspNetCore.Http;
6 | using Microsoft.AspNetCore.Mvc;
7 | using Microsoft.EntityFrameworkCore;
8 |
9 | namespace backend.Controllers
10 | {
11 | [Route("api/[controller]")]
12 | [ApiController]
13 | public class CompanyController : ControllerBase
14 | {
15 | private ApplicationDbContext _context { get; }
16 | private IMapper _mapper { get; }
17 |
18 | public CompanyController(ApplicationDbContext context, IMapper mapper)
19 | {
20 | _context = context;
21 | _mapper = mapper;
22 | }
23 |
24 | // CRUD
25 |
26 | // Create
27 | [HttpPost]
28 | [Route("Create")]
29 | public async Task CreateCompany([FromBody] CompanyCreateDto dto)
30 | {
31 | Company newCompany = _mapper.Map(dto);
32 | await _context.Companies.AddAsync(newCompany);
33 | await _context.SaveChangesAsync();
34 |
35 | return Ok("Companty Created Successfully");
36 | }
37 |
38 | // Read
39 | [HttpGet]
40 | [Route("Get")]
41 | public async Task>> GetCompanies()
42 | {
43 | var companies = await _context.Companies.OrderByDescending(q => q.CreatedAt).ToListAsync();
44 | var convertedCompanies = _mapper.Map>(companies);
45 |
46 | return Ok(convertedCompanies);
47 | }
48 |
49 | // Read (Get Company By ID)
50 |
51 | // Update
52 |
53 | // Delete
54 |
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/frontend/src/components/navbar/Navbar.component.tsx:
--------------------------------------------------------------------------------
1 | import { useContext, useState } from "react";
2 | import "./navbar.scss";
3 | import { Link } from "react-router-dom";
4 | import { Menu, LightMode, DarkMode } from "@mui/icons-material";
5 | import { ToggleButton } from "@mui/material";
6 | import { ThemeContext } from "../../context/theme.context";
7 |
8 | const links = [
9 | { href: "/", label: "Home" },
10 | { href: "/companies", label: "Companies" },
11 | { href: "/jobs", label: "Jobs" },
12 | { href: "/candidates", label: "Candidates" },
13 | ];
14 |
15 | const Navbar = () => {
16 | const [open, setOpen] = useState(false);
17 | const { darkMode, toggleDarkMode } = useContext(ThemeContext);
18 |
19 | const ToggleOpenMenu = () => {
20 | setOpen((prevState) => !prevState);
21 | };
22 |
23 | const menuStyles = open ? "menu open" : "menu";
24 |
25 | return (
26 |
27 |
28 | Resume Management
29 |
30 |
31 |
32 | {links.map((item) => (
33 |
34 | {item.label}
35 |
36 | ))}
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | {darkMode ? : }
45 |
46 |
47 |
48 | );
49 | };
50 |
51 | export default Navbar;
52 |
--------------------------------------------------------------------------------
/frontend/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | React App
28 |
29 |
30 | You need to enable JavaScript to run this app.
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/frontend/src/App.tsx:
--------------------------------------------------------------------------------
1 | import { useContext, lazy, Suspense } from "react";
2 | import Navbar from "./components/navbar/Navbar.component";
3 | import { ThemeContext } from "./context/theme.context";
4 | import { Routes, Route } from "react-router-dom";
5 | import CustomLinearProgress from "./components/custom-linear-progress/CustomLinearProgress.component";
6 |
7 | // Imports with Lazy loading
8 | const Home = lazy(() => import("./pages/home/Home.page"));
9 | const Companies = lazy(() => import("./pages/companies/Companies.page"));
10 | const AddCompany = lazy(() => import("./pages/companies/AddCompany.page"));
11 | const Jobs = lazy(() => import("./pages/jobs/Jobs.page"));
12 | const AddJob = lazy(() => import("./pages/jobs/AddJob.page"));
13 | const Candidates = lazy(() => import("./pages/candidates/Candidates.page"));
14 | const AddCandidate = lazy(() => import("./pages/candidates/AddCandidate.page"));
15 |
16 | const App = () => {
17 | const { darkMode } = useContext(ThemeContext);
18 |
19 | const appStyles = darkMode ? "app dark" : "app";
20 |
21 | return (
22 |
23 |
24 |
25 | }>
26 |
27 | } />
28 |
29 | } />
30 | } />
31 |
32 |
33 | } />
34 | } />
35 |
36 |
37 | } />
38 | } />
39 |
40 |
41 |
42 |
43 |
44 | );
45 | };
46 |
47 | export default App;
48 |
--------------------------------------------------------------------------------
/frontend/README.md:
--------------------------------------------------------------------------------
1 | # Getting Started with Create React App
2 |
3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
4 |
5 | ## Available Scripts
6 |
7 | In the project directory, you can run:
8 |
9 | ### `npm start`
10 |
11 | Runs the app in the development mode.\
12 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
13 |
14 | The page will reload if you make edits.\
15 | You will also see any lint errors in the console.
16 |
17 | ### `npm test`
18 |
19 | Launches the test runner in the interactive watch mode.\
20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
21 |
22 | ### `npm run build`
23 |
24 | Builds the app for production to the `build` folder.\
25 | It correctly bundles React in production mode and optimizes the build for the best performance.
26 |
27 | The build is minified and the filenames include the hashes.\
28 | Your app is ready to be deployed!
29 |
30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
31 |
32 | ### `npm run eject`
33 |
34 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!**
35 |
36 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
37 |
38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
39 |
40 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
41 |
42 | ## Learn More
43 |
44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
45 |
46 | To learn React, check out the [React documentation](https://reactjs.org/).
47 |
--------------------------------------------------------------------------------
/frontend/src/pages/companies/AddCompany.page.tsx:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 | import "./companies.scss";
3 | import { ICreateCompanyDto } from "../../types/global.typing";
4 | import {} from "@mui/material";
5 | import TextField from "@mui/material/TextField/TextField";
6 | import FormControl from "@mui/material/FormControl/FormControl";
7 | import InputLabel from "@mui/material/InputLabel/InputLabel";
8 | import Select from "@mui/material/Select/Select";
9 | import MenuItem from "@mui/material/MenuItem/MenuItem";
10 | import Button from "@mui/material/Button/Button";
11 | import { useNavigate } from "react-router-dom";
12 | import httpModule from "../../helpers/http.module";
13 |
14 | const AddCompany = () => {
15 | const [company, setCompany] = useState({ name: "", size: "" });
16 | const redirect = useNavigate();
17 |
18 | const handleClickSaveBtn = () => {
19 | if (company.name === "" || company.size === "") {
20 | alert("Fill all fields");
21 | return;
22 | }
23 | httpModule
24 | .post("/Company/Create", company)
25 | .then((responst) => redirect("/companies"))
26 | .catch((error) => console.log(error));
27 | };
28 |
29 | const handleClickBackBtn = () => {
30 | redirect("/companies");
31 | };
32 |
33 | return (
34 |
35 |
36 |
Add New Company
37 |
setCompany({ ...company, name: e.target.value })}
43 | />
44 |
45 | Company Size
46 | setCompany({ ...company, size: e.target.value })}
50 | >
51 | Small
52 | Medium
53 | Large
54 |
55 |
56 |
57 |
58 | Save
59 |
60 |
61 | Back
62 |
63 |
64 |
65 |
66 | );
67 | };
68 |
69 | export default AddCompany;
70 |
--------------------------------------------------------------------------------
/backend/backend/Controllers/CandidateController.cs:
--------------------------------------------------------------------------------
1 | using AutoMapper;
2 | using backend.Core.Context;
3 | using backend.Core.Dtos.Candidate;
4 | using backend.Core.Entities;
5 | using Microsoft.AspNetCore.Http;
6 | using Microsoft.AspNetCore.Mvc;
7 | using Microsoft.EntityFrameworkCore;
8 |
9 | namespace backend.Controllers
10 | {
11 | [Route("api/[controller]")]
12 | [ApiController]
13 | public class CandidateController : ControllerBase
14 | {
15 | private ApplicationDbContext _context { get; }
16 | private IMapper _mapper { get; }
17 |
18 | public CandidateController(ApplicationDbContext context, IMapper mapper)
19 | {
20 | _context = context;
21 | _mapper = mapper;
22 | }
23 |
24 | // CRUD
25 |
26 | // Create
27 | [HttpPost]
28 | [Route("Create")]
29 | public async Task CreateCandidate([FromForm] CandidateCreateDto dto, IFormFile pdfFile)
30 | {
31 | // Firt => Save pdf to Server
32 | // Then => save url into our entity
33 | var fiveMegaByte = 5 * 1024 * 1024;
34 | var pdfMimeType = "application/pdf";
35 |
36 | if (pdfFile.Length > fiveMegaByte || pdfFile.ContentType != pdfMimeType)
37 | {
38 | return BadRequest("File is not valid");
39 | }
40 |
41 | var resumeUrl = Guid.NewGuid().ToString() + ".pdf";
42 | var filePath = Path.Combine(Directory.GetCurrentDirectory(), "documents", "pdfs", resumeUrl);
43 | using (var stream = new FileStream(filePath, FileMode.Create))
44 | {
45 | await pdfFile.CopyToAsync(stream);
46 | }
47 | var newCandidate = _mapper.Map(dto);
48 | newCandidate.ResumeUrl = resumeUrl;
49 | await _context.Candidates.AddAsync(newCandidate);
50 | await _context.SaveChangesAsync();
51 |
52 | return Ok("Candidate Saved Successfully");
53 | }
54 |
55 | // Read
56 | [HttpGet]
57 | [Route("Get")]
58 | public async Task>> GetCandidates()
59 | {
60 | var candidates = await _context.Candidates.Include(c => c.Job).OrderByDescending(q => q.CreatedAt).ToListAsync();
61 | var convertedCandidates = _mapper.Map>(candidates);
62 |
63 | return Ok(convertedCandidates);
64 | }
65 |
66 | // Read (Download Pdf File)
67 | [HttpGet]
68 | [Route("download/{url}")]
69 | public IActionResult DownloadPdfFile(string url)
70 | {
71 | var filePath = Path.Combine(Directory.GetCurrentDirectory(), "documents", "pdfs", url);
72 |
73 | if(!System.IO.File.Exists(filePath))
74 | {
75 | return NotFound("File Not Found");
76 | }
77 |
78 | var pdfBytes = System.IO.File.ReadAllBytes(filePath);
79 | var file = File(pdfBytes, "application/pdf", url);
80 | return file;
81 | }
82 |
83 | // Read (Get Candidate By ID)
84 |
85 | // Update
86 |
87 | // Delete
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/frontend/src/pages/jobs/AddJob.page.tsx:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from "react";
2 | import "./jobs.scss";
3 | import { ICompany, ICreateCompanyDto, ICreateJobDto } from "../../types/global.typing";
4 |
5 | import TextField from "@mui/material/TextField/TextField";
6 | import FormControl from "@mui/material/FormControl/FormControl";
7 | import InputLabel from "@mui/material/InputLabel/InputLabel";
8 | import Select from "@mui/material/Select/Select";
9 | import MenuItem from "@mui/material/MenuItem/MenuItem";
10 | import Button from "@mui/material/Button/Button";
11 | import { useNavigate } from "react-router-dom";
12 | import httpModule from "../../helpers/http.module";
13 |
14 | const levelsArray: string[] = ["Intern", "Junior", "MidLevel", "Senior", "TeamLead", "Cto", "Architect"];
15 |
16 | const AddJob = () => {
17 | const [job, setJob] = useState({
18 | title: "",
19 | level: "",
20 | companyId: "",
21 | });
22 | const [companies, setCompanies] = useState([]);
23 |
24 | const redirect = useNavigate();
25 |
26 | useEffect(() => {
27 | httpModule
28 | .get("/Company/Get")
29 | .then((response) => {
30 | setCompanies(response.data);
31 | })
32 | .catch((error) => {
33 | alert("Error");
34 | console.log(error);
35 | });
36 | }, []);
37 |
38 | const handleClickSaveBtn = () => {
39 | if (job.title === "" || job.level === "" || job.companyId === "") {
40 | alert("Fill all fields");
41 | return;
42 | }
43 | httpModule
44 | .post("/Job/Create", job)
45 | .then((responst) => redirect("/jobs"))
46 | .catch((error) => console.log(error));
47 | };
48 |
49 | const handleClickBackBtn = () => {
50 | redirect("/jobs");
51 | };
52 |
53 | return (
54 |
55 |
56 |
Add New Job
57 |
setJob({ ...job, title: e.target.value })}
63 | />
64 |
65 |
66 | Job Level
67 | setJob({ ...job, level: e.target.value })}>
68 | {levelsArray.map((item) => (
69 |
70 | {item}
71 |
72 | ))}
73 |
74 |
75 |
76 |
77 | Company
78 | setJob({ ...job, companyId: e.target.value })}
82 | >
83 | {companies.map((item) => (
84 |
85 | {item.name}
86 |
87 | ))}
88 |
89 |
90 |
91 |
92 |
93 | Save
94 |
95 |
96 | Back
97 |
98 |
99 |
100 |
101 | );
102 | };
103 |
104 | export default AddJob;
105 |
--------------------------------------------------------------------------------
/backend/backend/Migrations/20230324220612_initila-migration.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.EntityFrameworkCore.Migrations;
3 |
4 | #nullable disable
5 |
6 | namespace backend.Migrations
7 | {
8 | ///
9 | public partial class initilamigration : Migration
10 | {
11 | ///
12 | protected override void Up(MigrationBuilder migrationBuilder)
13 | {
14 | migrationBuilder.CreateTable(
15 | name: "Companies",
16 | columns: table => new
17 | {
18 | ID = table.Column(type: "bigint", nullable: false)
19 | .Annotation("SqlServer:Identity", "1, 1"),
20 | Name = table.Column(type: "nvarchar(max)", nullable: false),
21 | Size = table.Column(type: "int", nullable: false),
22 | CreatedAt = table.Column(type: "datetime2", nullable: false),
23 | UpdatedAt = table.Column(type: "datetime2", nullable: false),
24 | IsActive = table.Column(type: "bit", nullable: false)
25 | },
26 | constraints: table =>
27 | {
28 | table.PrimaryKey("PK_Companies", x => x.ID);
29 | });
30 |
31 | migrationBuilder.CreateTable(
32 | name: "Jobs",
33 | columns: table => new
34 | {
35 | ID = table.Column(type: "bigint", nullable: false)
36 | .Annotation("SqlServer:Identity", "1, 1"),
37 | Title = table.Column(type: "nvarchar(max)", nullable: false),
38 | Level = table.Column(type: "int", nullable: false),
39 | CompanyId = table.Column(type: "bigint", nullable: false),
40 | CreatedAt = table.Column(type: "datetime2", nullable: false),
41 | UpdatedAt = table.Column(type: "datetime2", nullable: false),
42 | IsActive = table.Column(type: "bit", nullable: false)
43 | },
44 | constraints: table =>
45 | {
46 | table.PrimaryKey("PK_Jobs", x => x.ID);
47 | table.ForeignKey(
48 | name: "FK_Jobs_Companies_CompanyId",
49 | column: x => x.CompanyId,
50 | principalTable: "Companies",
51 | principalColumn: "ID",
52 | onDelete: ReferentialAction.Cascade);
53 | });
54 |
55 | migrationBuilder.CreateTable(
56 | name: "Candidates",
57 | columns: table => new
58 | {
59 | ID = table.Column(type: "bigint", nullable: false)
60 | .Annotation("SqlServer:Identity", "1, 1"),
61 | FirstName = table.Column(type: "nvarchar(max)", nullable: false),
62 | LastName = table.Column(type: "nvarchar(max)", nullable: false),
63 | Email = table.Column(type: "nvarchar(max)", nullable: false),
64 | Phone = table.Column(type: "nvarchar(max)", nullable: false),
65 | CoverLetter = table.Column(type: "nvarchar(max)", nullable: false),
66 | ResumeUrl = table.Column(type: "nvarchar(max)", nullable: false),
67 | JobId = table.Column(type: "bigint", nullable: false),
68 | CreatedAt = table.Column(type: "datetime2", nullable: false),
69 | UpdatedAt = table.Column(type: "datetime2", nullable: false),
70 | IsActive = table.Column(type: "bit", nullable: false)
71 | },
72 | constraints: table =>
73 | {
74 | table.PrimaryKey("PK_Candidates", x => x.ID);
75 | table.ForeignKey(
76 | name: "FK_Candidates_Jobs_JobId",
77 | column: x => x.JobId,
78 | principalTable: "Jobs",
79 | principalColumn: "ID",
80 | onDelete: ReferentialAction.Cascade);
81 | });
82 |
83 | migrationBuilder.CreateIndex(
84 | name: "IX_Candidates_JobId",
85 | table: "Candidates",
86 | column: "JobId");
87 |
88 | migrationBuilder.CreateIndex(
89 | name: "IX_Jobs_CompanyId",
90 | table: "Jobs",
91 | column: "CompanyId");
92 | }
93 |
94 | ///
95 | protected override void Down(MigrationBuilder migrationBuilder)
96 | {
97 | migrationBuilder.DropTable(
98 | name: "Candidates");
99 |
100 | migrationBuilder.DropTable(
101 | name: "Jobs");
102 |
103 | migrationBuilder.DropTable(
104 | name: "Companies");
105 | }
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/frontend/src/pages/candidates/AddCandidate.page.tsx:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from "react";
2 | import "./candidates.scss";
3 | import { ICompany, ICreateCandidateDto, ICreateCompanyDto, ICreateJobDto, IJob } from "../../types/global.typing";
4 |
5 | import TextField from "@mui/material/TextField/TextField";
6 | import FormControl from "@mui/material/FormControl/FormControl";
7 | import InputLabel from "@mui/material/InputLabel/InputLabel";
8 | import Select from "@mui/material/Select/Select";
9 | import MenuItem from "@mui/material/MenuItem/MenuItem";
10 | import Button from "@mui/material/Button/Button";
11 | import { useNavigate } from "react-router-dom";
12 | import httpModule from "../../helpers/http.module";
13 |
14 | const AddCandidate = () => {
15 | const [candidate, setCandidate] = useState({
16 | firstName: "",
17 | lastName: "",
18 | email: "",
19 | phone: "",
20 | coverLetter: "",
21 | jobId: "",
22 | });
23 | const [jobs, setJobs] = useState([]);
24 | const [pdfFile, setPdfFile] = useState();
25 |
26 | const redirect = useNavigate();
27 |
28 | useEffect(() => {
29 | httpModule
30 | .get("/Job/Get")
31 | .then((response) => {
32 | setJobs(response.data);
33 | })
34 | .catch((error) => {
35 | alert("Error");
36 | console.log(error);
37 | });
38 | }, []);
39 |
40 | const handleClickSaveBtn = () => {
41 | if (
42 | candidate.firstName === "" ||
43 | candidate.lastName === "" ||
44 | candidate.email === "" ||
45 | candidate.phone === "" ||
46 | candidate.coverLetter === "" ||
47 | candidate.jobId === "" ||
48 | !pdfFile
49 | ) {
50 | alert("Fill all fields");
51 | return;
52 | }
53 | const newCandidateFormData = new FormData();
54 | newCandidateFormData.append("firstName", candidate.firstName);
55 | newCandidateFormData.append("lastName", candidate.lastName);
56 | newCandidateFormData.append("email", candidate.email);
57 | newCandidateFormData.append("phone", candidate.phone);
58 | newCandidateFormData.append("coverLetter", candidate.coverLetter);
59 | newCandidateFormData.append("jobId", candidate.jobId);
60 | newCandidateFormData.append("pdfFile", pdfFile);
61 | httpModule
62 | .post("/Candidate/Create", newCandidateFormData)
63 | .then((responst) => redirect("/candidates"))
64 | .catch((error) => console.log(error));
65 | };
66 |
67 | const handleClickBackBtn = () => {
68 | redirect("/candidates");
69 | };
70 |
71 | return (
72 |
73 |
74 |
Add New Candidate
75 |
76 | Job
77 | setCandidate({ ...candidate, jobId: e.target.value })}
81 | >
82 | {jobs.map((item) => (
83 |
84 | {item.title}
85 |
86 | ))}
87 |
88 |
89 |
setCandidate({ ...candidate, firstName: e.target.value })}
95 | />
96 | setCandidate({ ...candidate, lastName: e.target.value })}
102 | />
103 | setCandidate({ ...candidate, email: e.target.value })}
109 | />
110 | setCandidate({ ...candidate, phone: e.target.value })}
116 | />
117 | setCandidate({ ...candidate, coverLetter: e.target.value })}
123 | multiline
124 | />
125 | setPdfFile(event.target.files ? event.target.files[0] : null)} />
126 |
127 |
128 |
129 | Save
130 |
131 |
132 | Back
133 |
134 |
135 |
136 |
137 | );
138 | };
139 |
140 | export default AddCandidate;
141 |
--------------------------------------------------------------------------------
/backend/backend/Migrations/ApplicationDbContextModelSnapshot.cs:
--------------------------------------------------------------------------------
1 | //
2 | using System;
3 | using Microsoft.EntityFrameworkCore;
4 | using Microsoft.EntityFrameworkCore.Infrastructure;
5 | using Microsoft.EntityFrameworkCore.Metadata;
6 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
7 | using backend.Core.Context;
8 |
9 | #nullable disable
10 |
11 | namespace backend.Migrations
12 | {
13 | [DbContext(typeof(ApplicationDbContext))]
14 | partial class ApplicationDbContextModelSnapshot : ModelSnapshot
15 | {
16 | protected override void BuildModel(ModelBuilder modelBuilder)
17 | {
18 | #pragma warning disable 612, 618
19 | modelBuilder
20 | .HasAnnotation("ProductVersion", "7.0.4")
21 | .HasAnnotation("Relational:MaxIdentifierLength", 128);
22 |
23 | SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
24 |
25 | modelBuilder.Entity("backend.Core.Entities.Candidate", b =>
26 | {
27 | b.Property("ID")
28 | .ValueGeneratedOnAdd()
29 | .HasColumnType("bigint");
30 |
31 | SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ID"));
32 |
33 | b.Property("CoverLetter")
34 | .IsRequired()
35 | .HasColumnType("nvarchar(max)");
36 |
37 | b.Property("CreatedAt")
38 | .HasColumnType("datetime2");
39 |
40 | b.Property("Email")
41 | .IsRequired()
42 | .HasColumnType("nvarchar(max)");
43 |
44 | b.Property("FirstName")
45 | .IsRequired()
46 | .HasColumnType("nvarchar(max)");
47 |
48 | b.Property("IsActive")
49 | .HasColumnType("bit");
50 |
51 | b.Property("JobId")
52 | .HasColumnType("bigint");
53 |
54 | b.Property("LastName")
55 | .IsRequired()
56 | .HasColumnType("nvarchar(max)");
57 |
58 | b.Property("Phone")
59 | .IsRequired()
60 | .HasColumnType("nvarchar(max)");
61 |
62 | b.Property("ResumeUrl")
63 | .IsRequired()
64 | .HasColumnType("nvarchar(max)");
65 |
66 | b.Property("UpdatedAt")
67 | .HasColumnType("datetime2");
68 |
69 | b.HasKey("ID");
70 |
71 | b.HasIndex("JobId");
72 |
73 | b.ToTable("Candidates");
74 | });
75 |
76 | modelBuilder.Entity("backend.Core.Entities.Company", b =>
77 | {
78 | b.Property("ID")
79 | .ValueGeneratedOnAdd()
80 | .HasColumnType("bigint");
81 |
82 | SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ID"));
83 |
84 | b.Property("CreatedAt")
85 | .HasColumnType("datetime2");
86 |
87 | b.Property("IsActive")
88 | .HasColumnType("bit");
89 |
90 | b.Property("Name")
91 | .IsRequired()
92 | .HasColumnType("nvarchar(max)");
93 |
94 | b.Property("Size")
95 | .IsRequired()
96 | .HasColumnType("nvarchar(max)");
97 |
98 | b.Property("UpdatedAt")
99 | .HasColumnType("datetime2");
100 |
101 | b.HasKey("ID");
102 |
103 | b.ToTable("Companies");
104 | });
105 |
106 | modelBuilder.Entity("backend.Core.Entities.Job", b =>
107 | {
108 | b.Property("ID")
109 | .ValueGeneratedOnAdd()
110 | .HasColumnType("bigint");
111 |
112 | SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ID"));
113 |
114 | b.Property("CompanyId")
115 | .HasColumnType("bigint");
116 |
117 | b.Property("CreatedAt")
118 | .HasColumnType("datetime2");
119 |
120 | b.Property("IsActive")
121 | .HasColumnType("bit");
122 |
123 | b.Property("Level")
124 | .IsRequired()
125 | .HasColumnType("nvarchar(max)");
126 |
127 | b.Property("Title")
128 | .IsRequired()
129 | .HasColumnType("nvarchar(max)");
130 |
131 | b.Property("UpdatedAt")
132 | .HasColumnType("datetime2");
133 |
134 | b.HasKey("ID");
135 |
136 | b.HasIndex("CompanyId");
137 |
138 | b.ToTable("Jobs");
139 | });
140 |
141 | modelBuilder.Entity("backend.Core.Entities.Candidate", b =>
142 | {
143 | b.HasOne("backend.Core.Entities.Job", "Job")
144 | .WithMany("Candidates")
145 | .HasForeignKey("JobId")
146 | .OnDelete(DeleteBehavior.Cascade)
147 | .IsRequired();
148 |
149 | b.Navigation("Job");
150 | });
151 |
152 | modelBuilder.Entity("backend.Core.Entities.Job", b =>
153 | {
154 | b.HasOne("backend.Core.Entities.Company", "Company")
155 | .WithMany("Jobs")
156 | .HasForeignKey("CompanyId")
157 | .OnDelete(DeleteBehavior.Cascade)
158 | .IsRequired();
159 |
160 | b.Navigation("Company");
161 | });
162 |
163 | modelBuilder.Entity("backend.Core.Entities.Company", b =>
164 | {
165 | b.Navigation("Jobs");
166 | });
167 |
168 | modelBuilder.Entity("backend.Core.Entities.Job", b =>
169 | {
170 | b.Navigation("Candidates");
171 | });
172 | #pragma warning restore 612, 618
173 | }
174 | }
175 | }
176 |
--------------------------------------------------------------------------------
/backend/backend/Migrations/20230324220612_initila-migration.Designer.cs:
--------------------------------------------------------------------------------
1 | //
2 | using System;
3 | using Microsoft.EntityFrameworkCore;
4 | using Microsoft.EntityFrameworkCore.Infrastructure;
5 | using Microsoft.EntityFrameworkCore.Metadata;
6 | using Microsoft.EntityFrameworkCore.Migrations;
7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
8 | using backend.Core.Context;
9 |
10 | #nullable disable
11 |
12 | namespace backend.Migrations
13 | {
14 | [DbContext(typeof(ApplicationDbContext))]
15 | [Migration("20230324220612_initila-migration")]
16 | partial class initilamigration
17 | {
18 | ///
19 | protected override void BuildTargetModel(ModelBuilder modelBuilder)
20 | {
21 | #pragma warning disable 612, 618
22 | modelBuilder
23 | .HasAnnotation("ProductVersion", "7.0.4")
24 | .HasAnnotation("Relational:MaxIdentifierLength", 128);
25 |
26 | SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
27 |
28 | modelBuilder.Entity("backend.Core.Entities.Candidate", b =>
29 | {
30 | b.Property("ID")
31 | .ValueGeneratedOnAdd()
32 | .HasColumnType("bigint");
33 |
34 | SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ID"));
35 |
36 | b.Property("CoverLetter")
37 | .IsRequired()
38 | .HasColumnType("nvarchar(max)");
39 |
40 | b.Property("CreatedAt")
41 | .HasColumnType("datetime2");
42 |
43 | b.Property("Email")
44 | .IsRequired()
45 | .HasColumnType("nvarchar(max)");
46 |
47 | b.Property("FirstName")
48 | .IsRequired()
49 | .HasColumnType("nvarchar(max)");
50 |
51 | b.Property("IsActive")
52 | .HasColumnType("bit");
53 |
54 | b.Property("JobId")
55 | .HasColumnType("bigint");
56 |
57 | b.Property("LastName")
58 | .IsRequired()
59 | .HasColumnType("nvarchar(max)");
60 |
61 | b.Property("Phone")
62 | .IsRequired()
63 | .HasColumnType("nvarchar(max)");
64 |
65 | b.Property("ResumeUrl")
66 | .IsRequired()
67 | .HasColumnType("nvarchar(max)");
68 |
69 | b.Property("UpdatedAt")
70 | .HasColumnType("datetime2");
71 |
72 | b.HasKey("ID");
73 |
74 | b.HasIndex("JobId");
75 |
76 | b.ToTable("Candidates");
77 | });
78 |
79 | modelBuilder.Entity("backend.Core.Entities.Company", b =>
80 | {
81 | b.Property("ID")
82 | .ValueGeneratedOnAdd()
83 | .HasColumnType("bigint");
84 |
85 | SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ID"));
86 |
87 | b.Property("CreatedAt")
88 | .HasColumnType("datetime2");
89 |
90 | b.Property("IsActive")
91 | .HasColumnType("bit");
92 |
93 | b.Property("Name")
94 | .IsRequired()
95 | .HasColumnType("nvarchar(max)");
96 |
97 | b.Property("Size")
98 | .HasColumnType("int");
99 |
100 | b.Property("UpdatedAt")
101 | .HasColumnType("datetime2");
102 |
103 | b.HasKey("ID");
104 |
105 | b.ToTable("Companies");
106 | });
107 |
108 | modelBuilder.Entity("backend.Core.Entities.Job", b =>
109 | {
110 | b.Property("ID")
111 | .ValueGeneratedOnAdd()
112 | .HasColumnType("bigint");
113 |
114 | SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ID"));
115 |
116 | b.Property("CompanyId")
117 | .HasColumnType("bigint");
118 |
119 | b.Property("CreatedAt")
120 | .HasColumnType("datetime2");
121 |
122 | b.Property("IsActive")
123 | .HasColumnType("bit");
124 |
125 | b.Property("Level")
126 | .HasColumnType("int");
127 |
128 | b.Property("Title")
129 | .IsRequired()
130 | .HasColumnType("nvarchar(max)");
131 |
132 | b.Property("UpdatedAt")
133 | .HasColumnType("datetime2");
134 |
135 | b.HasKey("ID");
136 |
137 | b.HasIndex("CompanyId");
138 |
139 | b.ToTable("Jobs");
140 | });
141 |
142 | modelBuilder.Entity("backend.Core.Entities.Candidate", b =>
143 | {
144 | b.HasOne("backend.Core.Entities.Job", "Job")
145 | .WithMany("Candidates")
146 | .HasForeignKey("JobId")
147 | .OnDelete(DeleteBehavior.Cascade)
148 | .IsRequired();
149 |
150 | b.Navigation("Job");
151 | });
152 |
153 | modelBuilder.Entity("backend.Core.Entities.Job", b =>
154 | {
155 | b.HasOne("backend.Core.Entities.Company", "Company")
156 | .WithMany("Jobs")
157 | .HasForeignKey("CompanyId")
158 | .OnDelete(DeleteBehavior.Cascade)
159 | .IsRequired();
160 |
161 | b.Navigation("Company");
162 | });
163 |
164 | modelBuilder.Entity("backend.Core.Entities.Company", b =>
165 | {
166 | b.Navigation("Jobs");
167 | });
168 |
169 | modelBuilder.Entity("backend.Core.Entities.Job", b =>
170 | {
171 | b.Navigation("Candidates");
172 | });
173 | #pragma warning restore 612, 618
174 | }
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/backend/backend/Migrations/20230324222318_update-enum-to-string.Designer.cs:
--------------------------------------------------------------------------------
1 | //
2 | using System;
3 | using Microsoft.EntityFrameworkCore;
4 | using Microsoft.EntityFrameworkCore.Infrastructure;
5 | using Microsoft.EntityFrameworkCore.Metadata;
6 | using Microsoft.EntityFrameworkCore.Migrations;
7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
8 | using backend.Core.Context;
9 |
10 | #nullable disable
11 |
12 | namespace backend.Migrations
13 | {
14 | [DbContext(typeof(ApplicationDbContext))]
15 | [Migration("20230324222318_update-enum-to-string")]
16 | partial class updateenumtostring
17 | {
18 | ///
19 | protected override void BuildTargetModel(ModelBuilder modelBuilder)
20 | {
21 | #pragma warning disable 612, 618
22 | modelBuilder
23 | .HasAnnotation("ProductVersion", "7.0.4")
24 | .HasAnnotation("Relational:MaxIdentifierLength", 128);
25 |
26 | SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
27 |
28 | modelBuilder.Entity("backend.Core.Entities.Candidate", b =>
29 | {
30 | b.Property("ID")
31 | .ValueGeneratedOnAdd()
32 | .HasColumnType("bigint");
33 |
34 | SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ID"));
35 |
36 | b.Property("CoverLetter")
37 | .IsRequired()
38 | .HasColumnType("nvarchar(max)");
39 |
40 | b.Property("CreatedAt")
41 | .HasColumnType("datetime2");
42 |
43 | b.Property("Email")
44 | .IsRequired()
45 | .HasColumnType("nvarchar(max)");
46 |
47 | b.Property("FirstName")
48 | .IsRequired()
49 | .HasColumnType("nvarchar(max)");
50 |
51 | b.Property("IsActive")
52 | .HasColumnType("bit");
53 |
54 | b.Property("JobId")
55 | .HasColumnType("bigint");
56 |
57 | b.Property("LastName")
58 | .IsRequired()
59 | .HasColumnType("nvarchar(max)");
60 |
61 | b.Property("Phone")
62 | .IsRequired()
63 | .HasColumnType("nvarchar(max)");
64 |
65 | b.Property("ResumeUrl")
66 | .IsRequired()
67 | .HasColumnType("nvarchar(max)");
68 |
69 | b.Property("UpdatedAt")
70 | .HasColumnType("datetime2");
71 |
72 | b.HasKey("ID");
73 |
74 | b.HasIndex("JobId");
75 |
76 | b.ToTable("Candidates");
77 | });
78 |
79 | modelBuilder.Entity("backend.Core.Entities.Company", b =>
80 | {
81 | b.Property("ID")
82 | .ValueGeneratedOnAdd()
83 | .HasColumnType("bigint");
84 |
85 | SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ID"));
86 |
87 | b.Property("CreatedAt")
88 | .HasColumnType("datetime2");
89 |
90 | b.Property("IsActive")
91 | .HasColumnType("bit");
92 |
93 | b.Property("Name")
94 | .IsRequired()
95 | .HasColumnType("nvarchar(max)");
96 |
97 | b.Property("Size")
98 | .IsRequired()
99 | .HasColumnType("nvarchar(max)");
100 |
101 | b.Property("UpdatedAt")
102 | .HasColumnType("datetime2");
103 |
104 | b.HasKey("ID");
105 |
106 | b.ToTable("Companies");
107 | });
108 |
109 | modelBuilder.Entity("backend.Core.Entities.Job", b =>
110 | {
111 | b.Property("ID")
112 | .ValueGeneratedOnAdd()
113 | .HasColumnType("bigint");
114 |
115 | SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ID"));
116 |
117 | b.Property("CompanyId")
118 | .HasColumnType("bigint");
119 |
120 | b.Property("CreatedAt")
121 | .HasColumnType("datetime2");
122 |
123 | b.Property("IsActive")
124 | .HasColumnType("bit");
125 |
126 | b.Property("Level")
127 | .IsRequired()
128 | .HasColumnType("nvarchar(max)");
129 |
130 | b.Property("Title")
131 | .IsRequired()
132 | .HasColumnType("nvarchar(max)");
133 |
134 | b.Property("UpdatedAt")
135 | .HasColumnType("datetime2");
136 |
137 | b.HasKey("ID");
138 |
139 | b.HasIndex("CompanyId");
140 |
141 | b.ToTable("Jobs");
142 | });
143 |
144 | modelBuilder.Entity("backend.Core.Entities.Candidate", b =>
145 | {
146 | b.HasOne("backend.Core.Entities.Job", "Job")
147 | .WithMany("Candidates")
148 | .HasForeignKey("JobId")
149 | .OnDelete(DeleteBehavior.Cascade)
150 | .IsRequired();
151 |
152 | b.Navigation("Job");
153 | });
154 |
155 | modelBuilder.Entity("backend.Core.Entities.Job", b =>
156 | {
157 | b.HasOne("backend.Core.Entities.Company", "Company")
158 | .WithMany("Jobs")
159 | .HasForeignKey("CompanyId")
160 | .OnDelete(DeleteBehavior.Cascade)
161 | .IsRequired();
162 |
163 | b.Navigation("Company");
164 | });
165 |
166 | modelBuilder.Entity("backend.Core.Entities.Company", b =>
167 | {
168 | b.Navigation("Jobs");
169 | });
170 |
171 | modelBuilder.Entity("backend.Core.Entities.Job", b =>
172 | {
173 | b.Navigation("Candidates");
174 | });
175 | #pragma warning restore 612, 618
176 | }
177 | }
178 | }
179 |
--------------------------------------------------------------------------------