профиль компании со списком вакансий, профиль пользователя и редактирование

This commit is contained in:
Татьяна Артамонова 2024-11-19 16:45:59 +04:00
parent 5528e3db15
commit 525668cb62
21 changed files with 605 additions and 83 deletions

View File

@ -12,10 +12,12 @@ namespace CandidateReviewBusinessLogic.BusinessLogic
{
private readonly ILogger _logger;
private readonly ICompanyStorage _сompanyStorage;
public CompanyLogic(ILogger<CompanyLogic> logger, ICompanyStorage сompanyStorage)
private readonly IVacancyStorage _vacancyStorage;
public CompanyLogic(ILogger<CompanyLogic> logger, ICompanyStorage сompanyStorage, IVacancyStorage vacancyStorage)
{
_logger = logger;
_сompanyStorage = сompanyStorage;
_vacancyStorage = vacancyStorage;
}
public int Create(CompanyBindingModel model)
{
@ -40,7 +42,7 @@ namespace CandidateReviewBusinessLogic.BusinessLogic
return true;
}
public CompanyViewModel? ReadElement(CompanySearchModel model)
/*public CompanyViewModel? ReadElement(CompanySearchModel model)
{
if (model == null)
{
@ -54,8 +56,55 @@ namespace CandidateReviewBusinessLogic.BusinessLogic
}
_logger.LogInformation("ReadElement find. Id: {Id}", element.Id);
return element;
}*/
public CompanyViewModel? ReadElement(CompanySearchModel model)
{
if (model == null)
{
throw new ArgumentNullException(nameof(model));
}
var company = _сompanyStorage.GetElement(model);
if (company == null)
{
_logger.LogWarning("ReadElement: Company not found for Id: {Id}", model.Id);
return null;
}
var vacancies = _vacancyStorage.GetFilteredList(new VacancySearchModel { CompanyId = company.Id});
var vacancyViewModels = vacancies?.Select(v => new VacancyViewModel
{
Id = v.Id,
CompanyId = v.CompanyId,
JobTitle = v.JobTitle,
Requirements = v.Requirements,
Responsibilities = v.Responsibilities,
JobType = v.JobType,
Salary = v.Salary,
Description = v.Description,
Status = v.Status,
CreatedAt = v.CreatedAt,
Tags = v.Tags
}).ToList() ?? new List<VacancyViewModel>();
var companyViewModel = new CompanyViewModel
{
Id = company.Id,
Name = company.Name,
Description = company.Description,
Contacts = company.Contacts,
Address = company.Address,
Website = company.Website,
LogoFilePath = company.LogoFilePath,
Vacancies = vacancyViewModels
};
_logger.LogInformation("ReadElement: Company found. Id: {Id}", company.Id);
return companyViewModel;
}
public List<CompanyViewModel>? ReadList(CompanySearchModel? model)
{
var list = model == null ? _сompanyStorage.GetFullList() : _сompanyStorage.GetFilteredList(model);

View File

@ -41,7 +41,6 @@ namespace CandidateReviewBusinessLogic.BusinessLogic
public bool Delete(UserBindingModel model)
{
CheckModel(model, false);
CheckPassword(model);
_logger.LogInformation("Delete. Id: {Id}", model.Id);
if (_userStorage.Delete(model) == null)
{

View File

@ -10,6 +10,7 @@ namespace CandidateReviewClientApp
private static readonly HttpClient _user = new();
public static UserViewModel? User { get; set; } = null;
public static CompanyViewModel? Company { get; set; } = null;
public static VacancyViewModel? Vacancy { get; set; } = null;
public static void Connect(IConfiguration configuration)
{
_user.BaseAddress = new Uri(configuration["IPAddress"]);

View File

@ -41,7 +41,19 @@ namespace CandidateReviewClientApp.Controllers
var model = APIClient.GetRequest<CompanyViewModel?>($"api/company/profile?id={id}");
if (model != null)
{
APIClient.PostRequest($"api/user/update", new UserBindingModel { Id = APIClient.User.Id, CompanyId = model.Id });
APIClient.PostRequest($"api/user/update", new UserBindingModel {
Id = APIClient.User.Id,
CompanyId = model.Id,
Surname = APIClient.User.Surname,
Name = APIClient.User.Name,
LastName = APIClient.User.LastName,
Email = APIClient.User.Email,
Password = APIClient.User.Password,
EmailConfirmed = APIClient.User.EmailConfirmed,
Role = APIClient.User.Role,
AvatarFilePath = APIClient.User.AvatarFilePath,
PhoneNumber = APIClient.User.PhoneNumber
});
}
return View(model);
}
@ -61,7 +73,7 @@ namespace CandidateReviewClientApp.Controllers
{
APIClient.PostRequest("api/company/create", model);
}
Response.Redirect("/Home/Index");
Response.Redirect($"/Company/CompanyProfile/{model.Id}");
}
[HttpPost]

View File

@ -41,6 +41,10 @@ namespace CandidateReviewUserApp.Controllers
throw new Exception("Ââåäèòå ëîãèí è ïàðîëü");
}
APIClient.User = APIClient.GetRequest<UserViewModel>($"api/user/login?login={login}&password={password}");
if (APIClient.User.CompanyId != null)
{
APIClient.Company = APIClient.GetRequest<CompanyViewModel>($"api/company/profile?id={APIClient.User?.CompanyId}");
}
if (APIClient.User == null)
{
throw new Exception("Íåâåðíûé ëîãèí/ïàðîëü");

View File

@ -24,7 +24,7 @@ namespace CandidateReviewClientApp.Controllers
if (model == null)
{
return RedirectToAction("Index");
return RedirectToAction("/Home/Index");
}
return View(model);
@ -37,7 +37,12 @@ namespace CandidateReviewClientApp.Controllers
{
return Redirect("/Home/Enter");
}
return View(APIClient.User);
var model = APIClient.GetRequest<UserViewModel?>($"api/user/profile?id={APIClient.User.Id}");
if (model == null)
{
return RedirectToAction("/Home/Index");
}
return View(model);
}
[HttpPost]
@ -48,17 +53,17 @@ namespace CandidateReviewClientApp.Controllers
Id = model.Id,
Surname = model.Surname,
Name = model.Name,
LastName = model.LastName ?? null,
CompanyId = model.CompanyId ?? null,
LastName = model.LastName,
CompanyId = model.CompanyId,
Email = model.Email,
Password = model.Password,
EmailConfirmed = model.EmailConfirmed,
Role = model.Role,
AvatarFilePath = model.AvatarFilePath ?? null,
PhoneNumber = model.PhoneNumber ?? null
AvatarFilePath = model.AvatarFilePath,
PhoneNumber = model.PhoneNumber
});
Response.Redirect("/User/UserProfile");
Response.Redirect($"/User/UserProfile/{model.Id}");
}
[HttpGet]
@ -68,6 +73,31 @@ namespace CandidateReviewClientApp.Controllers
Response.Redirect("/Home/Enter");
}
[HttpPost]
public void Delete(UserBindingModel model)
{
if (APIClient.User == null)
{
throw new Exception("Доступно только авторизованным пользователям");
}
APIClient.PostRequest($"api/user/delete", new UserBindingModel {
Id = model.Id,
Surname = model.Surname,
Name = model.Name,
LastName = model.LastName,
CompanyId = model.CompanyId,
Email = model.Email,
Password = model.Password,
EmailConfirmed = model.EmailConfirmed,
Role = model.Role,
AvatarFilePath = model.AvatarFilePath,
PhoneNumber = model.PhoneNumber
});
Response.Redirect("/Home/Enter");
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{

View File

@ -0,0 +1,92 @@
using CandidateReviewContracts.BindingModels;
using CandidateReviewContracts.ViewModels;
using Microsoft.AspNetCore.Mvc;
namespace CandidateReviewClientApp.Controllers
{
public class VacancyController : Controller
{
private readonly ILogger<VacancyController> _logger;
public VacancyController(ILogger<VacancyController> logger)
{
_logger = logger;
}
[HttpGet]
public IActionResult Vacancy(int? id)
{
if (APIClient.User == null)
{
return Redirect("~/Home/Enter");
}
if (id.HasValue)
{
APIClient.Vacancy = APIClient.GetRequest<VacancyViewModel?>($"api/vacancy/details?id={id}");
}
var model = APIClient.Vacancy;
return View(model);
}
[HttpGet]
public IActionResult EditVacancy(int? id)
{
if (APIClient.User == null)
{
return Redirect("~/Home/Enter");
}
if (!id.HasValue)
{
return View(new VacancyViewModel());
}
var model = APIClient.GetRequest<VacancyViewModel?>($"api/vacancy/details?id={id}");
return View(model);
}
[HttpPost]
public void EditVacancy(VacancyBindingModel model)
{
if (APIClient.User == null)
{
throw new Exception("Доступно только авторизованным пользователям");
}
if (model.Id != 0)
{
APIClient.PostRequest("api/vacancy/update", model);
}
else
{
APIClient.PostRequest("api/vacancy/create", model);
if (APIClient.Company != null)
{
APIClient.Company?.Vacancies.Add(new VacancyViewModel
{
Id = model.Id,
CompanyId = model.CompanyId,
CreatedAt = model.CreatedAt,
Description = model.Description,
JobTitle = model.JobTitle,
JobType = model.JobType,
Requirements = model.Requirements,
Responsibilities = model.Responsibilities,
Salary = model.Salary,
Status = model.Status,
Tags = model.Tags
});
}
}
Response.Redirect($"/Company/CompanyProfile/{model.CompanyId}");
}
[HttpPost]
public void Delete(int id)
{
if (APIClient.User == null)
{
throw new Exception("Доступно только авторизованным пользователям");
}
APIClient.PostRequest($"api/vacancy/delete", new VacancyBindingModel { Id = id });
Response.Redirect("/Home/Index");
}
}
}

View File

@ -3,54 +3,86 @@
@{
ViewData["Title"] = "Профиль компании";
var userRole = APIClient.User?.Role == CandidateReviewDataModels.Enums.RoleEnum.Сотрудник ? true : false;
}
<div class="container mt-5">
<div class="row g-4">
<div class="col-md-4">
<div class="card">
@if (!string.IsNullOrEmpty(Model.LogoFilePath))
{
<img src="@Model.LogoFilePath" class="card-img-top img-fluid" alt="Логотип компании">
}
<img src="@(Model.LogoFilePath ?? "https://static.thenounproject.com/png/2504969-200.png")"
class="card-img-top img-fluid rounded" alt="Логотип компании">
<div class="card-body">
<h5 class="card-title">@Model.Name</h5>
<p class="card-text text-truncate" style="max-height: 100px; overflow: hidden;">@Model.Description</p>
<a href="@Model.Website" target="_blank" class="btn btn-primary mt-2">@Model.Website</a>
<p class="card-text">@(Model.Description == null ? "Описание отсутствует" : Model.Description) </p>
<a href="@(Model.Website ?? "#")" target="_blank" class="btn btn-primary mt-2">@(Model.Website ?? "Веб-сайт отсутствует")</a> </a>
</div>
</div>
</div>
<div class="col-md-8">
<div class="card">
<div class="card-header">
<div class="card mb-4">
<div class="card-header d-flex justify-content-between align-items-center">
<h2>Информация о компании</h2>
<a asp-action="EditCompanyProfile" asp-controller="Company" asp-route-id="@Model.Id" class="btn btn-primary float-end">Редактировать</a>
@if (userRole)
{
<a asp-action="EditCompanyProfile" asp-controller="Company" asp-route-id="@Model.Id" class="btn btn-primary">Редактировать</a>
}
</div>
<div class="card-body">
<table class="table table-borderless">
<tbody>
<tr>
<th>Название</th>
<td>@Model.Name</td>
</tr>
<tr>
<th>Описание</th>
<td>@Model.Description</td>
</tr>
<tr>
<th>Официальный сайт</th>
<td><a href="@Model.Website" target="_blank">@Model.Website</a></td>
</tr>
<tr>
<th>Адрес</th>
<td>@Model.Address</td>
</tr>
<tr>
<th>Контакты</th>
<td>@Model.Contacts</td>
</tr>
</tbody>
</table>
<dl class="row">
<dt class="col-sm-3">Адрес:</dt>
<dd class="col-sm-9">@(Model.Address?.ToString() ?? "Адрес не указан")</dd>
<dt class="col-sm-3">Контакты:</dt>
<dd class="col-sm-9">@(Model.Contacts?.ToString() ?? "Контакты не указаны")</dd>
</dl>
</div>
</div>
<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<h2>Вакансии компании</h2>
@if (userRole)
{
<a asp-action="EditVacancy" asp-controller="Vacancy" asp-route-companyId="@Model.Id" class="btn btn-success">Добавить вакансию</a>
}
</div>
<div class="card-body">
@if (@Model.Vacancies != null && @Model.Vacancies.Any())
{
<table class="table table-striped">
<thead>
<tr>
<th>Название</th>
<th>Тип занятости</th>
<th>Зарплата</th>
<th>Действия</th>
</tr>
</thead>
<tbody>
@foreach (var vacancy in @Model.Vacancies)
{
<tr>
<td>@vacancy.JobTitle</td>
<td>@vacancy.JobType</td>
<td>@vacancy.Salary</td>
<td>
<a asp-action="VacancyDetails" asp-controller="Vacancy" asp-route-id="@vacancy.Id" class="btn btn-sm btn-info">Просмотр</a>
@if (userRole)
{
<a asp-action="EditVacancy" asp-controller="Vacancy" asp-route-id="@vacancy.Id" class="btn btn-sm btn-warning">Редактировать</a>
<a asp-action="DeleteVacancy" asp-controller="Vacancy" asp-route-id="@vacancy.Id" class="btn btn-sm btn-danger" onclick="return confirm('Вы уверены, что хотите удалить вакансию?');">Удалить</a>
}
</td>
</tr>
}
</tbody>
</table>
}
else
{
<p>Вакансий нет.</p>
}
</div>
</div>
</div>

View File

@ -1,6 +0,0 @@
@{
ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>
<p>Use this page to detail your site's privacy policy.</p>

View File

@ -8,7 +8,6 @@
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
<link rel="stylesheet" href="~/CandidateReviewClientApp.styles.css" asp-append-version="true" />
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
</head>
@ -17,7 +16,7 @@
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container">
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">Candidate Review</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#mainNav" aria-controls="mainNav" aria-expanded="false" aria-label="Toggle navigation">
<button class="navbar-toggler" type="button" onclick="toggleNavbar()" aria-controls="mainNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="mainNav">
@ -31,6 +30,9 @@
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="User" asp-action="UserProfile" asp-route-id="@(APIClient.User?.Id)">Профиль</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Vacancy" asp-action="SearchVacancies">Поиск вакансий</a>
</li>
</ul>
</div>
</div>
@ -48,5 +50,11 @@
</div>
</footer>
@await RenderSectionAsync("Scripts", required: false)
<script>
function toggleNavbar() {
var navbar = document.getElementById('mainNav');
navbar.classList.toggle('show');
}
</script>
</body>
</html>
</html>

View File

@ -9,41 +9,43 @@
<div class="row">
<div class="col-md-4 mb-4">
<div class="card">
@if (!string.IsNullOrEmpty(@Model.AvatarFilePath))
@if (!string.IsNullOrEmpty(@Model?.AvatarFilePath))
{
<img src="@Model.AvatarFilePath" class="card-img-top img-fluid rounded-circle mx-auto d-block" style="max-width: 150px; max-height: 150px;" alt="Аватар пользователя">
<img src="@Model?.AvatarFilePath" class="card-img-top img-fluid rounded-circle mx-auto d-block" style="max-width: 150px; max-height: 150px;" alt="Аватар пользователя">
}
<div class="card-body text-center">
<h5 class="card-title mb-0">
@Model.Name @(string.IsNullOrEmpty(@Model.Surname) ? "" : @Model.Surname) @(string.IsNullOrEmpty(@Model.LastName) ? "" : @Model.LastName)
@Model?.Name @(string.IsNullOrEmpty(@Model?.Surname) ? "" : @Model?.Surname) @(string.IsNullOrEmpty(@Model?.LastName) ? "" : @Model?.LastName)
</h5>
</div>
</div>
</div>
<div class="col-md-8">
<div class="card">
<div class="card-header">
<h2 class="mb-0">Контактная информация</h2>
<div class="btn-group float-end mt-2" role="group" aria-label="Действия">
<a asp-action="UserProfileEdit" asp-controller="User" asp-route-id="@Model?.Id" class="btn btn-primary">Редактировать</a>
<a asp-action="Delete" asp-controller="User" asp-route-id="@Model?.Id" class="btn btn-danger" onclick="return confirm('Вы уверены, что хотите удалить профиль?');">Удалить</a>
<dl class="row mt-3">
<dt class="col-sm-4">Email:</dt>
<dd class="col-sm-8">@Model?.Email</dd>
@if (!string.IsNullOrEmpty(@Model?.PhoneNumber))
{
<dt class="col-sm-4">Телефон:</dt>
<dd class="col-sm-8">@Model?.PhoneNumber</dd>
}
<dt class="col-sm-4">Роль:</dt>
<dd class="col-sm-8">@Model?.Role</dd>
</dl>
<div class="btn-group mt-3" role="group" aria-label="Действия">
<a asp-action="UserProfileEdit" asp-controller="User" asp-route-id="@Model?.Id" class="btn btn-primary">Редактировать профиль</a>
<form asp-action="Delete" asp-controller="User" method="post" onsubmit="return confirm('Вы уверены, что хотите удалить профиль?');">
<input type="hidden" name="id" value="@Model?.Id" />
<button type="submit" class="btn btn-danger">Удалить профиль</button>
</form>
<a asp-action="Logout" asp-controller="User" class="btn btn-secondary">Выйти</a>
</div>
</div>
</div>
</div>
<div class="col-md-8">
<div class="card">
<div class="card-header">
<h2>Мои резюме</h2>
</div>
<div class="card-body">
<dl class="row">
<dt class="col-sm-3">Email</dt>
<dd class="col-sm-9">@Model.Email</dd>
@if (!string.IsNullOrEmpty(@Model.PhoneNumber))
{
<dt class="col-sm-3">Телефон</dt>
<dd class="col-sm-9">@Model.PhoneNumber</dd>
}
<dt class="col-sm-3">Роль</dt>
<dd class="col-sm-9">@Model.Role</dd>
</dl>
</div>
</div>
</div>

View File

@ -0,0 +1,90 @@
@using CandidateReviewContracts.ViewModels
@using CandidateReviewDataModels.Enums
@model VacancyViewModel
@{
var title = @Model.Id <= 0 ? "Создать вакансию" : "Редактировать вакансию";
}
<div class="container">
<h1>@title</h1>
<form method="post" class="row g-3 needs-validation" novalidate>
<input type="hidden" name="id" value="@Model?.Id" />
<input type="hidden" name="companyId" value="@(APIClient.User?.CompanyId)" />
<div class="col-md-6">
<label for="JobTitle" class="form-label">Название должности <span class="text-danger">*</span></label>
<input type="text" class="form-control" id="JobTitle" name="JobTitle" value="@Model?.JobTitle" required placeholder="Введите название должности">
<div class="invalid-feedback">Пожалуйста, введите название должности.</div>
</div>
<div class="col-md-6">
<label for="requirements" class="form-label">Требования <span class="text-danger">*</span></label>
<textarea class="form-control" id="requirements" name="requirements" rows="3" placeholder="Введите требования к вакансии">@Model?.Requirements</textarea>
</div>
<div class="col-md-6">
<label for="Responsibilities" class="form-label">Обязанности <span class="text-danger">*</span></label>
<textarea class="form-control" id="Responsibilities" name="Responsibilities" rows="3" placeholder="Введите обязанности">@Model?.Responsibilities</textarea>
</div>
<div class="col-md-6">
<label for="JobType" class="form-label">Тип занятости</label>
<select id="JobType" name="JobType" class="form-control" asp-items="@(new SelectList(Enum.GetValues(typeof(JobTypeEnum)).Cast<JobTypeEnum>()))"></select>
</div>
<div class="col-md-6">
<label for="salary" class="form-label">Заработная плата (руб.)</label>
<input type="text" class="form-control" id="salary" name="salary" value="@Model?.Salary" placeholder="Введите заработную плату или поставьте '-'">
</div>
<div class="col-md-6">
<label for="description" class="form-label">Описание</label>
<input type="text" class="form-control" id="description" name="description" value="@Model?.Description" placeholder="Введите описание вакансии">
</div>
<div class="col-md-6">
<label for="Status" class="form-label">Статус вакансии</label>
<select id="Status" name="Status" class="form-control" asp-items="@(new SelectList(Enum.GetValues(typeof(VacancyStatusEnum)).Cast<VacancyStatusEnum>()))"></select>
</div>
<input type="hidden" name="createdAt" value="@Model?.CreatedAt" />
@{
var tagsString = @Model?.Tags;
var displayedTags = string.IsNullOrEmpty(tagsString) ? "" : string.Join(", ", tagsString.Split(',').Select(t => t.Trim()));
}
<div class="col-md-6">
<label for="tags" class="form-label">Тэги</label>
<input type="text" class="form-control" id="tags" name="tags" value="@displayedTags" placeholder="Введите тэги через запятую">
</div>
@* <input type="hidden" name="createdAt" value="@(APIClient.Company?.Vacancies.Add(Model))" />
*@
<div class="col-12">
<button type="submit" class="btn btn-primary">Сохранить</button>
</div>
</form>
</div>
<script>
(function () {
'use strict'
var forms = document.querySelectorAll('.needs-validation')
Array.prototype.slice.call(forms)
.forEach(function (form) {
form.addEventListener('submit', function (event) {
if (!form.checkValidity()) {
event.preventDefault()
event.stopPropagation()
}
form.classList.add('was-validated')
}, false)
})
})()
</script>

View File

@ -0,0 +1,40 @@
@* @using CandidateReviewContracts.ViewModels
@model VacancyViewModel
@{
ViewData["Title"] = "Поиск вакансий";
}
<div class="container mt-5">
<div class="row justify-content-center">
<div class="col-md-6">
<h1>Поиск вакансий</h1>
<form asp-action="Search" asp-controller="Vacancy" method="get">
<div class="input-group mb-3">
<input type="text" class="form-control" name="searchTerm" placeholder="Введите поисковый запрос" value="@Model?.SearchTerm">
<button class="btn btn-primary" type="submit">Поиск</button>
</div>
</form>
@if (@Model != null && @Model.Vacancies != null)
{
<h2>Результаты поиска:</h2>
@if (Model.Vacancies.Count > 0)
{
<ul>
@foreach (var vacancy in Model.Vacancies)
{
<li>@vacancy.JobTitle</li>
}
</ul>
}
else
{
<p>Вакансий не найдено.</p>
}
}
</div>
</div>
</div>
*@

View File

@ -0,0 +1,54 @@
@using Microsoft.AspNetCore.Mvc.TagHelpers
@using CandidateReviewContracts.ViewModels
@model VacancyViewModel
@{
ViewData["Title"] = "Информация о вакансии";
}
<div class="container mt-5">
<div class="card">
<div class="card-header">
<h2>@Model.JobTitle</h2>
<input type="hidden" name="id" value="@Model?.Id" />
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<dl class="row">
<dt class="col-sm-4">Компания:</dt>
<dd class="col-sm-8">@Model.CompanyId</dd>
<dt class="col-sm-4">Тип занятости:</dt>
<dd class="col-sm-8">@Model.JobType</dd>
<dt class="col-sm-4">Зарплата:</dt>
<dd class="col-sm-8">@Model.Salary</dd>
<dt class="col-sm-4">Дата публикации:</dt>
<dd class="col-sm-8">@Model.CreatedAt.ToShortDateString()</dd>
<dt class="col-sm-4">Статус:</dt>
<dd class="col-sm-8">@Model.Status</dd>
<dt class="col-sm-4">Теги:</dt>
<dd class="col-sm-8">@Model.Tags</dd>
</dl>
</div>
<div class="col-md-6">
<dl class="row">
<dt class="col-sm-4">Требования:</dt>
<dd class="col-sm-8">@Html.Raw(Model.Requirements)</dd>
<dt class="col-sm-4">Обязанности:</dt>
<dd class="col-sm-8">@Html.Raw(Model.Responsibilities)</dd>
<dt class="col-sm-4">Описание:</dt>
<dd class="col-sm-8">@Html.Raw(Model.Description)</dd>
</dl>
</div>
</div>
</div>
</div>
</div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -1,4 +1,5 @@
using CandidateReviewDataModels.Models;
using CandidateReviewContracts.ViewModels;
using CandidateReviewDataModels.Models;
namespace CandidateReviewContracts.BindingModels
{
@ -16,5 +17,7 @@ namespace CandidateReviewContracts.BindingModels
public string? Contacts { get; set; }
public int Id { get; set; }
public List<IVacancyModel> Vacancies { get; set; } = new();
}
}

View File

@ -16,5 +16,7 @@ namespace CandidateReviewContracts.ViewModels
public string? Contacts { get; set; }
public int Id { get; set; }
public List<VacancyViewModel> Vacancies { get; set; } = new();
}
}

