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..d22d610 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; } 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/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/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.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/appsettings.json b/WatchIt.Website/WatchIt.Website/appsettings.json index 69b7410..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": "", 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