Skip to content

Commit

Permalink
Merge pull request #8 from quizer-app/develop
Browse files Browse the repository at this point in the history
Add GetQuizByName
  • Loading branch information
EloToJaa authored Dec 26, 2023
2 parents ac4be4a + c959731 commit 04b9c2a
Show file tree
Hide file tree
Showing 23 changed files with 668 additions and 65 deletions.
13 changes: 7 additions & 6 deletions src/Quizer.Api/Controllers/V1/QuizController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
using Quizer.Application.Quizes.Commands.CreateQuiz;
using Quizer.Application.Quizes.Commands.DeleteQuiz;
using Quizer.Application.Quizes.Commands.UpdateQuiz;
using Quizer.Application.Quizes.Queries.GetQuiz;
using Quizer.Application.Quizes.Queries.GetQuizById;
using Quizer.Application.Quizes.Queries.GetQuizByName;
using Quizer.Application.Quizes.Queries.GetQuizes;
using Quizer.Contracts.Quiz;
using System.Security.Claims;
Expand Down Expand Up @@ -37,23 +38,23 @@ public async Task<IActionResult> GetQuizes(string? userId = null)
Problem);
}

[HttpGet("id/{id:guid}")]
[HttpGet("{id:guid}")]
[AllowAnonymous]
public async Task<IActionResult> GetQuizById(Guid id)
{
var query = new GetQuizQuery(id, null);
var query = new GetQuizByIdQuery(id);
var result = await _mediator.Send(query);

return result.Match(
quizes => Ok(_mapper.Map<QuizResponse>(quizes)),
Problem);
}