View File

@ -53,7 +53,7 @@ namespace CandidateReviewDatabaseImplement.Models
Salary = model.Salary,
Description = model.Description,
Status = model.Status,
CreatedAt = model.CreatedAt,
CreatedAt = DateTime.Now.ToUniversalTime(),
Tags = model.Tags
};
}

View File

@ -2,7 +2,9 @@
using CandidateReviewContracts.BusinessLogicsContracts;
using CandidateReviewContracts.SearchModels;
using CandidateReviewContracts.ViewModels;
using CandidateReviewDataModels.Models;
using Microsoft.AspNetCore.Mvc;
using System.Linq;
namespace CandidateReviewRestApi.Controllers
{
@ -12,10 +14,12 @@ namespace CandidateReviewRestApi.Controllers
{
private readonly ILogger _logger;
private readonly ICompanyLogic _logic;
public CompanyController(ICompanyLogic logic, ILogger<CompanyController> logger)
private readonly IVacancyLogic _vacancyLogic;
public CompanyController(ICompanyLogic logic, IVacancyLogic vacancyLogic, ILogger<CompanyController> logger)
{
_logger = logger;
_logic = logic;
_vacancyLogic = vacancyLogic;
}
[HttpGet]
@ -77,5 +81,17 @@ namespace CandidateReviewRestApi.Controllers
throw;
}
}
/*private CompanyBindingModel GetCompanyWithVacancies(CompanyBindingModel model)
{
var vacancies = _vacancyLogic.ReadList(new VacancySearchModel { CompanyId = model.Id });
if (vacancies != null)
{
model.Vacancies = vacancies.Where(v => v.CompanyId == model.Id)
.Select(v => (IVacancyModel)v)
.ToList();
}
return model;
}*/
}
}

