From 15eea06073973651ee3ca2455698042b7a3c2f34 Mon Sep 17 00:00:00 2001 From: StevanFreeborn Date: Fri, 24 Jun 2022 11:35:33 -0500 Subject: [PATCH] finished implementing characters endpoints --- server/Controllers/v1/CharactersController.cs | 2 +- server/Models/Character.cs | 12 ++ server/Models/CharacterFilter.cs | 15 +- .../Repositories/CharacterRepository.cs | 52 +++++- server/Program.cs | 161 +++++++++--------- .../ConfigureSwaggerOptions.cs | 2 +- .../Filters/ApiVersionOperationFilter.cs | 2 +- 7 files changed, 157 insertions(+), 89 deletions(-) rename server/{Options => SwaggerOptions}/ConfigureSwaggerOptions.cs (97%) rename server/{Options => SwaggerOptions}/Filters/ApiVersionOperationFilter.cs (94%) diff --git a/server/Controllers/v1/CharactersController.cs b/server/Controllers/v1/CharactersController.cs index 9f94a33..9e1c3e6 100644 --- a/server/Controllers/v1/CharactersController.cs +++ b/server/Controllers/v1/CharactersController.cs @@ -7,7 +7,7 @@ namespace server.Controllers.v1 { [ApiController] [ApiVersion("1.0")] - [Route("/api/episodes")] + [Route("/api/characters")] [Produces("application/json")] public class CharactersController : ControllerBase { diff --git a/server/Models/Character.cs b/server/Models/Character.cs index 46fada7..15e18ab 100644 --- a/server/Models/Character.cs +++ b/server/Models/Character.cs @@ -12,6 +12,12 @@ namespace server.Models [BsonRepresentation(BsonType.ObjectId)] public string? Id { get; set; } + /// + /// The character's full name. + /// + [BsonElement("fullName")] + public string FullName => $"{FirstName} {LastName}"; + /// /// The character's first name. /// @@ -24,6 +30,12 @@ namespace server.Models [BsonElement("lastName")] public string? LastName { get; set; } + /// + /// The full name of the actor who potrayed the character. + /// + [BsonElement("actorFullName")] + public string ActorFullName => $"{ActorFirstName} {ActorLastName}"; + /// /// The first name of the actor who potrayed the character. /// diff --git a/server/Models/CharacterFilter.cs b/server/Models/CharacterFilter.cs index 75e83dd..3d84338 100644 --- a/server/Models/CharacterFilter.cs +++ b/server/Models/CharacterFilter.cs @@ -8,6 +8,19 @@ namespace server.Models { public class CharacterFilter { - // TODO: Build character filter model + /// + /// Used to filter characters by their name. + /// + public string? Name { get; set; } = null; + + /// + /// Used to filter characters by the actor's name. + /// + public string? ActorName { get; set; } = null; + + /// + /// Used to filter characters by a season. + /// + public int? Season { get; set; } = null; } } diff --git a/server/Persistence/Repositories/CharacterRepository.cs b/server/Persistence/Repositories/CharacterRepository.cs index ab14804..5838d55 100644 --- a/server/Persistence/Repositories/CharacterRepository.cs +++ b/server/Persistence/Repositories/CharacterRepository.cs @@ -1,19 +1,59 @@ using server.Models; +using MongoDB.Driver; +using MongoDB.Driver.Linq; namespace server.Persistence.Repositories { public class CharacterRepository : ICharacterRepository { - // TODO: Implement getcharactersasync - public Task> GetCharactersAsync(CharacterFilter filter) + private readonly IDbContext _context; + + public CharacterRepository(IDbContext context) { - throw new NotImplementedException(); + _context = context; } - // TODO: Implement getcharacterbyidasync - public Task GetCharacterByIdAsync(string id) + public async Task> GetCharactersAsync(CharacterFilter filter) { - throw new NotImplementedException(); + try + { + var query = _context.Characters.AsQueryable(); + + if (filter?.Name != null) + { + query = query.Where(character => character.FullName.ToLower().Contains(filter.Name.ToLower())); + } + + if (filter?.ActorName != null) + { + query = query.Where(character => character.ActorFullName.ToLower().Contains(filter.ActorName.ToLower())); + } + + if (filter?.Season != null) + { + query = query.Where(character => character.Seasons.Any(season => season == filter.Season)); + } + + return await query.ToListAsync(); + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + } + + public async Task GetCharacterByIdAsync(string id) + { + try + { + return await _context.Characters.Find(character => character.Id == id).SingleOrDefaultAsync(); + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } } } } diff --git a/server/Program.cs b/server/Program.cs index 247734d..f4a4ea9 100644 --- a/server/Program.cs +++ b/server/Program.cs @@ -2,13 +2,13 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.AspNetCore.Mvc.Versioning; using Microsoft.Extensions.Options; -using server.Options; +using server.SwaggerOptions; using server.Persistence; using server.Persistence.Repositories; using server.Persistence.Seed; using System.Reflection; using AspNetCoreRateLimit; -using server.Options.Filters; +using server.SwaggerOptions.Filters; if (args.Length == 2 && args[0].ToLower() == "seed") { @@ -34,99 +34,102 @@ if (args.Length == 2 && args[0].ToLower() == "seed") await seeder.SeedCharactersAsync(); } } - -var builder = WebApplication.CreateBuilder(args); - -builder.Services.AddMemoryCache(); - -builder.Services.Configure( - builder.Configuration.GetSection("IpRateLimiting")); - -builder.Services.Configure( - builder.Configuration.GetSection("IpRateLimitPolicies")); - -builder.Services.AddInMemoryRateLimiting(); - -builder.Services.AddSingleton(); - -builder.Services.Configure( - builder.Configuration.GetSection("MongoDBSettings")); - -builder.Services.AddSingleton(sp => - sp.GetRequiredService>().Value); - -builder.Services.AddSingleton(); - -builder.Services.AddScoped(); - -builder.Services.AddScoped(); - -builder.Services.AddScoped(); - -builder.Services.AddScoped(); - -builder.Services.AddControllers(); - -builder.Services.AddEndpointsApiExplorer(); - -builder.Services.AddSwaggerGen(options => +else { - var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; - var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); - options.IncludeXmlComments(xmlPath); - options.OperationFilter(); -}); + var builder = WebApplication.CreateBuilder(args); -builder.Services.ConfigureOptions(); + builder.Services.AddMemoryCache(); -builder.Services.AddApiVersioning(config => -{ - config.DefaultApiVersion = new ApiVersion(1, 0); - config.AssumeDefaultVersionWhenUnspecified = true; - config.ReportApiVersions = true; - config.ApiVersionReader = new HeaderApiVersionReader("x-api-version"); -}); + builder.Services.Configure( + builder.Configuration.GetSection("IpRateLimiting")); -builder.Services.AddVersionedApiExplorer(config => -{ - config.GroupNameFormat = "'v'VVV"; -}); + builder.Services.Configure( + builder.Configuration.GetSection("IpRateLimitPolicies")); -var app = builder.Build(); + builder.Services.AddInMemoryRateLimiting(); -app.UseStaticFiles(); + builder.Services.AddSingleton(); -app.UseSwagger(options => -{ - options.RouteTemplate = "/{documentName}/docs.json"; -}); + builder.Services.Configure( + builder.Configuration.GetSection("MongoDBSettings")); -app.UseSwaggerUI(options => -{ - var provider = app.Services.GetRequiredService(); + builder.Services.AddSingleton(sp => + sp.GetRequiredService>().Value); - foreach (var description in provider.ApiVersionDescriptions) + builder.Services.AddSingleton(); + + builder.Services.AddScoped(); + + builder.Services.AddScoped(); + + builder.Services.AddScoped(); + + builder.Services.AddScoped(); + + builder.Services.AddControllers(); + + builder.Services.AddEndpointsApiExplorer(); + + builder.Services.AddSwaggerGen(options => { - var url = $"/{description.GroupName}/docs.json"; - var name = $"criminalmindsapi v{description.ApiVersion}"; + var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; + var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); - options.RoutePrefix = String.Empty; - options.SwaggerEndpoint(url, name); - options.EnableTryItOutByDefault(); - options.DisplayRequestDuration(); - options.DocumentTitle = "criminalmindsapi"; - } -}); + options.IncludeXmlComments(xmlPath); + options.OperationFilter(); + }); -app.UseHttpsRedirection(); + builder.Services.ConfigureOptions(); -app.UseAuthorization(); + builder.Services.AddApiVersioning(config => + { + config.DefaultApiVersion = new ApiVersion(1, 0); + config.AssumeDefaultVersionWhenUnspecified = true; + config.ReportApiVersions = true; + config.ApiVersionReader = new HeaderApiVersionReader("x-api-version"); + }); -app.MapControllers(); + builder.Services.AddVersionedApiExplorer(config => + { + config.GroupNameFormat = "'v'VVV"; + }); -app.UseIpRateLimiting(); + var app = builder.Build(); -app.Run(); + app.UseStaticFiles(); + + app.UseSwagger(options => + { + options.RouteTemplate = "/{documentName}/docs.json"; + }); + + app.UseSwaggerUI(options => + { + var provider = app.Services.GetRequiredService(); + + foreach (var description in provider.ApiVersionDescriptions) + { + var url = $"/{description.GroupName}/docs.json"; + var name = $"criminalmindsapi v{description.ApiVersion}"; + + options.RoutePrefix = String.Empty; + options.SwaggerEndpoint(url, name); + options.EnableTryItOutByDefault(); + options.DisplayRequestDuration(); + options.DocumentTitle = "criminalmindsapi"; + } + }); + + app.UseHttpsRedirection(); + + app.UseAuthorization(); + + app.MapControllers(); + + app.UseIpRateLimiting(); + + app.Run(); +} diff --git a/server/Options/ConfigureSwaggerOptions.cs b/server/SwaggerOptions/ConfigureSwaggerOptions.cs similarity index 97% rename from server/Options/ConfigureSwaggerOptions.cs rename to server/SwaggerOptions/ConfigureSwaggerOptions.cs index 8d2a8aa..a919623 100644 --- a/server/Options/ConfigureSwaggerOptions.cs +++ b/server/SwaggerOptions/ConfigureSwaggerOptions.cs @@ -3,7 +3,7 @@ using Microsoft.Extensions.Options; using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; -namespace server.Options +namespace server.SwaggerOptions { public class ConfigureSwaggerOptions : IConfigureOptions { diff --git a/server/Options/Filters/ApiVersionOperationFilter.cs b/server/SwaggerOptions/Filters/ApiVersionOperationFilter.cs similarity index 94% rename from server/Options/Filters/ApiVersionOperationFilter.cs rename to server/SwaggerOptions/Filters/ApiVersionOperationFilter.cs index 3d5eaf5..4445471 100644 --- a/server/Options/Filters/ApiVersionOperationFilter.cs +++ b/server/SwaggerOptions/Filters/ApiVersionOperationFilter.cs @@ -2,7 +2,7 @@ using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; -namespace server.Options.Filters +namespace server.SwaggerOptions.Filters { public class ApiVersionOperationFilter : IOperationFilter {