[HttpGet("name/{name}")]
[HttpGet("{userName}/{quizName}")]
[AllowAnonymous]
public async Task<IActionResult> GetQuizByName(string name)
public async Task<IActionResult> GetQuizByName(string userName, string quizName)
{
var query = new GetQuizQuery(null, name);
var query = new GetQuizByNameQuery(userName, quizName);
var result = await _mediator.Send(query);

return result.Match(
Expand Down
4 changes: 2 additions & 2 deletions src/Quizer.Api/OpenApi/ConfigureSwaggerOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ public void Configure(SwaggerGenOptions options)
description.GroupName,
new OpenApiInfo()
{
Title = "Example API",
Description = "An example API",
Title = "Quizer API",
Description = "An API for the Quizer App",
Version = description.ApiVersion.ToString(),
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ public interface IQuizRepository
Task Add(Quiz quiz);
Task<List<Quiz>> GetAll(Guid? userId = null);
Task<Quiz?> Get(QuizId id);
Task<Quiz?> Get(string name);
Task<Quiz?> Get(string userName, string quizName);
void Delete(Quiz quiz);
}
4 changes: 4 additions & 0 deletions src/Quizer.Application/DependencyInjection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using MediatR;
using Microsoft.Extensions.DependencyInjection;
using Quizer.Application.Common.Behaviors;
using Quizer.Application.Services;
using System.Reflection;

namespace Quizer.Application;
Expand All @@ -18,6 +19,9 @@ public static IServiceCollection AddApplication(this IServiceCollection services
services.AddScoped(typeof(IPipelineBehavior<,>), typeof(UnitOfWorkBehavior<,>));

services.AddValidatorsFromAssembly(assembly);

services.AddServices();

return services;
}
}
1 change: 1 addition & 0 deletions src/Quizer.Application/Quizer.Application.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Diacritics" Version="3.3.18" />
<PackageReference Include="ErrorOr" Version="1.3.0" />
<PackageReference Include="FluentValidation" Version="11.9.0" />
<PackageReference Include="FluentValidation.AspNetCore" Version="11.3.0" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,35 @@
using ErrorOr;
using MediatR;
using Microsoft.AspNetCore.Identity;
using Quizer.Application.Common.Interfaces.Persistance;
using Quizer.Application.Services.Slugify;
using Quizer.Domain.Common.Errors;
using Quizer.Domain.Common.ValueObjects;
using Quizer.Domain.QuizAggregate;
using Quizer.Domain.QuizAggregate.Entities;
using Quizer.Domain.UserAggregate;

namespace Quizer.Application.Quizes.Commands.CreateQuiz;

public class CreateQuizCommandHandler : IRequestHandler<CreateQuizCommand, ErrorOr<QuizId>>
{
private readonly IQuizRepository _quizRepository;
private readonly ISlugifyService _slugifyService;
private readonly UserManager<User> _userManager;

public CreateQuizCommandHandler(IQuizRepository quizRepository)
public CreateQuizCommandHandler(IQuizRepository quizRepository, ISlugifyService slugifyService, UserManager<User> userManager)
{
_quizRepository = quizRepository;
_slugifyService = slugifyService;
_userManager = userManager;
}

public async Task<ErrorOr<QuizId>> Handle(CreateQuizCommand request, CancellationToken cancellationToken)
{
if ((await _quizRepository.Get(request.Name)) is not null)
var user = await _userManager.FindByIdAsync(request.UserId.ToString());
string userName = user is null || user.UserName is null ? "Anonymous" : user.UserName;

if ((await _quizRepository.Get(userName, request.Name)) is not null)
return Errors.Quiz.DuplicateName;

var errors = new List<Error>();
Expand All @@ -36,10 +46,14 @@ public async Task<ErrorOr<QuizId>> Handle(CreateQuizCommand request, Cancellatio
var questions = questionResults
.ConvertAll(q => q.Value);

string slug = _slugifyService.GenerateSlug(request.Name);

var result = Quiz.Create(
request.Name,
slug,
request.Description,
request.UserId,
userName,
AverageRating.CreateNew(),
questions
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using MediatR;
using Quizer.Application.Common.Interfaces.Persistance;
using Quizer.Application.Quizes.Commands.UpdateQuiz;
using Quizer.Application.Services.Slugify;
using Quizer.Domain.Common.Errors;
using Quizer.Domain.QuizAggregate;

Expand All @@ -10,10 +11,12 @@ namespace Quizer.Application.Quizes.Commands.DeleteQuiz;
public class UpdateQuizCommandHandler : IRequestHandler<UpdateQuizCommand, ErrorOr<QuizId>>
{
private readonly IQuizRepository _quizRepository;
private readonly ISlugifyService _slugifyService;

public UpdateQuizCommandHandler(IQuizRepository quizRepository)
public UpdateQuizCommandHandler(IQuizRepository quizRepository, ISlugifyService slugifyService)
{
_quizRepository = quizRepository;
_slugifyService = slugifyService;
}

public async Task<ErrorOr<QuizId>> Handle(UpdateQuizCommand request, CancellationToken cancellationToken)
Expand All @@ -25,7 +28,9 @@ public async Task<ErrorOr<QuizId>> Handle(UpdateQuizCommand request, Cancellatio

var id = (QuizId)quiz.Id;

var result = quiz.Update(request.Name, request.Description);
string slug = _slugifyService.GenerateSlug(request.Name);

var result = quiz.Update(request.Name, slug, request.Description);
if (result.IsError) return result.Errors;

return id;
Expand Down
9 changes: 0 additions & 9 deletions src/Quizer.Application/Quizes/Queries/GetQuiz/GetQuizQuery.cs

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using ErrorOr;
using MediatR;
using Quizer.Domain.QuizAggregate;

namespace Quizer.Application.Quizes.Queries.GetQuizById;

public record GetQuizByIdQuery(
Guid QuizId) : IRequest<ErrorOr<Quiz>>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using ErrorOr;
using MediatR;
using Quizer.Application.Common.Interfaces.Persistance;
using Quizer.Domain.Common.Errors;
using Quizer.Domain.QuizAggregate;

namespace Quizer.Application.Quizes.Queries.GetQuizById;

public class GetQuizByIdQueryHandler : IRequestHandler<GetQuizByIdQuery, ErrorOr<Quiz>>
{
private readonly IQuizRepository _quizRepository;

public GetQuizByIdQueryHandler(IQuizRepository quizRepository)
{
_quizRepository = quizRepository;
}

public async Task<ErrorOr<Quiz>> Handle(GetQuizByIdQuery request, CancellationToken cancellationToken)
{
var quiz = await _quizRepository.Get(QuizId.Create(request.QuizId));
if (quiz is null) return Errors.Quiz.NotFound;
return quiz;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using ErrorOr;
using MediatR;
using Quizer.Domain.QuizAggregate;

namespace Quizer.Application.Quizes.Queries.GetQuizByName;

public record GetQuizByNameQuery(
string UserName,
string QuizName) : IRequest<ErrorOr<Quiz>>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using ErrorOr;
using MediatR;
using Microsoft.AspNetCore.Identity;
using Quizer.Application.Common.Interfaces.Persistance;
using Quizer.Domain.Common.Errors;
using Quizer.Domain.QuizAggregate;

namespace Quizer.Application.Quizes.Queries.GetQuizByName;

public class GetQuizByNameQueryHandler : IRequestHandler<GetQuizByNameQuery, ErrorOr<Quiz>>
{
private readonly IQuizRepository _quizRepository;

public GetQuizByNameQueryHandler(IQuizRepository quizRepository)
{
_quizRepository = quizRepository;
}

public async Task<ErrorOr<Quiz>> Handle(GetQuizByNameQuery request, CancellationToken cancellationToken)
{
var quiz = await _quizRepository.Get(request.UserName, request.QuizName);
if (quiz is null) return Errors.Quiz.NotFound;

return quiz;
}
}
17 changes: 17 additions & 0 deletions src/Quizer.Application/Services/DependencyInjection.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using Diacritics;
using Microsoft.Extensions.DependencyInjection;
using Quizer.Application.Services.Slugify;

namespace Quizer.Application.Services;

public static class DependencyInjection
{
public static IServiceCollection AddServices(this IServiceCollection services)
{
services.AddSingleton<IDiacriticsMapper, DefaultDiacriticsMapper>();
services.AddSingleton<ISlugifyService, SlugifyService>();

return services;
}
}

7 changes: 7 additions & 0 deletions src/Quizer.Application/Services/Slugify/ISlugifyService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Quizer.Application.Services.Slugify
{
public interface ISlugifyService
{
string GenerateSlug(string str);
}
}
71 changes: 71 additions & 0 deletions src/Quizer.Application/Services/Slugify/SlugifyService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using System.Text.RegularExpressions;
using System.Text;
using Diacritics;

namespace Quizer.Application.Services.Slugify
{
public class SlugifyService : ISlugifyService
{
protected readonly Config _config;
protected readonly IDiacriticsMapper _diacriticsMapper;

public SlugifyService(IDiacriticsMapper diacriticsMapper)
{
_config = new Config();
_diacriticsMapper = diacriticsMapper;
}

public string GenerateSlug(string str)
{
if (_config.ForceLowerCase)
str = str.ToLower();

str = CleanWhiteSpace(str, _config.CollapseWhiteSpace);
str = ApplyReplacements(str, _config.CharacterReplacements);
str = _diacriticsMapper.RemoveDiacritics(str);
str = DeleteCharacters(str, _config.DeniedCharactersRegex);

return str;
}

protected string CleanWhiteSpace(string str, bool collapse)
{
return Regex.Replace(str, collapse ? @"\s+" : @"\s", " ");
}

protected string ApplyReplacements(string str, Dictionary<string, string> replacements)
{
StringBuilder sb = new StringBuilder(str);

foreach (KeyValuePair<string, string> replacement in replacements)
sb.Replace(replacement.Key, replacement.Value);

return sb.ToString();
}

protected string DeleteCharacters(string str, string regex)
{
return Regex.Replace(str, regex, "");
}

public class Config
{
public Dictionary<string, string> CharacterReplacements { get; set; }
public bool ForceLowerCase { get; set; }
public bool CollapseWhiteSpace { get; set; }
public string DeniedCharactersRegex { get; set; }

public Config()
{
CharacterReplacements = new Dictionary<string, string>
{
{ " ", "-" }
};

ForceLowerCase = true;
CollapseWhiteSpace = true;
DeniedCharactersRegex = @"[^a-zA-Z0-9\-\._]";
}
}
}
}
2 changes: 2 additions & 0 deletions src/Quizer.Contracts/Quiz/QuizResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
public record QuizResponse(
string Id,
string UserId,
string UserName,
string Name,
string Slug,
string Description,
double AverageRating,
int NumberOfRatings,
Expand Down
Loading

0 comments on commit 04b9c2a

Please sign in to comment.