diff --git a/src/InternshipSystem.Api/Controllers/CompaniesController.cs b/src/InternshipSystem.Api/Controllers/CompaniesController.cs index 39011e6..59b99ad 100644 --- a/src/InternshipSystem.Api/Controllers/CompaniesController.cs +++ b/src/InternshipSystem.Api/Controllers/CompaniesController.cs @@ -3,8 +3,10 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using InternshipSystem.Api.Queries; +using InternshipSystem.Api.Queries.SearchQuery; using InternshipSystem.Core; using InternshipSystem.Repository; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; @@ -35,9 +37,9 @@ namespace InternshipSystem.Api.Controllers [HttpGet] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] - public async Task> SearchByNameAsync([FromQuery] SearchQuery searchQuery, CancellationToken cancellationToken) => + public async Task>> SearchByNameAsync([FromQuery] CompanySearchQuery searchQuery, CancellationToken cancellationToken) => await Context.Companies - .Where(c => c.Name.ToLower().Contains(searchQuery.Query.ToLower())) + .Where(c => c.Name.ToLower().Contains(searchQuery.Name.ToLower())) .OrderBy(o => o.Name) .Skip(searchQuery.Page * searchQuery.PerPage) .Take(searchQuery.PerPage) @@ -54,14 +56,14 @@ namespace InternshipSystem.Api.Controllers [HttpGet("{companyId}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] - public async Task> SearchBranchesByAddress([FromQuery] SearchQuery searchQuery, long companyId, CancellationToken token) + public async Task>> SearchBranchesByAddress([FromQuery] BranchOfficeSearchQuery searchQuery, long companyId, CancellationToken token) { var company = await Context.Companies.Where(c => c.Id == companyId).FirstAsync(token); return await Context.Entry(company) .Collection(c => c.Branches) .Query() - .Where(office => office.Address.City.Contains(searchQuery.Query.ToLower())) + .Where(office => office.Address.City.ToLower().Contains(searchQuery.City.ToLower())) .Skip(searchQuery.Page * searchQuery.PerPage) .Take(searchQuery.PerPage) .ToListAsync(token); @@ -79,6 +81,7 @@ namespace InternshipSystem.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status404NotFound)] + [Authorize] public async Task UpdateCompany([FromBody] CompanyForm companyForm, CancellationToken cancellationToken) { var validator = new CompanyForm.Validator(); @@ -129,6 +132,7 @@ namespace InternshipSystem.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status404NotFound)] + [Authorize] public async Task DeleteCompany(long companyId, CancellationToken cancellationToken) { var companyToDelete = await PractiseSupervisorDbContext.Companies @@ -159,6 +163,7 @@ namespace InternshipSystem.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status404NotFound)] + [Authorize] public async Task UpdateBranch([FromBody] BranchOfficeForm branchOfficeForm, long companyId, CancellationToken cancellationToken) { var validator = new BranchOfficeForm.Validator(); @@ -225,6 +230,7 @@ namespace InternshipSystem.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status404NotFound)] + [Authorize] public async Task DeleteBranch(long branchOfficeId, CancellationToken cancellationToken) { var company = diff --git a/src/InternshipSystem.Api/Controllers/StaticPagesController.cs b/src/InternshipSystem.Api/Controllers/StaticPagesController.cs index e819202..67fdde1 100644 --- a/src/InternshipSystem.Api/Controllers/StaticPagesController.cs +++ b/src/InternshipSystem.Api/Controllers/StaticPagesController.cs @@ -2,8 +2,10 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using InternshipSystem.Api.Queries; using InternshipSystem.Core; using InternshipSystem.Repository; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; @@ -52,5 +54,86 @@ namespace InternshipSystem.Api.Controllers return Ok(page); } + + [HttpPut] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [Authorize] + public async Task UpdateStaticPage([FromBody] StaticPageForm staticPageForm, CancellationToken cancellationToken) + { + var validator = new StaticPageForm.Validator(); + var validationResult = await validator.ValidateAsync(staticPageForm, cancellationToken); + + if (!validationResult.IsValid) + { + return BadRequest(validationResult.ToString()); + } + + if (!string.IsNullOrEmpty(staticPageForm.AccessName)) + { + var pageWithSameAccessName = await Context.StaticPages + .FirstOrDefaultAsync(sp => sp.AccessName.ToLower().Trim().Equals(staticPageForm.AccessName.ToLower().Trim()), cancellationToken: cancellationToken); + + if (pageWithSameAccessName != null) + { + return BadRequest($"Static page with access name: {staticPageForm.AccessName} already exist"); + } + } + + if (staticPageForm.Id.HasValue) + { + var pageToUpdate = await Context.StaticPages.FindAsync(staticPageForm.Id); + + if (pageToUpdate == null) + { + return NotFound($"Static page with id: {staticPageForm.Id} does not exist"); + } + + pageToUpdate.AccessName = string.IsNullOrEmpty(staticPageForm.AccessName) ? pageToUpdate.AccessName : staticPageForm.AccessName; + pageToUpdate.Title = string.IsNullOrEmpty(staticPageForm.Title) ? pageToUpdate.Title : staticPageForm.Title; + pageToUpdate.TitleEng = string.IsNullOrEmpty(staticPageForm.TitleEng) ? pageToUpdate.TitleEng : staticPageForm.TitleEng; + pageToUpdate.Content = string.IsNullOrEmpty(staticPageForm.Content) ? pageToUpdate.Content : staticPageForm.Content; + pageToUpdate.ContentEng = string.IsNullOrEmpty(staticPageForm.ContentEng) ? pageToUpdate.ContentEng : staticPageForm.ContentEng; + } + else + { + var newStaticPage = new StaticPage + { + AccessName = staticPageForm.AccessName.ToLower().Trim(), + Title = staticPageForm.Title, + TitleEng = staticPageForm.Title, + Content = staticPageForm.Content, + ContentEng = staticPageForm.ContentEng, + }; + await Context.StaticPages.AddAsync(newStaticPage, cancellationToken); + } + + await Context.SaveChangesAsync(cancellationToken); + + return Ok($"Static page updated successfully"); + } + + + [HttpDelete("{accessName}")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [Authorize] + public async Task DeleteStaticPage(string accessName, CancellationToken cancellationToken) + { + var pageToDelete = await Context.StaticPages + .FirstOrDefaultAsync(sp => sp.AccessName.ToLower().Trim().Equals(accessName.ToLower().Trim()), cancellationToken: cancellationToken); + + if (pageToDelete == null) + { + return NotFound($"Static page with access name: {accessName} does not exist"); + } + + Context.StaticPages.Attach(pageToDelete); + Context.StaticPages.Remove(pageToDelete); + await Context.SaveChangesAsync(cancellationToken); + return Ok($"Static page with access name: {accessName} deleted successfully"); + } } } \ No newline at end of file diff --git a/src/InternshipSystem.Api/Controllers/StudentController.cs b/src/InternshipSystem.Api/Controllers/StudentController.cs deleted file mode 100644 index 165dc6f..0000000 --- a/src/InternshipSystem.Api/Controllers/StudentController.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; -using InternshipSystem.Api.Queries; -using InternshipSystem.Api.Security; -using InternshipSystem.Core; -using InternshipSystem.Repository; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; - -namespace InternshipSystem.Api.Controllers -{ - [Route("student")] - [ApiController] - public class StudentController : ControllerBase - { - private readonly InternshipDbContext _context; - - public StudentController(InternshipDbContext context) - { - _context = context; - } - - [HttpGet("current")] - [Authorize] - public async Task GetCurrentStudentData([FromServices] User user, CancellationToken cancellationToken) - { - return await _context.Students.FindAsync(user.PersonNumber); - } - - [HttpPut("updateCurrent")] - [Authorize] - public async Task UpdateStudentData([FromBody] StudentForm studentNewData, [FromServices] User user, CancellationToken cancellationToken) - { - var validator = new StudentForm.Validator(); - var validationResult = await validator.ValidateAsync(studentNewData, cancellationToken); - - if (!validationResult.IsValid || !user.PersonNumber.Equals(studentNewData.Id)) - { - return BadRequest(); - } - - var currentStudent = await _context.Students.FindAsync(user.PersonNumber); - - currentStudent.AlbumNumber = studentNewData.AlbumNumber ?? currentStudent.AlbumNumber; - currentStudent.FirstName = string.IsNullOrEmpty(studentNewData.FirstName) ? currentStudent.FirstName : studentNewData.FirstName; - currentStudent.LastName = string.IsNullOrEmpty(studentNewData.LastName) ? currentStudent.LastName : studentNewData.LastName; - currentStudent.Email = string.IsNullOrEmpty(studentNewData.Email) ? currentStudent.Email : studentNewData.Email; - currentStudent.Course = string.IsNullOrEmpty(studentNewData.Course) ? currentStudent.Course : studentNewData.Course; - currentStudent.Semester = studentNewData.Semester ?? currentStudent.Semester; - - await _context.SaveChangesAsync(cancellationToken); - - return Ok(); - } - } -} \ No newline at end of file diff --git a/src/InternshipSystem.Api/Controllers/StudentsController.cs b/src/InternshipSystem.Api/Controllers/StudentsController.cs new file mode 100644 index 0000000..a125f84 --- /dev/null +++ b/src/InternshipSystem.Api/Controllers/StudentsController.cs @@ -0,0 +1,99 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using InternshipSystem.Api.Queries; +using InternshipSystem.Api.Security; +using InternshipSystem.Core; +using InternshipSystem.Repository; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; + +namespace InternshipSystem.Api.Controllers +{ + [Route("students")] + [ApiController] + public class StudentsController : ControllerBase + { + private readonly InternshipDbContext _context; + + public StudentsController(InternshipDbContext context) + { + _context = context; + } + + [HttpGet("current")] + [Authorize] + public async Task> GetCurrentStudentData([FromServices] User user, CancellationToken cancellationToken) + { + return await _context.Students.FindAsync(user.PersonNumber); + } + + [HttpPut("current")] + [Authorize] + public async Task UpdateCurrentStudentData([FromBody] CurrentStudentForm studentNewData, [FromServices] User user, CancellationToken cancellationToken) + { + var currentStudent = await _context.Students.FindAsync(user.PersonNumber); + + currentStudent.AlbumNumber = studentNewData.AlbumNumber ?? currentStudent.AlbumNumber; + currentStudent.FirstName = string.IsNullOrEmpty(studentNewData.FirstName) ? currentStudent.FirstName : studentNewData.FirstName; + currentStudent.LastName = string.IsNullOrEmpty(studentNewData.LastName) ? currentStudent.LastName : studentNewData.LastName; + currentStudent.Email = string.IsNullOrEmpty(studentNewData.Email) ? currentStudent.Email : studentNewData.Email; + currentStudent.Course = string.IsNullOrEmpty(studentNewData.Course) ? currentStudent.Course : studentNewData.Course; + currentStudent.Semester = studentNewData.Semester ?? currentStudent.Semester; + + await _context.SaveChangesAsync(cancellationToken); + + return Ok($"Student updated successfully"); + } + + [HttpGet("{studentPersonNumber}")] + [Authorize] + public async Task> GetStudentByPersonNumber(long studentPersonNumber, CancellationToken cancellationToken) => + await _context.Students.FindAsync(studentPersonNumber); + + [HttpGet] + [Authorize] + public async Task>> GetStudents([FromBody] StudentSearchQuery searchQuery, CancellationToken cancellationToken) => + await _context.Students + .Where(s => !searchQuery.AlbumNumber.HasValue || s.AlbumNumber.Equals(searchQuery.AlbumNumber)) + .Where(s => string.IsNullOrEmpty(searchQuery.FirstName) || s.FirstName.ToLower().Contains(searchQuery.FirstName.ToLower())) + .Where(s => string.IsNullOrEmpty(searchQuery.LastName) || s.LastName.ToLower().Contains(searchQuery.LastName.ToLower())) + .OrderBy(s => s.AlbumNumber) + .Skip(searchQuery.Page * searchQuery.PerPage) + .Take(searchQuery.PerPage) + .ToListAsync(cancellationToken); + + [HttpPut] + [Authorize] + public async Task UpdateStudentData([FromBody] StudentForm studentNewData, CancellationToken cancellationToken) + { + var validator = new StudentForm.Validator(); + var validationResult = await validator.ValidateAsync(studentNewData, cancellationToken); + + if (!validationResult.IsValid) + { + return BadRequest(validationResult.ToString()); + } + + var currentStudent = await _context.Students.FindAsync(studentNewData.Id); + + if (currentStudent == null) + { + return NotFound($"Student with id: {studentNewData.Id} does not exist"); + } + + currentStudent.AlbumNumber = studentNewData.AlbumNumber ?? currentStudent.AlbumNumber; + currentStudent.FirstName = string.IsNullOrEmpty(studentNewData.FirstName) ? currentStudent.FirstName : studentNewData.FirstName; + currentStudent.LastName = string.IsNullOrEmpty(studentNewData.LastName) ? currentStudent.LastName : studentNewData.LastName; + currentStudent.Email = string.IsNullOrEmpty(studentNewData.Email) ? currentStudent.Email : studentNewData.Email; + currentStudent.Course = string.IsNullOrEmpty(studentNewData.Course) ? currentStudent.Course : studentNewData.Course; + currentStudent.Semester = studentNewData.Semester ?? currentStudent.Semester; + + await _context.SaveChangesAsync(cancellationToken); + + return Ok($"Student updated successfully"); + } + } +} \ No newline at end of file diff --git a/src/InternshipSystem.Api/Queries/BranchOfficeForm.cs b/src/InternshipSystem.Api/Queries/BranchOfficeForm.cs index 75219d5..fd240bf 100644 --- a/src/InternshipSystem.Api/Queries/BranchOfficeForm.cs +++ b/src/InternshipSystem.Api/Queries/BranchOfficeForm.cs @@ -20,15 +20,15 @@ namespace InternshipSystem.Api.Queries string.IsNullOrEmpty(c.Country) || string.IsNullOrEmpty(c.City) || string.IsNullOrEmpty(c.PostalCode) || string.IsNullOrEmpty(c.Street) || string.IsNullOrEmpty(c.Building)); - RuleFor(b => b.Country).NotNull() + RuleFor(b => b.Country).NotEmpty() .When(b => !b.Id.HasValue); - RuleFor(b => b.City).NotNull() + RuleFor(b => b.City).NotEmpty() .When(b => !b.Id.HasValue); - RuleFor(b => b.PostalCode).NotNull() + RuleFor(b => b.PostalCode).NotEmpty() .When(b => !b.Id.HasValue); - RuleFor(b => b.Street).NotNull() + RuleFor(b => b.Street).NotEmpty() .When(b => !b.Id.HasValue); - RuleFor(b => b.Building).NotNull() + RuleFor(b => b.Building).NotEmpty() .When(b => !b.Id.HasValue); } } diff --git a/src/InternshipSystem.Api/Queries/CurrentStudentForm.cs b/src/InternshipSystem.Api/Queries/CurrentStudentForm.cs new file mode 100644 index 0000000..134302a --- /dev/null +++ b/src/InternshipSystem.Api/Queries/CurrentStudentForm.cs @@ -0,0 +1,12 @@ +namespace InternshipSystem.Api.Queries +{ + public class CurrentStudentForm + { + public int? AlbumNumber { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public string Email { get; set; } + public string Course { get; set; } + public int? Semester { get; set; } + } +} \ No newline at end of file diff --git a/src/InternshipSystem.Api/Queries/SearchQuery/BranchOfficeSearchQuery.cs b/src/InternshipSystem.Api/Queries/SearchQuery/BranchOfficeSearchQuery.cs new file mode 100644 index 0000000..d91df7c --- /dev/null +++ b/src/InternshipSystem.Api/Queries/SearchQuery/BranchOfficeSearchQuery.cs @@ -0,0 +1,9 @@ +using InternshipSystem.Api.Queries.SearchQuery; + +namespace InternshipSystem.Api.Controllers +{ + public class BranchOfficeSearchQuery : SearchQuery + { + public string City { get; set; } = ""; + } +} \ No newline at end of file diff --git a/src/InternshipSystem.Api/Queries/SearchQuery/CompanySearchQuery.cs b/src/InternshipSystem.Api/Queries/SearchQuery/CompanySearchQuery.cs new file mode 100644 index 0000000..b1723c7 --- /dev/null +++ b/src/InternshipSystem.Api/Queries/SearchQuery/CompanySearchQuery.cs @@ -0,0 +1,10 @@ +namespace InternshipSystem.Api.Queries.SearchQuery +{ + public class CompanySearchQuery : SearchQuery + { + /// + /// Value against which collection will be queried + /// + public string Name { get; set; } = ""; + } +} \ No newline at end of file diff --git a/src/InternshipSystem.Api/Queries/SearchQuery.cs b/src/InternshipSystem.Api/Queries/SearchQuery/SearchQuery.cs similarity index 62% rename from src/InternshipSystem.Api/Queries/SearchQuery.cs rename to src/InternshipSystem.Api/Queries/SearchQuery/SearchQuery.cs index fc49350..23eb580 100644 --- a/src/InternshipSystem.Api/Queries/SearchQuery.cs +++ b/src/InternshipSystem.Api/Queries/SearchQuery/SearchQuery.cs @@ -1,12 +1,7 @@ -namespace InternshipSystem.Api.Queries +namespace InternshipSystem.Api.Queries.SearchQuery { public class SearchQuery { - /// - /// Value against which collection will be queried - /// - public string Query { get; set; } = ""; - /// /// Which part of the collections to retrieve /// diff --git a/src/InternshipSystem.Api/Queries/SearchQuery/StudentSearchQuery.cs b/src/InternshipSystem.Api/Queries/SearchQuery/StudentSearchQuery.cs new file mode 100644 index 0000000..ff36db0 --- /dev/null +++ b/src/InternshipSystem.Api/Queries/SearchQuery/StudentSearchQuery.cs @@ -0,0 +1,11 @@ +using InternshipSystem.Api.Queries.SearchQuery; + +namespace InternshipSystem.Api.Controllers +{ + public class StudentSearchQuery : SearchQuery + { + public int? AlbumNumber { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + } +} \ No newline at end of file diff --git a/src/InternshipSystem.Api/Queries/StaticPageForm.cs b/src/InternshipSystem.Api/Queries/StaticPageForm.cs new file mode 100644 index 0000000..fc79b4c --- /dev/null +++ b/src/InternshipSystem.Api/Queries/StaticPageForm.cs @@ -0,0 +1,36 @@ +using FluentValidation; + +namespace InternshipSystem.Api.Queries +{ + public class StaticPageForm + { + public long? Id { get; set; } + public string AccessName { get; set; } + public string Title { get; set; } + public string TitleEng { get; set; } + public string Content { get; set; } + public string ContentEng { get; set; } + + public class Validator : AbstractValidator + { + public Validator() + { + RuleFor(sp => sp.Id).NotNull() + .When(sp => + string.IsNullOrEmpty(sp.AccessName) || string.IsNullOrEmpty(sp.Title) || + string.IsNullOrEmpty(sp.TitleEng) || string.IsNullOrEmpty(sp.Content) || + string.IsNullOrEmpty(sp.ContentEng)); + RuleFor(sp => sp.AccessName).NotEmpty() + .When(sp => !sp.Id.HasValue); + RuleFor(sp => sp.Title).NotEmpty() + .When(sp => !sp.Id.HasValue); + RuleFor(sp => sp.TitleEng).NotEmpty() + .When(sp => !sp.Id.HasValue); + RuleFor(sp => sp.Content).NotEmpty() + .When(sp => !sp.Id.HasValue); + RuleFor(sp => sp.ContentEng).NotEmpty() + .When(sp => !sp.Id.HasValue); + } + } + } +} \ No newline at end of file diff --git a/src/InternshipSystem.Api/Queries/StudentForm.cs b/src/InternshipSystem.Api/Queries/StudentForm.cs index d9ab467..f58b19c 100644 --- a/src/InternshipSystem.Api/Queries/StudentForm.cs +++ b/src/InternshipSystem.Api/Queries/StudentForm.cs @@ -5,7 +5,7 @@ namespace InternshipSystem.Api.Queries { public class StudentForm { - public long? Id { get; set; } + public long Id { get; set; } public int? AlbumNumber { get; set; } public string FirstName { get; set; } public string LastName { get; set; }