View File

@ -80,5 +80,19 @@ namespace CandidateReviewRestApi.Controllers
throw;
}
}
[HttpPost]
public void Delete(UserBindingModel model)
{
try
{
_logic.Delete(model);
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка удаления профиля пользователя");
throw;
}
}
}
}

View File

@ -0,0 +1,80 @@
using CandidateReviewContracts.BindingModels;
using CandidateReviewContracts.BusinessLogicsContracts;
using CandidateReviewContracts.SearchModels;
using CandidateReviewContracts.ViewModels;
using Microsoft.AspNetCore.Mvc;
namespace CandidateReviewRestApi.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class VacancyController : Controller
{
private readonly ILogger _logger;
private readonly IVacancyLogic _logic;
public VacancyController(IVacancyLogic logic, ILogger<VacancyController> logger)
{
_logger = logger;
_logic = logic;
}
[HttpGet]
public VacancyViewModel? Details(int id)
{
try
{
return _logic.ReadElement(new VacancySearchModel
{
Id = id
});
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка получения вакансии");
throw;
}
}
[HttpPost]
public void Create(VacancyBindingModel model)
{
try
{
_logic.Create(model);
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка создания вакансии");
throw;
}
}
[HttpPost]
public void Update(VacancyBindingModel model)
{
try
{
_logic.Update(model);
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка обновления вакансии");
throw;
}
}
[HttpDelete]
public void Delete(VacancyBindingModel model)
{
try
{
_logic.Delete(model);
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка удаления вакансии");
throw;
}
}
}
}