Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor bookingRequest into service and improve error handling + front-end refactor #114

Merged
merged 12 commits into from
Apr 20, 2024
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
using kabinizer_api.Dtos.BookingRequest;
using kabinizer_api.Model;
using kabinizer_api.Services;
using kabinizer_api.Services.BookingRequest;
using kabinizer_api.Services.Export;
using kabinizer_data;
using kabinizer_data.Entities;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
Expand All @@ -12,71 +11,124 @@ namespace kabinizer_api.Controllers;

[Route("api/[controller]")]
[ApiController]
public class BookingRequestController(EntityContext entityContext, ITokenService tokenService) : ControllerBase
public class BookingRequestController(
EntityContext entityContext,
BookingRequestService bookingRequestService
) : ControllerBase
{
[HttpGet]
public IEnumerable<BookingRequest> GetBookingRequests()
[HttpGet("{id:guid}")]
[ProducesResponseType(200, Type = typeof(BookingRequestDto))]
[ProducesResponseType(404, Type = typeof(string))]
public async Task<ActionResult<BookingRequestDto>> GetBookingRequest(Guid id)
{
var currentUserId = tokenService.GetUserId();
return entityContext.BookingRequests
.Include(br => br.User)
.Include(br => br.Period)
.Where(b => b.UserId == currentUserId)
.AsEnumerable().Select(BookingRequest.FromModel);
try
{
var bookingRequest = await bookingRequestService.GetBookingRequest(id);
if (bookingRequest == null)
{
return NotFound("Booking request does not exist or does not belong to the current user");
}

return Ok(BookingRequestDto.FromModel(bookingRequest));
}
catch (Exception ex)
{
return NotFound(ex.Message);
}
}

[HttpPost]
public void AddBookingRequests([Required] IEnumerable<CreateBookingRequestDto> requests)
[HttpGet]
[ProducesResponseType(200, Type = typeof(IEnumerable<BookingRequestDto>))]
[ProducesResponseType(404, Type = typeof(string))]
public async Task<ActionResult<IEnumerable<BookingRequestDto>>> GetBookingRequests()
{
var currentUserId = tokenService.GetUserId();
var periodIds = requests.Select(e => e.PeriodId).ToList();

var periods = entityContext.Periods
.Where(p => periodIds.Contains(p.Id))
.Include(p => p.Draw)
.ToList();

if (periods.Count != periodIds.Count)
try
{
throw new Exception("One or more periods do not exist");
var bookingRequests = await bookingRequestService.GetBookingRequests();
return Ok(bookingRequests.Select(BookingRequestDto.FromModel));
}

var periodsWithoutDraw = periods.Where(p => p.Draw == null).ToList();
if (periodsWithoutDraw.Count != 0)
catch (Exception ex)
{
throw new Exception("One or more periods are not part of a draw");
return NotFound(ex.Message);
}

var periodsWithEndedDraw = periods.Where(p => p.Draw?.DeadlineEnd > DateTime.Now).ToList();
if (periodsWithEndedDraw.Count != 0)
}

[HttpGet("user/{userId:guid}")]
[ProducesResponseType(200, Type = typeof(IEnumerable<BookingRequestDto>))]
[ProducesResponseType(404, Type = typeof(string))]
public async Task<ActionResult<IEnumerable<BookingRequestDto>>> GetBookingRequestsByUser(Guid userId)
{
try
{
throw new Exception("Cannot make a booking request for a draw that has ended");
var bookingRequests = await bookingRequestService.GetBookingRequestsByUser(userId);
return Ok(bookingRequests.Select(BookingRequestDto.FromModel));
}
catch (Exception ex)
{
return NotFound(ex.Message);
}
}

[HttpGet("period/{periodId:guid}")]
[ProducesResponseType(200, Type = typeof(IEnumerable<BookingRequestDto>))]
[ProducesResponseType(404, Type = typeof(string))]
public async Task<ActionResult<IEnumerable<BookingRequestDto>>> GetBookingRequestsByPeriod(Guid periodId)
{
try
{
var bookingRequests = await bookingRequestService.GetBookingRequestsByPeriod(periodId);
if (bookingRequests.Count == 0)
{
return NotFound("No booking requests found for the period");
}

return Ok(bookingRequests.Select(BookingRequestDto.FromModel));
}
catch (Exception ex)
{
return NotFound(ex.Message);
}

var bookingRequestEntities = periodIds.Select(id => new BookingRequestEntity(currentUserId, id));
entityContext.BookingRequests.AddRange(bookingRequestEntities);
entityContext.SaveChanges();
}

[HttpDelete]
public bool DeleteBookingRequests([Required] IEnumerable<Guid> requests)
[HttpPost]
[ProducesResponseType(200, Type = typeof(BookingRequestDto))]
[ProducesResponseType(400, Type = typeof(string))]
public async Task<ActionResult<IEnumerable<BookingRequestDto>>> AddBookingRequests([Required] IEnumerable<CreateBookingRequestDto> requests)
{
var currentUserId = tokenService.GetUserId();
try
{
var bookingRequest = await bookingRequestService.AddBookingRequest(requests.First());
if (bookingRequest == null)
{
return BadRequest("Booking request could not be added");
}

foreach (Guid requestId in requests)
return Ok(BookingRequestDto.FromModel(bookingRequest));
}
catch (Exception e)
{
BookingRequestEntity entityToRemove = entityContext.BookingRequests.Single(br => br.Id == requestId);
return BadRequest(e.Message);
}
}

if (entityToRemove.UserId != currentUserId)
[HttpDelete]
[ProducesResponseType(200, Type = typeof(string))]
[ProducesResponseType(400, Type = typeof(string))]
public async Task<IActionResult> DeleteBookingRequests([Required] IEnumerable<Guid> requests)
{
try
{
foreach (Guid request in requests)
{
throw new Exception("You cannot remove a booking request for another user");
await bookingRequestService.DeleteBookingRequest(request);
}

entityContext.BookingRequests.Remove(entityToRemove);
return Ok("Booking requests deleted");
}
catch (Exception e)
{
return BadRequest(e.Message);
}

entityContext.SaveChanges();
return true;
}

[HttpGet]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using kabinizer_data.Entities;

namespace kabinizer_api.Dtos.BookingRequest;

public class BookingRequestDto
{
public Guid Id { get; set; }
public Guid UserId { get; set; }
public Guid PeriodId { get; set; }
public DateTime CreatedDate { get; set; }
public Guid CreatedBy { get; set; }
public DateTime? UpdatedDate { get; set; }
public Guid? UpdatedBy { get; set; }

public static BookingRequestDto FromModel(BookingRequestEntity e)
{
return new BookingRequestDto
{
Id = e.Id,
UserId = e.UserId,
PeriodId = e.PeriodId,
CreatedDate = e.CreatedDate,
CreatedBy = e.CreatedBy,
UpdatedDate = e.UpdatedDate,
UpdatedBy = e.UpdatedBy
};
}
}
4 changes: 2 additions & 2 deletions kabinizer-back-end/kabinizer-api/Model/Period.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

namespace kabinizer_api.Model;

public record Period(Guid Id, DateTime PeriodStart, DateTime PeriodEnd, string Title, Guid DrawId)
public record Period(Guid Id, DateTime PeriodStart, DateTime PeriodEnd, string? Title, Guid DrawId)
{
public Period(DateTime periodStart, DateTime periodEnd, string title, Guid DrawId)
public Period(DateTime periodStart, DateTime periodEnd, string? title, Guid DrawId)
: this(Guid.NewGuid(), periodStart, periodEnd, title, DrawId)
{
}
Expand Down
2 changes: 1 addition & 1 deletion kabinizer-back-end/kabinizer-api/Model/User.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace kabinizer_api.Model;

public record User(Guid Id, string Name)
public record User(Guid Id, string? Name)
{
public static User FromEntity(UserEntity u)
{
Expand Down
3 changes: 3 additions & 0 deletions kabinizer-back-end/kabinizer-api/Program.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
using kabinizer_api.Services;
using kabinizer_api.Services.BookingRequest;
using kabinizer_api.Services.Draw;
using kabinizer_data;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.EntityFrameworkCore;
using Microsoft.Identity.Web;
using Microsoft.OpenApi.Models;
using System.Text.Json.Serialization;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors();
builder.Services.AddScoped<DrawService>();
builder.Services.AddScoped<PeriodService>();
builder.Services.AddScoped<BookingRequestService>();

// Add services to the container.
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
using kabinizer_api.Dtos.BookingRequest;
using kabinizer_data;
using kabinizer_data.Entities;
using Microsoft.EntityFrameworkCore;

namespace kabinizer_api.Services.BookingRequest;

public class BookingRequestService(EntityContext entityContext, ITokenService tokenService)
{
private async Task<BookingRequestEntity?> GetBookingRequestById(Guid bookingRequestId)
{
return await entityContext.BookingRequests
.Include(br => br.User)
.Include(br => br.Period)
.FirstOrDefaultAsync(b => b.Id == bookingRequestId && b.UserId == tokenService.GetUserId())
?? throw new InvalidOperationException("No matching booking request found.");
}

public async Task<BookingRequestEntity?> GetBookingRequest(Guid bookingRequestId)
{
BookingRequestEntity? id = await GetBookingRequestById(bookingRequestId);
if (id == null)
{
throw new Exception("Booking request does not exist or does not belong to the current user");
}

return id;
}

public async Task<IEnumerable<BookingRequestEntity>> GetBookingRequests()
{
var bookingRequestEntities = await entityContext.BookingRequests
.Include(br => br.User)
.Include(br => br.Period)
.Where(b => b.UserId == tokenService.GetUserId())
.ToListAsync();
if (bookingRequestEntities == null)
{
throw new Exception("No booking requests found for the current user");
}

return bookingRequestEntities;
}

public async Task<BookingRequestEntity?> AddBookingRequest(CreateBookingRequestDto request)
{
var period = await entityContext.Periods
.Include(p => p.Draw)
.FirstOrDefaultAsync(p => p.Draw != null && p.Id == request.PeriodId && p.Draw.DeadlineEnd >= DateTime.Now);

if (period == null)
{
throw new Exception("Period does not exist, is not part of a draw, or the draw has ended");
}

var user = await entityContext.Users.FirstOrDefaultAsync(u => u.Id == tokenService.GetUserId());
if (user == null)
{
throw new Exception("User does not exist");
}

var bookingRequest = new BookingRequestEntity
{
PeriodId = period.Id,
UserId = user.Id,
CreatedDate = DateTime.Now,
CreatedBy = user.Id,
User = user,
Period = period
};
entityContext.BookingRequests.Add(bookingRequest);
await entityContext.SaveChangesAsync();
return bookingRequest;
}

public async Task DeleteBookingRequest(Guid bookingRequestId)
{
var bookingRequest = await entityContext.BookingRequests.FirstOrDefaultAsync(b => b.Id == bookingRequestId);
if (bookingRequest == null)
{
throw new Exception(
$"Booking request with id {bookingRequestId} does not exist or does not belong to the current user");
}

entityContext.BookingRequests.Remove(bookingRequest);
await entityContext.SaveChangesAsync();
}

public async Task<List<BookingRequestEntity>> GetBookingRequestsByUser(Guid userId)
{
var bookingRequests = await entityContext.BookingRequests
.Include(br => br.User)
.Include(br => br.Period)
.Where(b => b.UserId == userId)
.ToListAsync();
if (bookingRequests == null)
{
throw new Exception("No booking requests found for the user");
}

return bookingRequests;
}

public async Task<List<BookingRequestEntity>> GetBookingRequestsByPeriod(Guid periodId)
{
var bookingRequests = await entityContext.BookingRequests
.Include(br => br.User)
.Include(br => br.Period)
.Where(b => b.PeriodId == periodId)
.ToListAsync();

if (bookingRequests == null)
{
throw new Exception("No booking requests found for the period");
}

return bookingRequests;
}
}
Loading
Loading