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

Ivanchuk/Add to favorites #241

Merged
merged 8 commits into from
Jul 23, 2021
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions OutOfSchool/OutOfSchool.DataAccess/Models/Favorite.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System.ComponentModel.DataAnnotations;

namespace OutOfSchool.Services.Models
{
public class Favorite
{
public long Id { get; set; }

[Required]
[Range(1, long.MaxValue, ErrorMessage = "Workshop id should be grater than 0")]
public long WorkshopId { get; set; }

[Required]
public string UserId { get; set; }

public virtual Workshop Workshop { get; set; }

public virtual User User { get; set; }
}
}
2 changes: 2 additions & 0 deletions OutOfSchool/OutOfSchool.DataAccess/OutOfSchoolDbContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ public OutOfSchoolDbContext(DbContextOptions<OutOfSchoolDbContext> options)

public DbSet<City> Cities { get; set; }

public DbSet<Favorite> Favorites { get; set; }

protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
Expand Down
149 changes: 149 additions & 0 deletions OutOfSchool/OutOfSchool.WebApi/Controllers/FavoriteController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Localization;
using OutOfSchool.WebApi.Extensions;
using OutOfSchool.WebApi.Models;
using OutOfSchool.WebApi.Services;

namespace OutOfSchool.WebApi.Controllers
{
[ApiController]
[Route("[controller]")]
[Authorize(AuthenticationSchemes = "Bearer")]
public class FavoriteController : ControllerBase
{
private readonly IFavoriteService service;
private readonly IStringLocalizer<SharedResource> localizer;

/// <summary>
/// Initializes a new instance of the <see cref="FavoriteController"/> class.
/// </summary>
/// <param name="service">Service for Favorite model.</param>
/// <param name="localizer">Localizer.</param>
public FavoriteController(IFavoriteService service, IStringLocalizer<SharedResource> localizer)
{
this.service = service;
this.localizer = localizer;
}

/// <summary>
/// Get all Favorites from the database.
/// </summary>
/// <returns>List of all Favorites.</returns>
[Authorize(Roles = "admin")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable<FavoriteDto>))]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[HttpGet("all")]
public async Task<IActionResult> Get()
{
var favorites = await service.GetAll().ConfigureAwait(false);

if (!favorites.Any())
{
return NoContent();
}

return Ok(favorites);
}

/// <summary>
/// Get Favorite by it's id.
/// </summary>
/// <param name="id">Favorite id.</param>
/// <returns>Favorite.</returns>
[Authorize(Roles = "parent,admin")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(FavoriteDto))]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[HttpGet("{id}")]
public async Task<IActionResult> GetById(long id)
{
this.ValidateId(id, localizer);

return Ok(await service.GetById(id).ConfigureAwait(false));
}

/// <summary>
/// Get all Favorites from the database by UserId.
/// </summary>
/// <returns>List of all User Favorites.</returns>
[Authorize(Roles = "parent,admin")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable<FavoriteDto>))]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[HttpGet]
public async Task<IActionResult> GetAllByUser()
{
string userId = User.FindFirst("sub")?.Value;

var favorites = await service.GetAllByUser(userId).ConfigureAwait(false);

if (!favorites.Any())
{
return NoContent();
}

return Ok(favorites);
}

/// <summary>
/// Add a new Favorite to the database.
/// </summary>
/// <param name="dto">Favorite entity to add.</param>
/// <returns>A <see cref="Task{TResult}"/> representing the result of the asynchronous operation.</returns>
[Authorize(Roles = "parent,admin")]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[HttpPost]
public async Task<IActionResult> Create(FavoriteDto dto)
{
var favorite = await service.Create(dto).ConfigureAwait(false);

return CreatedAtAction(
nameof(GetById),
new { id = favorite.Id, },
favorite);
}

/// <summary>
/// Update info about a Favorite in the database.
/// </summary>
/// <param name="dto">Favorite to update.</param>
/// <returns>Favorite.</returns>
[Authorize(Roles = "parent,admin")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[HttpPut]
public async Task<IActionResult> Update(FavoriteDto dto)
{
return Ok(await service.Update(dto).ConfigureAwait(false));
}

/// <summary>
/// Delete a specific Favorite from the database.
/// </summary>
/// <param name="id">Favorite id.</param>
/// <returns>A <see cref="Task{TResult}"/> representing the result of the asynchronous operation.</returns>
[Authorize(Roles = "parent,admin")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[HttpDelete("{id}")]
public async Task<IActionResult> Delete(long id)
{
this.ValidateId(id, localizer);

await service.Delete(id).ConfigureAwait(false);

return NoContent();
}
}
}
10 changes: 10 additions & 0 deletions OutOfSchool/OutOfSchool.WebApi/Extensions/MappingExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ public static DirectionDto ToModel(this Direction direction)
return Mapper<Direction, DirectionDto>(direction, cfg => { cfg.CreateMap<Direction, DirectionDto>(); });
}

