diff --git a/WatchIt.Common/WatchIt.Common.Model/Genders/GenderQueryParameters.cs b/WatchIt.Common/WatchIt.Common.Model/Genders/GenderQueryParameters.cs new file mode 100644 index 0000000..490a674 --- /dev/null +++ b/WatchIt.Common/WatchIt.Common.Model/Genders/GenderQueryParameters.cs @@ -0,0 +1,22 @@ +using Microsoft.AspNetCore.Mvc; +using WatchIt.Common.Query; + +namespace WatchIt.Common.Model.Genders; + +public class GenderQueryParameters : QueryParameters +{ + #region PROPERTIES + + [FromQuery(Name = "name")] + public string? Name { get; set; } + + #endregion + + + + #region PRIVATE METHODS + + protected override bool IsMeetingConditions(GenderResponse item) => TestStringWithRegex(item.Name, Name); + + #endregion +} \ No newline at end of file diff --git a/WatchIt.Common/WatchIt.Common.Model/Genders/GenderRequest.cs b/WatchIt.Common/WatchIt.Common.Model/Genders/GenderRequest.cs new file mode 100644 index 0000000..60f5a42 --- /dev/null +++ b/WatchIt.Common/WatchIt.Common.Model/Genders/GenderRequest.cs @@ -0,0 +1,13 @@ +namespace WatchIt.Common.Model.Genders; + +public class GenderRequest : Gender +{ + #region PUBLIC METHODS + + public Database.Model.Common.Gender CreateGender() => new Database.Model.Common.Gender() + { + Name = Name + }; + + #endregion +} \ No newline at end of file diff --git a/WatchIt.Common/WatchIt.Common.Model/Genders/GenderResponse.cs b/WatchIt.Common/WatchIt.Common.Model/Genders/GenderResponse.cs index 9677a0d..16eeeec 100644 --- a/WatchIt.Common/WatchIt.Common.Model/Genders/GenderResponse.cs +++ b/WatchIt.Common/WatchIt.Common.Model/Genders/GenderResponse.cs @@ -1,12 +1,20 @@ using System.Diagnostics.CodeAnalysis; using System.Text.Json.Serialization; +using WatchIt.Common.Query; namespace WatchIt.Common.Model.Genders; -public class GenderResponse : Gender +public class GenderResponse : Gender, IQueryOrderable { #region PROPERTIES + [JsonIgnore] + public static IDictionary> OrderableProperties { get; } = new Dictionary> + { + { "name", item => item.Name } + }; + + [JsonPropertyName("id")] public required short? Id { get; set; } @@ -15,6 +23,9 @@ public class GenderResponse : Gender #region CONSTRUCTORS + + [JsonConstructor] + public GenderResponse() { } [SetsRequiredMembers] public GenderResponse(Database.Model.Common.Gender gender) diff --git a/WatchIt.Common/WatchIt.Common.Model/Media/MediaPosterRequest.cs b/WatchIt.Common/WatchIt.Common.Model/Media/MediaPosterRequest.cs index 5a9fa95..1b83f1a 100644 --- a/WatchIt.Common/WatchIt.Common.Model/Media/MediaPosterRequest.cs +++ b/WatchIt.Common/WatchIt.Common.Model/Media/MediaPosterRequest.cs @@ -10,10 +10,10 @@ public class MediaPosterRequest : MediaPoster public MediaPosterRequest() {} [SetsRequiredMembers] - public MediaPosterRequest(MediaPosterResponse response) + public MediaPosterRequest(Picture image) { - Image = response.Image; - MimeType = response.MimeType; + Image = image.Image; + MimeType = image.MimeType; } #endregion diff --git a/WatchIt.Common/WatchIt.Common.Model/Persons/PersonPhoto.cs b/WatchIt.Common/WatchIt.Common.Model/Persons/PersonPhoto.cs new file mode 100644 index 0000000..67094f6 --- /dev/null +++ b/WatchIt.Common/WatchIt.Common.Model/Persons/PersonPhoto.cs @@ -0,0 +1,6 @@ +namespace WatchIt.Common.Model.Persons; + +public class PersonPhoto : Picture +{ + +} \ No newline at end of file diff --git a/WatchIt.Common/WatchIt.Common.Model/Persons/PersonPhotoRequest.cs b/WatchIt.Common/WatchIt.Common.Model/Persons/PersonPhotoRequest.cs new file mode 100644 index 0000000..8397887 --- /dev/null +++ b/WatchIt.Common/WatchIt.Common.Model/Persons/PersonPhotoRequest.cs @@ -0,0 +1,41 @@ +using System.Diagnostics.CodeAnalysis; +using System.Text.Json.Serialization; +using WatchIt.Database.Model.Person; + +namespace WatchIt.Common.Model.Persons; + +public class PersonPhotoRequest : PersonPhoto +{ + #region CONSTRUCTORS + + [JsonConstructor] + public PersonPhotoRequest() {} + + [SetsRequiredMembers] + public PersonPhotoRequest(Picture image) + { + Image = image.Image; + MimeType = image.MimeType; + } + + #endregion + + + + #region PUBLIC METHODS + + public PersonPhotoImage CreatePersonPhotoImage() => new PersonPhotoImage + { + Image = Image, + MimeType = MimeType, + }; + + public void UpdatePersonPhotoImage(PersonPhotoImage item) + { + item.Image = Image; + item.MimeType = MimeType; + item.UploadDate = DateTime.UtcNow; + } + + #endregion +} \ No newline at end of file diff --git a/WatchIt.Common/WatchIt.Common.Model/Persons/PersonPhotoResponse.cs b/WatchIt.Common/WatchIt.Common.Model/Persons/PersonPhotoResponse.cs new file mode 100644 index 0000000..957e76c --- /dev/null +++ b/WatchIt.Common/WatchIt.Common.Model/Persons/PersonPhotoResponse.cs @@ -0,0 +1,36 @@ +using System.Diagnostics.CodeAnalysis; +using System.Text.Json.Serialization; +using WatchIt.Database.Model.Person; + +namespace WatchIt.Common.Model.Persons; + +public class PersonPhotoResponse : PersonPhoto +{ + #region PROPERTIES + + [JsonPropertyName("id")] + public Guid Id { get; set; } + + [JsonPropertyName("upload_date")] + public DateTime UploadDate { get; set; } + + #endregion + + + + #region CONSTRUCTORS + + [JsonConstructor] + public PersonPhotoResponse() {} + + [SetsRequiredMembers] + public PersonPhotoResponse(PersonPhotoImage personPhotoImage) + { + Id = personPhotoImage.Id; + Image = personPhotoImage.Image; + MimeType = personPhotoImage.MimeType; + UploadDate = personPhotoImage.UploadDate; + } + + #endregion +} \ No newline at end of file diff --git a/WatchIt.Common/WatchIt.Common.Model/Persons/PersonRequest.cs b/WatchIt.Common/WatchIt.Common.Model/Persons/PersonRequest.cs index 5379e05..7e7052b 100644 --- a/WatchIt.Common/WatchIt.Common.Model/Persons/PersonRequest.cs +++ b/WatchIt.Common/WatchIt.Common.Model/Persons/PersonRequest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.Text.Json.Serialization; namespace WatchIt.Common.Model.Persons; @@ -10,6 +11,29 @@ public class PersonRequest : Person public short? GenderId { get; set; } #endregion + + + + #region CONSTRUCTORS + + [SetsRequiredMembers] + public PersonRequest() + { + Name = string.Empty; + } + + [SetsRequiredMembers] + public PersonRequest(PersonResponse person) + { + Name = person.Name; + FullName = person.FullName; + Description = person.Description; + BirthDate = person.BirthDate; + DeathDate = person.DeathDate; + GenderId = person.Gender?.Id; + } + + #endregion diff --git a/WatchIt.Common/WatchIt.Common.Model/Persons/PersonResponse.cs b/WatchIt.Common/WatchIt.Common.Model/Persons/PersonResponse.cs index 3ff33ee..a81e5ab 100644 --- a/WatchIt.Common/WatchIt.Common.Model/Persons/PersonResponse.cs +++ b/WatchIt.Common/WatchIt.Common.Model/Persons/PersonResponse.cs @@ -40,6 +40,9 @@ public class PersonResponse : Person, IQueryOrderable #region CONSTRUCTORS + [JsonConstructor] + public PersonResponse() { } + [SetsRequiredMembers] public PersonResponse(Database.Model.Person.Person person) { diff --git a/WatchIt.Common/WatchIt.Common.Model/Picture.cs b/WatchIt.Common/WatchIt.Common.Model/Picture.cs index ab0e8ee..b16065e 100644 --- a/WatchIt.Common/WatchIt.Common.Model/Picture.cs +++ b/WatchIt.Common/WatchIt.Common.Model/Picture.cs @@ -2,7 +2,7 @@ using System.Text.Json.Serialization; namespace WatchIt.Common.Model; -public abstract class Picture +public class Picture { #region PROPERTIES diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Controllers/GendersController.cs b/WatchIt.WebAPI/WatchIt.WebAPI.Controllers/GendersController.cs new file mode 100644 index 0000000..af3be9f --- /dev/null +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Controllers/GendersController.cs @@ -0,0 +1,66 @@ +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using WatchIt.Common.Model.Genders; +using WatchIt.WebAPI.Services.Controllers.Genders; + +namespace WatchIt.WebAPI.Controllers; + +[ApiController] +[Route("genders")] +public class GendersController : ControllerBase +{ + #region SERVICES + + private readonly IGendersControllerService _gendersControllerService; + + #endregion + + + + #region CONSTRUCTORS + + public GendersController(IGendersControllerService gendersControllerService) + { + _gendersControllerService = gendersControllerService; + } + + #endregion + + + + #region METHODS + + #region Main + + [HttpGet] + [AllowAnonymous] + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + public async Task GetAllGenders(GenderQueryParameters query) => await _gendersControllerService.GetAllGenders(query); + + [HttpGet("{id}")] + [AllowAnonymous] + [ProducesResponseType(typeof(GenderResponse), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task GetGender([FromRoute]short id) => await _gendersControllerService.GetGender(id); + + [HttpPost] + [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] + [ProducesResponseType(typeof(GenderResponse), StatusCodes.Status201Created)] + [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)] + [ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)] + [ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)] + public async Task PostGender([FromBody]GenderRequest body) => await _gendersControllerService.PostGender(body); + + [HttpDelete("{id}")] + [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] + [ProducesResponseType(typeof(GenderResponse), StatusCodes.Status204NoContent)] + [ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)] + [ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)] + public async Task DeleteGender([FromRoute]short id) => await _gendersControllerService.DeleteGender(id); + + #endregion + + #endregion +} \ No newline at end of file diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Controllers/PersonsController.cs b/WatchIt.WebAPI/WatchIt.WebAPI.Controllers/PersonsController.cs index aaf1d45..258763a 100644 --- a/WatchIt.WebAPI/WatchIt.WebAPI.Controllers/PersonsController.cs +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Controllers/PersonsController.cs @@ -80,5 +80,31 @@ public class PersonsController : ControllerBase #endregion + #region Photo + + [HttpGet("{id}/photo")] + [AllowAnonymous] + [ProducesResponseType(typeof(PersonPhotoResponse), StatusCodes.Status200OK)] + [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task GetPersonPhoto([FromRoute] long id) => await _personsControllerService.GetPersonPhoto(id); + + [HttpPut("{id}/photo")] + [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] + [ProducesResponseType(typeof(PersonPhotoResponse), StatusCodes.Status200OK)] + [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)] + [ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)] + [ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)] + public async Task PutPersonPhoto([FromRoute]long id, [FromBody]PersonPhotoRequest body) => await _personsControllerService.PutPersonPhoto(id, body); + + [HttpDelete("{id}/photo")] + [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] + [ProducesResponseType(typeof(void), StatusCodes.Status204NoContent)] + [ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)] + [ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)] + public async Task DeletePersonPhoto([FromRoute]long id) => await _personsControllerService.DeletePersonPhoto(id); + + #endregion + #endregion } \ No newline at end of file diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Controllers/WatchIt.WebAPI.Controllers.csproj b/WatchIt.WebAPI/WatchIt.WebAPI.Controllers/WatchIt.WebAPI.Controllers.csproj index b254b7e..c2bb202 100644 --- a/WatchIt.WebAPI/WatchIt.WebAPI.Controllers/WatchIt.WebAPI.Controllers.csproj +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Controllers/WatchIt.WebAPI.Controllers.csproj @@ -14,6 +14,7 @@ + diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Genders/GendersControllerService.cs b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Genders/GendersControllerService.cs new file mode 100644 index 0000000..43011b9 --- /dev/null +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Genders/GendersControllerService.cs @@ -0,0 +1,93 @@ +using Microsoft.EntityFrameworkCore; +using WatchIt.Common.Model.Genders; +using WatchIt.Database; +using WatchIt.Database.Model.Common; +using WatchIt.WebAPI.Services.Controllers.Common; +using WatchIt.WebAPI.Services.Utility.User; +using Gender = WatchIt.Database.Model.Common.Gender; + +namespace WatchIt.WebAPI.Services.Controllers.Genders; + +public class GendersControllerService : IGendersControllerService +{ + #region SERVICES + + private readonly DatabaseContext _database; + private readonly IUserService _userService; + + #endregion + + + + #region CONSTRUCTORS + + public GendersControllerService(DatabaseContext database, IUserService userService) + { + _database = database; + _userService = userService; + } + + #endregion + + + + #region PUBLIC METHODS + + public async Task GetAllGenders(GenderQueryParameters query) + { + IEnumerable rawData = await _database.Genders.ToListAsync(); + IEnumerable data = rawData.Select(x => new GenderResponse(x)); + data = query.PrepareData(data); + return RequestResult.Ok(data); + } + + public async Task GetGender(short id) + { + Gender? item = await _database.Genders.FirstOrDefaultAsync(x => x.Id == id); + if (item is null) + { + return RequestResult.NotFound(); + } + + GenderResponse data = new GenderResponse(item); + return RequestResult.Ok(data); + } + + public async Task PostGender(GenderRequest data) + { + UserValidator validator = _userService.GetValidator().MustBeAdmin(); + if (!validator.IsValid) + { + return RequestResult.Forbidden(); + } + + Gender item = data.CreateGender(); + await _database.Genders.AddAsync(item); + await _database.SaveChangesAsync(); + + return RequestResult.Created($"genres/{item.Id}", new GenderResponse(item)); + } + + public async Task DeleteGender(short id) + { + UserValidator validator = _userService.GetValidator().MustBeAdmin(); + if (!validator.IsValid) + { + return RequestResult.Forbidden(); + } + + Gender? item = await _database.Genders.FirstOrDefaultAsync(x => x.Id == id); + if (item is null) + { + return RequestResult.NoContent(); + } + + _database.Genders.Attach(item); + _database.Genders.Remove(item); + await _database.SaveChangesAsync(); + + return RequestResult.NoContent(); + } + + #endregion +} \ No newline at end of file diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Genders/IGendersControllerService.cs b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Genders/IGendersControllerService.cs new file mode 100644 index 0000000..92aec83 --- /dev/null +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Genders/IGendersControllerService.cs @@ -0,0 +1,12 @@ +using WatchIt.Common.Model.Genders; +using WatchIt.WebAPI.Services.Controllers.Common; + +namespace WatchIt.WebAPI.Services.Controllers.Genders; + +public interface IGendersControllerService +{ + Task GetAllGenders(GenderQueryParameters query); + Task GetGender(short id); + Task PostGender(GenderRequest data); + Task DeleteGender(short id); +} \ No newline at end of file diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Genders/WatchIt.WebAPI.Services.Controllers.Genders.csproj b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Genders/WatchIt.WebAPI.Services.Controllers.Genders.csproj new file mode 100644 index 0000000..9e4603e --- /dev/null +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Genders/WatchIt.WebAPI.Services.Controllers.Genders.csproj @@ -0,0 +1,16 @@ + + + + net8.0 + enable + enable + + + + + + + + + + diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Persons/IPersonsControllerService.cs b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Persons/IPersonsControllerService.cs index f9b5f6f..d3bd360 100644 --- a/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Persons/IPersonsControllerService.cs +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Persons/IPersonsControllerService.cs @@ -10,5 +10,10 @@ public interface IPersonsControllerService Task PostPerson(PersonRequest data); Task PutPerson(long id, PersonRequest data); Task DeletePerson(long id); + Task GetPersonsViewRank(int first, int days); + + Task GetPersonPhoto(long id); + Task PutPersonPhoto(long id, PersonPhotoRequest data); + Task DeletePersonPhoto(long id); } \ No newline at end of file diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Persons/PersonsControllerService.cs b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Persons/PersonsControllerService.cs index 09137fe..549a5c1 100644 --- a/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Persons/PersonsControllerService.cs +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Services/WatchIt.WebAPI.Services.Controllers/WatchIt.WebAPI.Services.Controllers.Persons/PersonsControllerService.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore; using WatchIt.Common.Model.Persons; using WatchIt.Database; +using WatchIt.Database.Model.Person; using WatchIt.WebAPI.Services.Controllers.Common; using WatchIt.WebAPI.Services.Utility.User; using Person = WatchIt.Database.Model.Person.Person; @@ -142,5 +143,80 @@ public class PersonsControllerService : IPersonsControllerService #endregion + #region Photo + + public async Task GetPersonPhoto(long id) + { + Person? person = await _database.Persons.FirstOrDefaultAsync(x => x.Id == id); + if (person is null) + { + return RequestResult.BadRequest(); + } + + PersonPhotoImage? photo = person.PersonPhoto; + if (photo is null) + { + return RequestResult.NotFound(); + } + + PersonPhotoResponse data = new PersonPhotoResponse(photo); + return RequestResult.Ok(data); + } + + public async Task PutPersonPhoto(long id, PersonPhotoRequest data) + { + UserValidator validator = _userService.GetValidator().MustBeAdmin(); + if (!validator.IsValid) + { + return RequestResult.Forbidden(); + } + + Person? person = await _database.Persons.FirstOrDefaultAsync(x => x.Id == id); + if (person is null) + { + return RequestResult.BadRequest(); + } + + if (person.PersonPhoto is null) + { + PersonPhotoImage image = data.CreatePersonPhotoImage(); + await _database.PersonPhotoImages.AddAsync(image); + await _database.SaveChangesAsync(); + + person.PersonPhotoId = image.Id; + } + else + { + data.UpdatePersonPhotoImage(person.PersonPhoto); + } + + await _database.SaveChangesAsync(); + + PersonPhotoResponse returnData = new PersonPhotoResponse(person.PersonPhoto); + return RequestResult.Ok(returnData); + } + + public async Task DeletePersonPhoto(long id) + { + UserValidator validator = _userService.GetValidator().MustBeAdmin(); + if (!validator.IsValid) + { + return RequestResult.Forbidden(); + } + + Person? person = await _database.Persons.FirstOrDefaultAsync(x => x.Id == id); + + if (person?.PersonPhoto != null) + { + _database.PersonPhotoImages.Attach(person.PersonPhoto); + _database.PersonPhotoImages.Remove(person.PersonPhoto); + await _database.SaveChangesAsync(); + } + + return RequestResult.NoContent(); + } + + #endregion + #endregion } \ No newline at end of file diff --git a/WatchIt.WebAPI/WatchIt.WebAPI.Validators/Persons/PersonRequestValidator.cs b/WatchIt.WebAPI/WatchIt.WebAPI.Validators/Persons/PersonRequestValidator.cs index f244081..2f3618e 100644 --- a/WatchIt.WebAPI/WatchIt.WebAPI.Validators/Persons/PersonRequestValidator.cs +++ b/WatchIt.WebAPI/WatchIt.WebAPI.Validators/Persons/PersonRequestValidator.cs @@ -1,9 +1,19 @@ using FluentValidation; using WatchIt.Common.Model.Persons; +using WatchIt.Database; namespace WatchIt.WebAPI.Validators.Persons; public class PersonRequestValidator : AbstractValidator { - + public PersonRequestValidator(DatabaseContext database) + { + RuleFor(x => x.Name).NotEmpty().MaximumLength(100); + RuleFor(x => x.FullName).MaximumLength(200); + RuleFor(x => x.Description).MaximumLength(1000); + When(x => x.GenderId.HasValue, () => + { + RuleFor(x => x.GenderId!.Value).MustBeIn(database.Genders.Select(g => g.Id)); + }); + } } \ No newline at end of file diff --git a/WatchIt.WebAPI/WatchIt.WebAPI/Program.cs b/WatchIt.WebAPI/WatchIt.WebAPI/Program.cs index 4e2c243..d8a531d 100644 --- a/WatchIt.WebAPI/WatchIt.WebAPI/Program.cs +++ b/WatchIt.WebAPI/WatchIt.WebAPI/Program.cs @@ -10,6 +10,7 @@ using Microsoft.IdentityModel.JsonWebTokens; using Microsoft.IdentityModel.Tokens; using WatchIt.Database; using WatchIt.WebAPI.Services.Controllers.Accounts; +using WatchIt.WebAPI.Services.Controllers.Genders; using WatchIt.WebAPI.Services.Controllers.Genres; using WatchIt.WebAPI.Services.Controllers.Media; using WatchIt.WebAPI.Services.Controllers.Movies; @@ -154,6 +155,7 @@ public static class Program // Controller builder.Services.AddTransient(); + builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); diff --git a/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.Utility/WatchIt.Website.Services.Utility.Configuration/Model/Endpoints.cs b/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.Utility/WatchIt.Website.Services.Utility.Configuration/Model/Endpoints.cs index ef20f7a..8052021 100644 --- a/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.Utility/WatchIt.Website.Services.Utility.Configuration/Model/Endpoints.cs +++ b/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.Utility/WatchIt.Website.Services.Utility.Configuration/Model/Endpoints.cs @@ -4,6 +4,7 @@ public class Endpoints { public string Base { get; set; } public Accounts Accounts { get; set; } + public Genders Genders { get; set; } public Genres Genres { get; set; } public Media Media { get; set; } public Movies Movies { get; set; } diff --git a/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.Utility/WatchIt.Website.Services.Utility.Configuration/Model/Genders.cs b/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.Utility/WatchIt.Website.Services.Utility.Configuration/Model/Genders.cs new file mode 100644 index 0000000..58a8f53 --- /dev/null +++ b/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.Utility/WatchIt.Website.Services.Utility.Configuration/Model/Genders.cs @@ -0,0 +1,10 @@ +namespace WatchIt.Website.Services.Utility.Configuration.Model; + +public class Genders +{ + public string Base { get; set; } + public string GetAllGenders { get; set; } + public string GetGender { get; set; } + public string PostGender { get; set; } + public string DeleteGender { get; set; } +} \ No newline at end of file diff --git a/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.Utility/WatchIt.Website.Services.Utility.Configuration/Model/Persons.cs b/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.Utility/WatchIt.Website.Services.Utility.Configuration/Model/Persons.cs index 1bf760a..a1c1ab6 100644 --- a/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.Utility/WatchIt.Website.Services.Utility.Configuration/Model/Persons.cs +++ b/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.Utility/WatchIt.Website.Services.Utility.Configuration/Model/Persons.cs @@ -9,4 +9,7 @@ public class Persons public string PutPerson { get; set; } public string DeletePerson { get; set; } public string GetPersonsViewRank { get; set; } + public string GetPersonPhoto { get; set; } + public string PutPersonPhoto { get; set; } + public string DeletePersonPhoto { get; set; } } \ No newline at end of file diff --git a/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.WebAPI/WatchIt.Website.Services.WebAPI.Genders/GendersWebAPIService.cs b/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.WebAPI/WatchIt.Website.Services.WebAPI.Genders/GendersWebAPIService.cs new file mode 100644 index 0000000..1976795 --- /dev/null +++ b/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.WebAPI/WatchIt.Website.Services.WebAPI.Genders/GendersWebAPIService.cs @@ -0,0 +1,98 @@ +using WatchIt.Common.Model.Genders; +using WatchIt.Common.Services.HttpClient; +using WatchIt.Website.Services.Utility.Configuration; +using WatchIt.Website.Services.WebAPI.Common; + +namespace WatchIt.Website.Services.WebAPI.Genders; + +public class GendersWebAPIService : BaseWebAPIService, IGendersWebAPIService +{ + #region SERVICES + + private IHttpClientService _httpClientService; + private IConfigurationService _configurationService; + + #endregion + + + + #region CONSTRUCTORS + + public GendersWebAPIService(IHttpClientService httpClientService, IConfigurationService configurationService) : base(configurationService) + { + _httpClientService = httpClientService; + _configurationService = configurationService; + } + + #endregion + + + + #region PUBLIC METHODS + + #region Main + + public async Task GetAllGenders(GenderQueryParameters? query = null, Action>? successAction = null) + { + string url = GetUrl(EndpointsConfiguration.Genders.GetAllGenders); + + HttpRequest request = new HttpRequest(HttpMethodType.Get, url); + request.Query = query; + + HttpResponse response = await _httpClientService.SendRequestAsync(request); + response.RegisterActionFor2XXSuccess(successAction) + .ExecuteAction(); + } + + public async Task GetGender(long id, Action? successAction = null, Action? notFoundAction = null) + { + string url = GetUrl(EndpointsConfiguration.Genders.GetGender, id); + + HttpRequest request = new HttpRequest(HttpMethodType.Get, url); + + HttpResponse response = await _httpClientService.SendRequestAsync(request); + response.RegisterActionFor2XXSuccess(successAction) + .RegisterActionFor404NotFound(notFoundAction) + .ExecuteAction(); + } + + public async Task PostGender(GenderRequest data, Action? successAction = null, Action>? badRequestAction = null, Action? unauthorizedAction = null, Action? forbiddenAction = null) + { + string url = GetUrl(EndpointsConfiguration.Genders.PostGender); + + HttpRequest request = new HttpRequest(HttpMethodType.Post, url); + request.Body = data; + + HttpResponse response = await _httpClientService.SendRequestAsync(request); + response.RegisterActionFor2XXSuccess(successAction) + .RegisterActionFor400BadRequest(badRequestAction) + .RegisterActionFor401Unauthorized(unauthorizedAction) + .RegisterActionFor403Forbidden(forbiddenAction) + .ExecuteAction(); + } + + public async Task DeleteGender(long id, Action? successAction = null, Action? unauthorizedAction = null, Action? forbiddenAction = null) + { + string url = GetUrl(EndpointsConfiguration.Genders.DeleteGender, id); + + HttpRequest request = new HttpRequest(HttpMethodType.Delete, url); + + HttpResponse response = await _httpClientService.SendRequestAsync(request); + response.RegisterActionFor2XXSuccess(successAction) + .RegisterActionFor401Unauthorized(unauthorizedAction) + .RegisterActionFor403Forbidden(forbiddenAction) + .ExecuteAction(); + } + + #endregion + + #endregion + + + + #region PRIVATE METHODS + + protected override string GetServiceBase() => EndpointsConfiguration.Genders.Base; + + #endregion +} \ No newline at end of file diff --git a/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.WebAPI/WatchIt.Website.Services.WebAPI.Genders/IGendersWebAPIService.cs b/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.WebAPI/WatchIt.Website.Services.WebAPI.Genders/IGendersWebAPIService.cs new file mode 100644 index 0000000..393b0fe --- /dev/null +++ b/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.WebAPI/WatchIt.Website.Services.WebAPI.Genders/IGendersWebAPIService.cs @@ -0,0 +1,11 @@ +using WatchIt.Common.Model.Genders; + +namespace WatchIt.Website.Services.WebAPI.Genders; + +public interface IGendersWebAPIService +{ + Task GetAllGenders(GenderQueryParameters? query = null, Action>? successAction = null); + Task GetGender(long id, Action? successAction = null, Action? notFoundAction = null); + Task PostGender(GenderRequest data, Action? successAction = null, Action>? badRequestAction = null, Action? unauthorizedAction = null, Action? forbiddenAction = null); + Task DeleteGender(long id, Action? successAction = null, Action? unauthorizedAction = null, Action? forbiddenAction = null); +} \ No newline at end of file diff --git a/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.WebAPI/WatchIt.Website.Services.WebAPI.Genders/WatchIt.Website.Services.WebAPI.Genders.csproj b/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.WebAPI/WatchIt.Website.Services.WebAPI.Genders/WatchIt.Website.Services.WebAPI.Genders.csproj new file mode 100644 index 0000000..abf3359 --- /dev/null +++ b/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.WebAPI/WatchIt.Website.Services.WebAPI.Genders/WatchIt.Website.Services.WebAPI.Genders.csproj @@ -0,0 +1,14 @@ + + + + net8.0 + enable + enable + + + + + + + + diff --git a/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.WebAPI/WatchIt.Website.Services.WebAPI.Persons/IPersonsWebAPIService.cs b/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.WebAPI/WatchIt.Website.Services.WebAPI.Persons/IPersonsWebAPIService.cs index 2f2181f..3572536 100644 --- a/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.WebAPI/WatchIt.Website.Services.WebAPI.Persons/IPersonsWebAPIService.cs +++ b/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.WebAPI/WatchIt.Website.Services.WebAPI.Persons/IPersonsWebAPIService.cs @@ -9,5 +9,10 @@ public interface IPersonsWebAPIService Task PostPerson(PersonRequest data, Action? successAction = null, Action>? badRequestAction = null, Action? unauthorizedAction = null, Action? forbiddenAction = null); Task PutPerson(long id, PersonRequest data, Action? successAction = null, Action>? badRequestAction = null, Action? unauthorizedAction = null, Action? forbiddenAction = null); Task DeletePerson(long id, Action? successAction = null, Action? unauthorizedAction = null, Action? forbiddenAction = null); + Task GetPersonsViewRank(int? first = null, int? days = null, Action>? successAction = null, Action>? badRequestAction = null); + + Task GetPersonPhoto(long id, Action? successAction = null, Action>? badRequestAction = null, Action? notFoundAction = null); + Task PutPersonPhoto(long id, PersonPhotoRequest data, Action? successAction = null, Action>? badRequestAction = null, Action? unauthorizedAction = null, Action? forbiddenAction = null); + Task DeletePersonPhoto(long id, Action? successAction = null, Action? unauthorizedAction = null, Action? forbiddenAction = null); } \ No newline at end of file diff --git a/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.WebAPI/WatchIt.Website.Services.WebAPI.Persons/PersonsWebAPIService.cs b/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.WebAPI/WatchIt.Website.Services.WebAPI.Persons/PersonsWebAPIService.cs index b19d450..cd40eff 100644 --- a/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.WebAPI/WatchIt.Website.Services.WebAPI.Persons/PersonsWebAPIService.cs +++ b/WatchIt.Website/WatchIt.Website.Services/WatchIt.Website.Services.WebAPI/WatchIt.Website.Services.WebAPI.Persons/PersonsWebAPIService.cs @@ -138,6 +138,53 @@ public class PersonsWebAPIService : BaseWebAPIService, IPersonsWebAPIService .ExecuteAction(); } + #endregion + + #region Photo + + public async Task GetPersonPhoto(long id, Action? successAction = null, Action>? badRequestAction = null, Action? notFoundAction = null) + { + string url = GetUrl(EndpointsConfiguration.Persons.GetPersonPhoto, id); + + HttpRequest request = new HttpRequest(HttpMethodType.Get, url); + + HttpResponse response = await _httpClientService.SendRequestAsync(request); + response.RegisterActionFor2XXSuccess(successAction) + .RegisterActionFor400BadRequest(badRequestAction) + .RegisterActionFor404NotFound(notFoundAction) + .ExecuteAction(); + } + + public async Task PutPersonPhoto(long id, PersonPhotoRequest data, Action? successAction = null, Action>? badRequestAction = null, Action? unauthorizedAction = null, Action? forbiddenAction = null) + { + string url = GetUrl(EndpointsConfiguration.Persons.PutPersonPhoto, id); + + HttpRequest request = new HttpRequest(HttpMethodType.Put, url) + { + Body = data + }; + + HttpResponse response = await _httpClientService.SendRequestAsync(request); + response.RegisterActionFor2XXSuccess(successAction) + .RegisterActionFor400BadRequest(badRequestAction) + .RegisterActionFor401Unauthorized(unauthorizedAction) + .RegisterActionFor403Forbidden(forbiddenAction) + .ExecuteAction(); + } + + public async Task DeletePersonPhoto(long id, Action? successAction = null, Action? unauthorizedAction = null, Action? forbiddenAction = null) + { + string url = GetUrl(EndpointsConfiguration.Persons.DeletePersonPhoto, id); + + HttpRequest request = new HttpRequest(HttpMethodType.Delete, url); + + HttpResponse response = await _httpClientService.SendRequestAsync(request); + response.RegisterActionFor2XXSuccess(successAction) + .RegisterActionFor401Unauthorized(unauthorizedAction) + .RegisterActionFor403Forbidden(forbiddenAction) + .ExecuteAction(); + } + #endregion #endregion diff --git a/WatchIt.Website/WatchIt.Website/Components/PersonEditPage/PersonEditFormComponent.razor b/WatchIt.Website/WatchIt.Website/Components/PersonEditPage/PersonEditFormComponent.razor new file mode 100644 index 0000000..c365b9d --- /dev/null +++ b/WatchIt.Website/WatchIt.Website/Components/PersonEditPage/PersonEditFormComponent.razor @@ -0,0 +1,76 @@ +@using WatchIt.Common.Model.Genders +
+ @if (_loaded) + { + + +
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+
+ + - + +
+
+
+
+ +
+ + + @foreach (GenderResponse gender in _genders) + { + + } + +
+
+
+
+ @if (!string.IsNullOrWhiteSpace(_error)) + { + @(_error) + } +
+
+ +
+
+
+
+ } + else + { + + } +
\ No newline at end of file diff --git a/WatchIt.Website/WatchIt.Website/Components/PersonEditPage/PersonEditFormComponent.razor.cs b/WatchIt.Website/WatchIt.Website/Components/PersonEditPage/PersonEditFormComponent.razor.cs new file mode 100644 index 0000000..ad07799 --- /dev/null +++ b/WatchIt.Website/WatchIt.Website/Components/PersonEditPage/PersonEditFormComponent.razor.cs @@ -0,0 +1,110 @@ +using Microsoft.AspNetCore.Components; +using WatchIt.Common.Model.Genders; +using WatchIt.Common.Model.Persons; +using WatchIt.Website.Services.WebAPI.Genders; +using WatchIt.Website.Services.WebAPI.Persons; + +namespace WatchIt.Website.Components.PersonEditPage; + +public partial class PersonEditFormComponent : ComponentBase +{ + #region SERVICES + + [Inject] private NavigationManager NavigationManager { get; set; } = default!; + [Inject] private IPersonsWebAPIService PersonsWebAPIService { get; set; } = default!; + [Inject] private IGendersWebAPIService GendersWebAPIService { get; set; } = default!; + + #endregion + + + + #region PARAMETERS + + [Parameter] public long? Id { get; set; } + [Parameter] public string Class { get; set; } = string.Empty; + + #endregion + + + + #region FIELDS + + private bool _loaded; + private bool _saving; + private string? _error; + + private IEnumerable _genders = []; + + private PersonRequest _person = new PersonRequest(); + + #endregion + + + + #region PRIVATE METHODS + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + List endTasks = new List(); + + // STEP 0 + endTasks.AddRange( + [ + GendersWebAPIService.GetAllGenders(successAction: data => _genders = data) + ]); + if (Id.HasValue) + { + endTasks.AddRange( + [ + PersonsWebAPIService.GetPerson(Id.Value, data => _person = new PersonRequest(data)) + ]); + } + + // END + await Task.WhenAll(endTasks); + + _loaded = true; + StateHasChanged(); + } + } + + private async Task Save() + { + void PutSuccess() + { + _error = null; + _saving = false; + } + + void PostSuccess(PersonResponse data) + { + NavigationManager.NavigateTo($"person/{data.Id}/edit"); + } + + void BadRequest(IDictionary errors) + { + _error = errors.SelectMany(x => x.Value).FirstOrDefault() ?? "Unknown error"; + _saving = false; + } + + void AuthError() + { + _error = "Authentication error"; + _saving = false; + } + + _saving = true; + if (Id.HasValue) + { + await PersonsWebAPIService.PutPerson(Id.Value, _person, PutSuccess, BadRequest, AuthError, AuthError); + } + else + { + await PersonsWebAPIService.PostPerson(_person, PostSuccess, BadRequest, AuthError, AuthError); + } + } + + #endregion +} \ No newline at end of file diff --git a/WatchIt.Website/WatchIt.Website/Components/PersonEditPage/PersonEditFormComponent.razor.css b/WatchIt.Website/WatchIt.Website/Components/PersonEditPage/PersonEditFormComponent.razor.css new file mode 100644 index 0000000..e69de29 diff --git a/WatchIt.Website/WatchIt.Website/Components/PictureEditorComponent.razor b/WatchIt.Website/WatchIt.Website/Components/PictureEditorComponent.razor new file mode 100644 index 0000000..eab6080 --- /dev/null +++ b/WatchIt.Website/WatchIt.Website/Components/PictureEditorComponent.razor @@ -0,0 +1,65 @@ +
+ @if (_loaded) + { +
+ poster + + @if (_pictureChanged || _pictureSaved is not null) + { +
+ @if (_pictureChanged) + { +
+ +
+
+ +
+ } + else if (_pictureSaved is not null) + { +
+ +
+ } +
+ } +
+ } + else + { +
+ +
+ } +
+ + + + \ No newline at end of file diff --git a/WatchIt.Website/WatchIt.Website/Components/PictureEditorComponent.razor.cs b/WatchIt.Website/WatchIt.Website/Components/PictureEditorComponent.razor.cs new file mode 100644 index 0000000..4f9fa02 --- /dev/null +++ b/WatchIt.Website/WatchIt.Website/Components/PictureEditorComponent.razor.cs @@ -0,0 +1,122 @@ +using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components.Forms; +using WatchIt.Common.Model; + +namespace WatchIt.Website.Components; + +public partial class PictureEditorComponent : ComponentBase +{ + #region PARAMETERS + + [Parameter] public long? Id { get; set; } + [Parameter] public int ContentWidth { get; set; } = 300; + [Parameter] public string PicturePlaceholder { get; set; } = "assets/poster.png"; + [Parameter] public string Class { get; set; } = string.Empty; + [Parameter] public required Func, Task> PictureGetTask { get; set; } + [Parameter] public required Func, Task> PicturePutTask { get; set; } + [Parameter] public required Func PictureDeleteTask { get; set; } + + #endregion + + + + #region FIELDS + + private bool _loaded; + + private Picture? _pictureSaved; + private Picture? _pictureSelected; + private bool _pictureChanged; + private bool _pictureSaving; + private bool _pictureDeleting; + + #endregion + + + + #region PRIVATE METHODS + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + List endTask = new List(); + + // STEP 0 + if (Id.HasValue) + { + endTask.AddRange( + [ + PictureGetTask(Id.Value, data => + { + _pictureSaved = data; + _pictureSelected = data; + }) + ]); + } + + // END + await Task.WhenAll(endTask); + + _loaded = true; + StateHasChanged(); + } + } + + private async Task Load(InputFileChangeEventArgs args) + { + if (args.File.ContentType.StartsWith("image")) + { + Stream stream = args.File.OpenReadStream(5242880); + byte[] array; + using (MemoryStream ms = new MemoryStream()) + { + await stream.CopyToAsync(ms); + array = ms.ToArray(); + } + + _pictureSelected = new Picture + { + Image = array, + MimeType = args.File.ContentType + }; + _pictureChanged = true; + } + } + + private async Task Save() + { + void Success(Picture data) + { + _pictureSaved = data; + _pictureSelected = data; + _pictureChanged = false; + _pictureSaving = false; + } + + _pictureSaving = true; + await PicturePutTask(Id.Value, _pictureSelected, Success); + } + + private void Cancel() + { + _pictureSelected = _pictureSaved; + _pictureChanged = false; + } + + private async Task Delete() + { + void Success() + { + _pictureSaved = null; + _pictureSelected = null; + _pictureChanged = false; + _pictureDeleting = false; + } + + _pictureDeleting = true; + await PictureDeleteTask(Id.Value, Success); + } + + #endregion +} \ No newline at end of file diff --git a/WatchIt.Website/WatchIt.Website/Components/PictureEditorComponent.razor.css b/WatchIt.Website/WatchIt.Website/Components/PictureEditorComponent.razor.css new file mode 100644 index 0000000..e69de29 diff --git a/WatchIt.Website/WatchIt.Website/Pages/AdminPage.razor b/WatchIt.Website/WatchIt.Website/Pages/AdminPage.razor index c13c42f..b3f992d 100644 --- a/WatchIt.Website/WatchIt.Website/Pages/AdminPage.razor +++ b/WatchIt.Website/WatchIt.Website/Pages/AdminPage.razor @@ -14,14 +14,14 @@
-

New movie

+

New movie

+
+ +

New TV series

+
+ +

New person

-
-

New TV series

-
-
-

New TV series

-
} else diff --git a/WatchIt.Website/WatchIt.Website/Pages/DatabasePage.razor b/WatchIt.Website/WatchIt.Website/Pages/DatabasePage.razor index 66a49ac..61a64d9 100644 --- a/WatchIt.Website/WatchIt.Website/Pages/DatabasePage.razor +++ b/WatchIt.Website/WatchIt.Website/Pages/DatabasePage.razor @@ -7,12 +7,17 @@ + @("WatchIt - ") @switch (Type) { - case "movies": @("Movies"); break; - case "series": @("Series"); break; + case "movies": + @("Movies"); + break; + case "series": + @("Series"); + break; } - @(" database - WatchIt") + @(" database") diff --git a/WatchIt.Website/WatchIt.Website/Pages/PersonEditPage.razor b/WatchIt.Website/WatchIt.Website/Pages/PersonEditPage.razor new file mode 100644 index 0000000..3930c19 --- /dev/null +++ b/WatchIt.Website/WatchIt.Website/Pages/PersonEditPage.razor @@ -0,0 +1,73 @@ +@using WatchIt.Common.Model.Persons + +@page "/person/{id:long}/edit" +@page "/person/new" + + + + + WatchIt - + @if (_loaded) + { + if (string.IsNullOrWhiteSpace(_error) && _user?.IsAdmin == true) + { + if (_person is not null) + { + @("Edit \"")@(_person.Name)@("\"") + } + else + { + @("Create new person") + } + } + else + { + @("Error") + } + } + else + { + @("Loading") + } + + + + +@if (_loaded) +{ + if (_user?.IsAdmin == true) + { +
+
+
+
+

@(Id is not null ? "Edit" : "Create new") person @(_person is not null ? $" \"{_person.Name}\"" : string.Empty)

+
+
+
+
+
+ +
+
+ +
+
+
+ } + else + { + + } +} +else +{ +
+ +
+} diff --git a/WatchIt.Website/WatchIt.Website/Pages/PersonEditPage.razor.cs b/WatchIt.Website/WatchIt.Website/Pages/PersonEditPage.razor.cs new file mode 100644 index 0000000..52b0d46 --- /dev/null +++ b/WatchIt.Website/WatchIt.Website/Pages/PersonEditPage.razor.cs @@ -0,0 +1,77 @@ +using Microsoft.AspNetCore.Components; +using WatchIt.Common.Model.Persons; +using WatchIt.Website.Layout; +using WatchIt.Website.Services.Utility.Authentication; +using WatchIt.Website.Services.WebAPI.Persons; + +namespace WatchIt.Website.Pages; + +public partial class PersonEditPage : ComponentBase +{ + #region SERVICES + + [Inject] private IAuthenticationService AuthenticationService { get; set; } = default!; + [Inject] private IPersonsWebAPIService PersonsWebAPIService { get; set; } = default!; + + #endregion + + + + #region PARAMETERS + + [Parameter] public long? Id { get; set; } + + [CascadingParameter] public MainLayout Layout { get; set; } + + #endregion + + + + #region FIELDS + + private bool _loaded; + private string? _error; + + private User? _user; + + private PersonResponse? _person; + + #endregion + + + + #region PRIVATE METHODS + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + List step1Tasks = new List(); + List endTasks = new List(); + + // STEP 0 + step1Tasks.AddRange( + [ + Task.Run(async () => _user = await AuthenticationService.GetUserAsync()) + ]); + + // STEP 1 + await Task.WhenAll(step1Tasks); + if (_user?.IsAdmin == true && Id.HasValue) + { + endTasks.AddRange( + [ + PersonsWebAPIService.GetPerson(Id.Value, data => _person = data) + ]); + } + + // END + await Task.WhenAll(endTasks); + + _loaded = true; + StateHasChanged(); + } + } + + #endregion +} \ No newline at end of file diff --git a/WatchIt.Website/WatchIt.Website/Pages/PersonEditPage.razor.css b/WatchIt.Website/WatchIt.Website/Pages/PersonEditPage.razor.css new file mode 100644 index 0000000..e69de29 diff --git a/WatchIt.Website/WatchIt.Website/Program.cs b/WatchIt.Website/WatchIt.Website/Program.cs index 283995a..6975f44 100644 --- a/WatchIt.Website/WatchIt.Website/Program.cs +++ b/WatchIt.Website/WatchIt.Website/Program.cs @@ -9,8 +9,10 @@ using WatchIt.Website.Services.Utility.Authentication; using WatchIt.Website.Services.Utility.Configuration; using WatchIt.Website.Services.Utility.Tokens; using WatchIt.Website.Services.WebAPI.Accounts; +using WatchIt.Website.Services.WebAPI.Genders; using WatchIt.Website.Services.WebAPI.Media; using WatchIt.Website.Services.WebAPI.Movies; +using WatchIt.Website.Services.WebAPI.Persons; using WatchIt.Website.Services.WebAPI.Photos; using WatchIt.Website.Services.WebAPI.Series; @@ -71,10 +73,12 @@ public static class Program // WebAPI builder.Services.AddScoped(); + builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); + builder.Services.AddSingleton(); return builder; } diff --git a/WatchIt.Website/WatchIt.Website/WatchIt.Website.csproj b/WatchIt.Website/WatchIt.Website/WatchIt.Website.csproj index 3ba0027..7a61124 100644 --- a/WatchIt.Website/WatchIt.Website/WatchIt.Website.csproj +++ b/WatchIt.Website/WatchIt.Website/WatchIt.Website.csproj @@ -20,8 +20,10 @@ + +
diff --git a/WatchIt.Website/WatchIt.Website/_Imports.razor b/WatchIt.Website/WatchIt.Website/_Imports.razor index 3a478f4..e8981f0 100644 --- a/WatchIt.Website/WatchIt.Website/_Imports.razor +++ b/WatchIt.Website/WatchIt.Website/_Imports.razor @@ -9,6 +9,7 @@ @using WatchIt.Website @using WatchIt.Website.Layout @using WatchIt.Website.Components +@using WatchIt.Website.Components.PersonEditPage @using WatchIt.Common.Model.Accounts @using WatchIt.Common.Model.Media @using WatchIt.Website.Services.Utility.Tokens diff --git a/WatchIt.Website/WatchIt.Website/appsettings.json b/WatchIt.Website/WatchIt.Website/appsettings.json index ab714ae..9961a07 100644 --- a/WatchIt.Website/WatchIt.Website/appsettings.json +++ b/WatchIt.Website/WatchIt.Website/appsettings.json @@ -20,6 +20,13 @@ "Logout": "/logout", "GetProfilePicture": "/{0}/profile-picture" }, + "Genders": { + "Base": "/genders", + "GetAllGenders": "", + "GetGender": "/{0}", + "PostGender": "", + "DeleteGender": "/{0}" + }, "Genres": { "Base": "/genres", "GetAll": "", @@ -78,7 +85,10 @@ "PostPerson": "", "PutPerson": "/{0}", "DeletePerson": "/{0}", - "GetPersonsViewRank": "/view" + "GetPersonsViewRank": "/view", + "GetPersonPhoto": "/{0}/poster", + "PutPersonPhoto": "/{0}/poster", + "DeletePersonPhoto": "/{0}/poster" } } } diff --git a/WatchIt.sln b/WatchIt.sln index 92de90e..5cd82c9 100644 --- a/WatchIt.sln +++ b/WatchIt.sln @@ -92,6 +92,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WatchIt.WebAPI.Services.Con EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WatchIt.Website.Services.WebAPI.Persons", "WatchIt.Website\WatchIt.Website.Services\WatchIt.Website.Services.WebAPI\WatchIt.Website.Services.WebAPI.Persons\WatchIt.Website.Services.WebAPI.Persons.csproj", "{83D42D72-FF67-4577-8280-2ABD5B20F985}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WatchIt.WebAPI.Services.Controllers.Genders", "WatchIt.WebAPI\WatchIt.WebAPI.Services\WatchIt.WebAPI.Services.Controllers\WatchIt.WebAPI.Services.Controllers.Genders\WatchIt.WebAPI.Services.Controllers.Genders.csproj", "{13BE36AB-2120-4F1B-815A-6F5E3F589EE8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WatchIt.Website.Services.WebAPI.Genders", "WatchIt.Website\WatchIt.Website.Services\WatchIt.Website.Services.WebAPI\WatchIt.Website.Services.WebAPI.Genders\WatchIt.Website.Services.WebAPI.Genders.csproj", "{B74144DE-EF62-430A-AB80-5D185DD03C05}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -140,6 +144,8 @@ Global {960A833F-C195-4D1D-AD4F-D00B57067181} = {46E3711F-18BD-4004-AF53-EA4D8643D92F} {335686F5-65B8-4D66-AAA8-C5032906451D} = {CEC468DB-CC49-47D3-9E3E-1CC9530C3CE7} {83D42D72-FF67-4577-8280-2ABD5B20F985} = {46E3711F-18BD-4004-AF53-EA4D8643D92F} + {13BE36AB-2120-4F1B-815A-6F5E3F589EE8} = {CEC468DB-CC49-47D3-9E3E-1CC9530C3CE7} + {B74144DE-EF62-430A-AB80-5D185DD03C05} = {46E3711F-18BD-4004-AF53-EA4D8643D92F} EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {23383776-1F27-4B5D-8C7C-57BFF75FA473}.Debug|Any CPU.ActiveCfg = Debug|Any CPU @@ -278,5 +284,13 @@ Global {83D42D72-FF67-4577-8280-2ABD5B20F985}.Debug|Any CPU.Build.0 = Debug|Any CPU {83D42D72-FF67-4577-8280-2ABD5B20F985}.Release|Any CPU.ActiveCfg = Release|Any CPU {83D42D72-FF67-4577-8280-2ABD5B20F985}.Release|Any CPU.Build.0 = Release|Any CPU + {13BE36AB-2120-4F1B-815A-6F5E3F589EE8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {13BE36AB-2120-4F1B-815A-6F5E3F589EE8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {13BE36AB-2120-4F1B-815A-6F5E3F589EE8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {13BE36AB-2120-4F1B-815A-6F5E3F589EE8}.Release|Any CPU.Build.0 = Release|Any CPU + {B74144DE-EF62-430A-AB80-5D185DD03C05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B74144DE-EF62-430A-AB80-5D185DD03C05}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B74144DE-EF62-430A-AB80-5D185DD03C05}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B74144DE-EF62-430A-AB80-5D185DD03C05}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal