diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Controllers/MoviesController.cs b/WatchIt.WebAPI/WatchIt.WebAPI.Controllers/MoviesController.cs index 517d6cd..5f87add 100644 --- a/WatchIt.WebAPI/WatchIt.WebAPI.Controllers/MoviesController.cs +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Controllers/MoviesController.cs @@ -11,18 +11,41 @@ namespace WatchIt.WebAPI.Controllers; [ApiController] [Route("movies")] -public class MoviesController(IMoviesControllerService moviesControllerService) : ControllerBase +public class MoviesController : ControllerBase { + #region SERVICES + + private readonly IMoviesControllerService _moviesControllerService; + + #endregion + + + + #region CONSTRUCTORS + + public MoviesController(IMoviesControllerService moviesControllerService) + { + _moviesControllerService = moviesControllerService; + } + + #endregion + + + + #region METHODS + + #region Main + [HttpGet] [AllowAnonymous] [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] - public async Task GetAll(MovieQueryParameters query) => await moviesControllerService.GetAll(query); + public async Task GetAllMovies(MovieQueryParameters query) => await _moviesControllerService.GetAllMovies(query); [HttpGet("{id}")] [AllowAnonymous] [ProducesResponseType(typeof(MovieResponse), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task Get([FromRoute]long id) => await moviesControllerService.Get(id); + public async Task GetMovie([FromRoute] long id) => await _moviesControllerService.GetMovie(id); [HttpPost] [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] @@ -30,7 +53,7 @@ public class MoviesController(IMoviesControllerService moviesControllerService) [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)] [ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)] - public async Task Post([FromBody]MovieRequest body) => await moviesControllerService.Post(body); + public async Task PostMovie([FromBody] MovieRequest body) => await _moviesControllerService.PostMovie(body); [HttpPut("{id}")] [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] @@ -38,12 +61,26 @@ public class MoviesController(IMoviesControllerService moviesControllerService) [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)] [ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)] - public async Task Put([FromRoute]long id, [FromBody]MovieRequest body) => await moviesControllerService.Put(id, body); + public async Task PutMovie([FromRoute] long id, [FromBody]MovieRequest body) => await _moviesControllerService.PutMovie(id, body); [HttpDelete("{id}")] [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] [ProducesResponseType(typeof(void), StatusCodes.Status204NoContent)] [ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)] [ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)] - public async Task Delete([FromRoute] long id) => await moviesControllerService.Delete(id); + public async Task DeleteMovie([FromRoute] long id) => await _moviesControllerService.DeleteMovie(id); + + #endregion + + #region View count + + [HttpGet("view")] + [AllowAnonymous] + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public async Task GetMoviesViewRank([FromQuery] int first = 5, [FromQuery] int days = 7) => await _moviesControllerService.GetMoviesViewRank(first, days); + + #endregion + + #endregion } \ No newline at end of file diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Movies/IMoviesControllerService.cs b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Movies/IMoviesControllerService.cs index 173f7e7..cc514a5 100644 --- a/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Movies/IMoviesControllerService.cs +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Movies/IMoviesControllerService.cs @@ -5,9 +5,11 @@ namespace WatchIt.WebAPI.Services.Controllers.Movies; public interface IMoviesControllerService { - Task GetAll(MovieQueryParameters query); - Task Get(long id); - Task Post(MovieRequest data); - Task Put(long id, MovieRequest data); - Task Delete(long id); + Task GetAllMovies(MovieQueryParameters query); + Task GetMovie(long id); + Task PostMovie(MovieRequest data); + Task PutMovie(long id, MovieRequest data); + Task DeleteMovie(long id); + + Task GetMoviesViewRank(int first, int days); } \ No newline at end of file diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Movies/MoviesControllerService.cs b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Movies/MoviesControllerService.cs index 5ab3398..cc5d69e 100644 --- a/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Movies/MoviesControllerService.cs +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Movies/MoviesControllerService.cs @@ -7,20 +7,44 @@ using WatchIt.WebAPI.Services.Utility.User; namespace WatchIt.WebAPI.Services.Controllers.Movies; -public class MoviesControllerService(DatabaseContext database, IUserService userService) : IMoviesControllerService +public class MoviesControllerService : IMoviesControllerService { - #region PUBLIC METHODS + #region SERVICES - public async Task GetAll(MovieQueryParameters query) + private readonly DatabaseContext _database; + + private readonly IUserService _userService; + + #endregion + + + + #region CONSTRUCTORS + + public MoviesControllerService(DatabaseContext database, IUserService userService) { - IEnumerable data = await database.MediaMovies.Select(x => new MovieResponse(x)).ToListAsync(); + _database = database; + + _userService = userService; + } + + #endregion + + + #region PUBLIC METHODS + + #region Main + + public async Task GetAllMovies(MovieQueryParameters query) + { + IEnumerable data = await _database.MediaMovies.Select(x => new MovieResponse(x)).ToListAsync(); data = query.PrepareData(data); return RequestResult.Ok(data); } - public async Task Get(long id) + public async Task GetMovie(long id) { - MediaMovie? item = await database.MediaMovies.FirstOrDefaultAsync(x => x.Id == id); + MediaMovie? item = await _database.MediaMovies.FirstOrDefaultAsync(x => x.Id == id); if (item is null) { return RequestResult.NotFound(); @@ -30,33 +54,33 @@ public class MoviesControllerService(DatabaseContext database, IUserService user return RequestResult.Ok(data); } - public async Task Post(MovieRequest data) + public async Task PostMovie(MovieRequest data) { - UserValidator validator = userService.GetValidator().MustBeAdmin(); + UserValidator validator = _userService.GetValidator().MustBeAdmin(); if (!validator.IsValid) { return RequestResult.Forbidden(); } Media mediaItem = data.CreateMedia(); - await database.Media.AddAsync(mediaItem); - await database.SaveChangesAsync(); + await _database.Media.AddAsync(mediaItem); + await _database.SaveChangesAsync(); MediaMovie mediaMovieItem = data.CreateMediaMovie(mediaItem.Id); - await database.MediaMovies.AddAsync(mediaMovieItem); - await database.SaveChangesAsync(); + await _database.MediaMovies.AddAsync(mediaMovieItem); + await _database.SaveChangesAsync(); return RequestResult.Created($"movies/{mediaItem.Id}", new MovieResponse(mediaMovieItem)); } - public async Task Put(long id, MovieRequest data) + public async Task PutMovie(long id, MovieRequest data) { - UserValidator validator = userService.GetValidator().MustBeAdmin(); + UserValidator validator = _userService.GetValidator().MustBeAdmin(); if (!validator.IsValid) { return RequestResult.Forbidden(); } - MediaMovie? item = await database.MediaMovies.FirstOrDefaultAsync(x => x.Id == id); + MediaMovie? item = await _database.MediaMovies.FirstOrDefaultAsync(x => x.Id == id); if (item is null) { return RequestResult.NotFound(); @@ -64,49 +88,74 @@ public class MoviesControllerService(DatabaseContext database, IUserService user data.UpdateMediaMovie(item); data.UpdateMedia(item.Media); - await database.SaveChangesAsync(); + await _database.SaveChangesAsync(); return RequestResult.NoContent(); } - public async Task Delete(long id) + public async Task DeleteMovie(long id) { - UserValidator validator = userService.GetValidator().MustBeAdmin(); + UserValidator validator = _userService.GetValidator().MustBeAdmin(); if (!validator.IsValid) { return RequestResult.Forbidden(); } - MediaMovie? item = await database.MediaMovies.FirstOrDefaultAsync(x => x.Id == id); + MediaMovie? item = await _database.MediaMovies.FirstOrDefaultAsync(x => x.Id == id); if (item is null) { return RequestResult.NotFound(); } - database.MediaMovies.Attach(item); - database.MediaMovies.Remove(item); - database.MediaPosterImages.Attach(item.Media.MediaPosterImage!); - database.MediaPosterImages.Remove(item.Media.MediaPosterImage!); - database.MediaPhotoImages.AttachRange(item.Media.MediaPhotoImages); - database.MediaPhotoImages.RemoveRange(item.Media.MediaPhotoImages); - database.MediaGenres.AttachRange(item.Media.MediaGenres); - database.MediaGenres.RemoveRange(item.Media.MediaGenres); - database.MediaProductionCountries.AttachRange(item.Media.MediaProductionCountries); - database.MediaProductionCountries.RemoveRange(item.Media.MediaProductionCountries); - database.PersonActorRoles.AttachRange(item.Media.PersonActorRoles); - database.PersonActorRoles.RemoveRange(item.Media.PersonActorRoles); - database.PersonCreatorRoles.AttachRange(item.Media.PersonCreatorRoles); - database.PersonCreatorRoles.RemoveRange(item.Media.PersonCreatorRoles); - database.RatingsMedia.AttachRange(item.Media.RatingMedia); - database.RatingsMedia.RemoveRange(item.Media.RatingMedia); - database.ViewCountsMedia.AttachRange(item.Media.ViewCountsMedia); - database.ViewCountsMedia.RemoveRange(item.Media.ViewCountsMedia); - database.Media.Attach(item.Media); - database.Media.Remove(item.Media); - await database.SaveChangesAsync(); + _database.MediaMovies.Attach(item); + _database.MediaMovies.Remove(item); + _database.MediaPosterImages.Attach(item.Media.MediaPosterImage!); + _database.MediaPosterImages.Remove(item.Media.MediaPosterImage!); + _database.MediaPhotoImages.AttachRange(item.Media.MediaPhotoImages); + _database.MediaPhotoImages.RemoveRange(item.Media.MediaPhotoImages); + _database.MediaGenres.AttachRange(item.Media.MediaGenres); + _database.MediaGenres.RemoveRange(item.Media.MediaGenres); + _database.MediaProductionCountries.AttachRange(item.Media.MediaProductionCountries); + _database.MediaProductionCountries.RemoveRange(item.Media.MediaProductionCountries); + _database.PersonActorRoles.AttachRange(item.Media.PersonActorRoles); + _database.PersonActorRoles.RemoveRange(item.Media.PersonActorRoles); + _database.PersonCreatorRoles.AttachRange(item.Media.PersonCreatorRoles); + _database.PersonCreatorRoles.RemoveRange(item.Media.PersonCreatorRoles); + _database.RatingsMedia.AttachRange(item.Media.RatingMedia); + _database.RatingsMedia.RemoveRange(item.Media.RatingMedia); + _database.ViewCountsMedia.AttachRange(item.Media.ViewCountsMedia); + _database.ViewCountsMedia.RemoveRange(item.Media.ViewCountsMedia); + _database.Media.Attach(item.Media); + _database.Media.Remove(item.Media); + await _database.SaveChangesAsync(); return RequestResult.NoContent(); } + + #endregion + + #region View count + + public async Task GetMoviesViewRank(int first, int days) + { + if (first < 1 || days < 1) + { + return RequestResult.BadRequest(); + } + + DateOnly startDate = DateOnly.FromDateTime(DateTime.Now).AddDays(-days); + IEnumerable rawData = await _database.MediaMovies.OrderByDescending(x => x.Media.ViewCountsMedia.Where(y => y.Date >= startDate) + .Sum(y => y.ViewCount)) + .ThenBy(x => x.Id) + .Take(first) + .ToListAsync(); + + IEnumerable data = rawData.Select(x => new MovieResponse(x)); + + return RequestResult.Ok(data); + } + + #endregion #endregion } \ No newline at end of file diff --git a/WatchIt.Website/WatchIt.Website/Pages/MediaPage.razor.cs b/WatchIt.Website/WatchIt.Website/Pages/MediaPage.razor.cs index b3cfa20..31430d2 100644 --- a/WatchIt.Website/WatchIt.Website/Pages/MediaPage.razor.cs +++ b/WatchIt.Website/WatchIt.Website/Pages/MediaPage.razor.cs @@ -33,16 +33,18 @@ public partial class MediaPage : ComponentBase #region FIELDS - private bool _loaded = false; + private bool _loaded; private string? _error; private MediaResponse? _media; - private MovieResponse? _movie; - private IEnumerable _genres; - private MediaRatingResponse _globalRating; + + private User? _user; + private MediaPhotoResponse? _background; private MediaPosterResponse? _poster; - private User? _user; + private IEnumerable _genres; + private MediaRatingResponse _globalRating; + private MovieResponse? _movie; private short? _userRating;