public static FavoriteDto ToModel(this Favorite favorite)
{
return Mapper<Favorite, FavoriteDto>(favorite, cfg => { cfg.CreateMap<Favorite, FavoriteDto>(); });
}

public static ParentDTO ToModel(this Parent parent)
{
var parentDto =
Expand Down Expand Up @@ -202,6 +207,11 @@ public static Direction ToDomain(this DirectionDto directionDto)
return Mapper<DirectionDto, Direction>(directionDto, cfg => { cfg.CreateMap<DirectionDto, Direction>(); });
}

public static Favorite ToDomain(this FavoriteDto favoriteDto)
{
return Mapper<FavoriteDto, Favorite>(favoriteDto, cfg => { cfg.CreateMap<FavoriteDto, Favorite>(); });
}

public static Parent ToDomain(this ParentDTO parentDto)
{
var parent =
Expand Down
16 changes: 16 additions & 0 deletions OutOfSchool/OutOfSchool.WebApi/Models/FavoriteDto.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System.ComponentModel.DataAnnotations;

namespace OutOfSchool.WebApi.Models
{
public class FavoriteDto
{
public long Id { get; set; }

[Required]
[Range(1, long.MaxValue, ErrorMessage = "Workshop id should be grater than 0")]
public long WorkshopId { get; set; }

[Required]
public string UserId { get; set; }
}
}
131 changes: 131 additions & 0 deletions OutOfSchool/OutOfSchool.WebApi/Services/FavoriteService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Localization;
using OutOfSchool.Services.Models;
using OutOfSchool.Services.Repository;
using OutOfSchool.WebApi.Extensions;
using OutOfSchool.WebApi.Models;
using Serilog;

namespace OutOfSchool.WebApi.Services
{
/// <summary>
/// Implements the interface with CRUD functionality for Favorite entity.
/// </summary>
public class FavoriteService : IFavoriteService
{
private readonly IEntityRepository<Favorite> repository;
private readonly ILogger logger;
private readonly IStringLocalizer<SharedResource> localizer;

public FavoriteService(IEntityRepository<Favorite> repository, ILogger logger, IStringLocalizer<SharedResource> localizer)
{
this.repository = repository;
this.logger = logger;
this.localizer = localizer;
}

/// <inheritdoc/>
public async Task<IEnumerable<FavoriteDto>> GetAll()
{
logger.Information("Getting all Favorites started.");

var favorites = await repository.GetAll().ConfigureAwait(false);

logger.Information(!favorites.Any()
? "Favorites table is empty."
: $"All {favorites.Count()} records were successfully received from the Favorites table");

return favorites.Select(favorite => favorite.ToModel()).ToList();
}

/// <inheritdoc/>
public async Task<FavoriteDto> GetById(long id)
{
logger.Information($"Getting Favorite by Id started. Looking Id = {id}.");

var favorite = await repository.GetById(id).ConfigureAwait(false);

if (favorite == null)
{
throw new ArgumentOutOfRangeException(
nameof(id),
localizer["The id cannot be greater than number of table entities."]);
}

logger.Information($"Successfully got a Favorite with Id = {id}.");

return favorite.ToModel();
}

/// <inheritdoc/>
public async Task<IEnumerable<FavoriteDto>> GetAllByUser(string userId)
{
logger.Information($"Getting Favorites by User started. Looking UserId = {userId}.");

var favorites = await repository.GetByFilter(x => x.UserId == userId).ConfigureAwait(false);

logger.Information(!favorites.Any()
? $"There aren't Favorites for User with Id = {userId}."
: $"All {favorites.Count()} records were successfully received from the Favorites table");

return favorites.Select(x => x.ToModel()).ToList();
}

/// <inheritdoc/>
public async Task<FavoriteDto> Create(FavoriteDto dto)
{
logger.Information("Favorite creating was started.");

var favorite = dto.ToDomain();

var newFavorite = await repository.Create(favorite).ConfigureAwait(false);

logger.Information($"Favorite with Id = {newFavorite?.Id} created successfully.");

return newFavorite.ToModel();
}

/// <inheritdoc/>
public async Task<FavoriteDto> Update(FavoriteDto dto)
{
logger.Information($"Updating Favorite with Id = {dto?.Id} started.");

try
{
var favorite = await repository.Update(dto.ToDomain()).ConfigureAwait(false);

logger.Information($"Favorite with Id = {favorite?.Id} updated succesfully.");

return favorite.ToModel();
}
catch (DbUpdateConcurrencyException)
{
logger.Error($"Updating failed. Favorite with Id = {dto?.Id} doesn't exist in the system.");
throw;
}
}

/// <inheritdoc/>
public async Task Delete(long id)
{
logger.Information($"Deleting Favorite with Id = {id} started.");

var favorite = await repository.GetById(id).ConfigureAwait(false);

if (favorite == null)
{
throw new ArgumentOutOfRangeException(
nameof(id),
localizer[$"Favorite with Id = {id} doesn't exist in the system"]);
}

await repository.Delete(favorite).ConfigureAwait(false);

logger.Information($"Favorite with Id = {id} succesfully deleted.");
}
}
}
Loading