Skip to content

Commit

Permalink
Merge pull request #33 from quizer-app/develop
Browse files Browse the repository at this point in the history
Add claims to JWT
  • Loading branch information
EloToJaa authored Jan 30, 2024
2 parents f6d0027 + cb27bb9 commit 6312d6b
Show file tree
Hide file tree
Showing 40 changed files with 335 additions and 110 deletions.
7 changes: 7 additions & 0 deletions Quizer.sln
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{6EB218AE-AB5B-4601-A909-DDB63BB384CC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Quizer.Seed", "tests\Quizer.Seed\Quizer.Seed.csproj", "{3B99FAB7-0D62-47FE-AE6E-9494AADD5CBF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -55,6 +57,10 @@ Global
{6EB218AE-AB5B-4601-A909-DDB63BB384CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6EB218AE-AB5B-4601-A909-DDB63BB384CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6EB218AE-AB5B-4601-A909-DDB63BB384CC}.Release|Any CPU.Build.0 = Release|Any CPU
{3B99FAB7-0D62-47FE-AE6E-9494AADD5CBF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3B99FAB7-0D62-47FE-AE6E-9494AADD5CBF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3B99FAB7-0D62-47FE-AE6E-9494AADD5CBF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3B99FAB7-0D62-47FE-AE6E-9494AADD5CBF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -65,6 +71,7 @@ Global
{38AC9614-809E-419D-A209-023F9C2AFE75} = {494A7292-4421-4AEF-AB70-D0D62DC59055}
{644F4CCF-BCCE-4AB5-AD20-D1D8E9174A84} = {494A7292-4421-4AEF-AB70-D0D62DC59055}
{22E70F95-D56C-4122-8317-F28B3A9F9620} = {494A7292-4421-4AEF-AB70-D0D62DC59055}
{3B99FAB7-0D62-47FE-AE6E-9494AADD5CBF} = {1230AD7A-D6D4-4C7F-8817-65DDACA2C059}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F9941C6F-58D7-4463-9EA6-D40F74E8CC90}
Expand Down
6 changes: 0 additions & 6 deletions src/Quizer.Api/ApplicationConfiguration.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Quizer.Api.Common.Settings;
using Quizer.Infrastructure;
using Serilog;

namespace Quizer.Api;
Expand All @@ -8,11 +7,6 @@ public static class ApplicationConfiguration
{
public static WebApplication UsePresentation(this WebApplication app, ConfigurationManager configuration)
{
if(app.Environment.IsDevelopment())
{
app.UseMigration();
}

app.UseVersionedSwagger(configuration);

app.UseSerilogRequestLogging();
Expand Down
19 changes: 12 additions & 7 deletions src/Quizer.Api/Common/Mapping/QuizMappingConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,16 @@ private static void RegisterQuestion(TypeAdapterConfig config)
config.NewConfig<Answer, AnswerResponse>()
.Map(dest => dest, src => src);

config.NewConfig<(UpdateQuestionRequest Request, Guid QuestionId), UpdateQuestionCommand>()
config.NewConfig<(UpdateQuestionRequest Request, Guid? UserId, Guid QuestionId), UpdateQuestionCommand>()
.Map(dest => dest.QuestionId, src => src.QuestionId)
.Map(dest => dest.UserId, src => src.UserId)
.Map(dest => dest.QuestionText, src => src.Request.Question)
.Map(dest => dest.Answers, src => src.Request.Answers)
.Map(dest => dest, src => src.Request);

config.NewConfig<(CreateQuestionRequest Request, Guid QuizId), CreateQuestionCommand>()
config.NewConfig<(CreateQuestionRequest Request, Guid? UserId, Guid QuizId), CreateQuestionCommand>()
.Map(dest => dest.QuizId, src => src.QuizId)
.Map(dest => dest.UserId, src => src.UserId)
.Map(dest => dest.QuestionText, src => src.Request.Question)
.Map(dest => dest.Answers, src => src.Request.Answers)
.Map(dest => dest, src => src.Request);
Expand All @@ -51,11 +53,12 @@ private static void RegisterQuestion(TypeAdapterConfig config)

private static void RegisterQuiz(TypeAdapterConfig config)
{
config.NewConfig<(CreateQuizRequest Request, string UserId), CreateQuizCommand>()
.Map(dest => dest.UserId, src => new Guid(src.UserId))
config.NewConfig<(CreateQuizRequest Request, Guid? UserId), CreateQuizCommand>()
.Map(dest => dest.UserId, src => src.UserId)
.Map(dest => dest, src => src.Request);

config.NewConfig<(UpdateQuizRequest Request, Guid QuizId), UpdateQuizCommand>()
config.NewConfig<(UpdateQuizRequest Request, Guid? UserId, Guid QuizId), UpdateQuizCommand>()
.Map(dest => dest.UserId, src => src.UserId)
.Map(dest => dest.QuizId, src => src.QuizId)
.Map(dest => dest, src => src.Request);

Expand All @@ -64,13 +67,15 @@ private static void RegisterQuiz(TypeAdapterConfig config)

config.NewConfig<Quiz, ShortQuizResponse>()
.Map(dest => dest.Id, src => src.Id.Value.ToString())
.Map(dest => dest.UserId, src => src.UserId.ToString())
.Map(dest => dest.CreatedBy, src => src.CreatedBy.ToString())
.Map(dest => dest.UpdatedBy, src => src.UpdatedBy.ToString())
.Map(dest => dest.AverageRating, src => src.AverageRating.Value)
.Map(dest => dest.NumberOfRatings, src => src.AverageRating.NumRatings);

config.NewConfig<DetailedQuizResult, QuizResponse>()
.Map(dest => dest.Id, src => src.Quiz.Id.Value.ToString())
.Map(dest => dest.UserId, src => src.Quiz.UserId.ToString())
.Map(dest => dest.CreatedBy, src => src.Quiz.CreatedBy.ToString())
.Map(dest => dest.UpdatedBy, src => src.Quiz.UpdatedBy.ToString())
.Map(dest => dest.AverageRating, src => src.Quiz.AverageRating.Value)
.Map(dest => dest.NumberOfRatings, src => src.Quiz.AverageRating.NumRatings)
.Map(dest => dest, src => src.Quiz)
Expand Down
10 changes: 10 additions & 0 deletions src/Quizer.Api/Controllers/V1/ApiController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Quizer.Api.Common.Http;
using System.Security.Claims;

namespace Quizer.Api.Controllers.V1;

Expand Down Expand Up @@ -57,4 +58,13 @@ private IActionResult ValidationProblem(List<Error> errors)
}
return ValidationProblem(modelState);
}

protected Guid? UserId {
get
{
string? userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
Guid? userIdGuid = userId is null ? null : new Guid(userId);
return userIdGuid;
}
}
}
6 changes: 3 additions & 3 deletions src/Quizer.Api/Controllers/V1/QuestionController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public async Task<IActionResult> CreateQuestion(
Guid quizId,
[FromBody] CreateQuestionRequest request)
{
var command = _mapper.Map<CreateQuestionCommand>((request, quizId));
var command = _mapper.Map<CreateQuestionCommand>((request, UserId, quizId));
var result = await _mediator.Send(command);

return result.Match(
Expand All @@ -53,7 +53,7 @@ public async Task<IActionResult> UpdateQuestion(
Guid questionId,
[FromBody] UpdateQuestionRequest request)
{
var command = _mapper.Map<UpdateQuestionCommand>((request, questionId));
var command = _mapper.Map<UpdateQuestionCommand>((request, UserId, questionId));
var result = await _mediator.Send(command);

return result.Match(
Expand All @@ -64,7 +64,7 @@ public async Task<IActionResult> UpdateQuestion(
[HttpDelete("{questionId:guid}")]
public async Task<IActionResult> DeleteQuestion(Guid questionId)
{
var command = new DeleteQuestionCommand(questionId);
var command = new DeleteQuestionCommand((Guid)UserId!, questionId);
var result = await _mediator.Send(command);

return result.Match(
Expand Down
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 @@ -12,7 +12,7 @@
using Quizer.Application.Quizes.Queries.GetQuizImage;
using Quizer.Contracts.Common;
using Quizer.Contracts.Quiz;
using System.Security.Claims;
using Quizer.Infrastructure.Authentication;

namespace Quizer.Api.Controllers.V1;

Expand All @@ -29,6 +29,7 @@ public QuizController(ISender mediator, IMapper mapper)
_mapper = mapper;
}

[AllowAnonymous]
[HttpGet]
public async Task<IActionResult> GetQuizes(
string? searchTerm,
Expand All @@ -53,8 +54,8 @@ public async Task<IActionResult> GetQuizes(
Problem);
}

[HttpGet("{quizId:guid}")]
[AllowAnonymous]
[HttpGet("{quizId:guid}")]
public async Task<IActionResult> GetQuizById(Guid quizId)
{
var query = new GetQuizByIdQuery(quizId);
Expand All @@ -65,8 +66,8 @@ public async Task<IActionResult> GetQuizById(Guid quizId)
Problem);
}

[HttpGet("{userName}/{quizSlug}")]
[AllowAnonymous]
[HttpGet("{userName}/{quizSlug}")]
public async Task<IActionResult> GetQuizByName(string userName, string quizSlug)
{
var query = new GetQuizByNameQuery(userName, quizSlug);
Expand All @@ -77,12 +78,12 @@ public async Task<IActionResult> GetQuizByName(string userName, string quizSlug)
Problem);
}

[HasPermission(Permission.CreateQuiz)]
[HttpPost]
public async Task<IActionResult> CreateQuiz(
CreateQuizRequest request)
{
string userId = User.FindFirstValue(ClaimTypes.NameIdentifier)!;
var command = _mapper.Map<CreateQuizCommand>((request, userId));
var command = _mapper.Map<CreateQuizCommand>((request, UserId));
var result = await _mediator.Send(command);

return result.Match(
Expand All @@ -95,7 +96,7 @@ public async Task<IActionResult> UpdateQuiz(
Guid quizId,
[FromBody] UpdateQuizRequest request)
{
var command = _mapper.Map<UpdateQuizCommand>((request, quizId));
var command = _mapper.Map<UpdateQuizCommand>((request, UserId, quizId));
var result = await _mediator.Send(command);

return result.Match(
Expand Down
1 change: 1 addition & 0 deletions src/Quizer.Api/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

var app = builder.Build();
{
await app.MigrateDatabase();
app.UsePresentation(builder.Configuration);
}

4 changes: 2 additions & 2 deletions src/Quizer.Api/appsettings.Development.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
},
"JwtSettings": {
"Secret": "8@aeQ&V!9b^j*&kJKwebGrfQ3Tx!355q8@aeQ&V!9b^j*&kJKwebGrfQ3Tx!355q",
"Issuer": "https://quizer.com",
"Audience": "https://quizer.com"
"Issuer": "Quizer",
"Audience": "Quizer"
},
"ConnectionStrings": {
"DefaultConnection": "Host=localhost;Port=5432;Database=quizer;User Id=postgres;Password=postgres;"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ namespace Quizer.Application.Authentication.Commands.Login;

public class LoginCommandHandler : IRequestHandler<LoginCommand, ErrorOr<LoginResult>>
{
private readonly IJwtTokenGenerator _jwtTokenGenerator;
private readonly IJwtTokenProvider _jwtTokenGenerator;
private readonly IRefreshTokenRepository _refreshTokenRepository;
private readonly UserManager<User> _userManager;
private readonly SignInManager<User> _signInManager;

public LoginCommandHandler(IJwtTokenGenerator jwtTokenGenerator, UserManager<User> userManager, SignInManager<User> signInManager, IRefreshTokenRepository refreshTokenRepository)
public LoginCommandHandler(IJwtTokenProvider jwtTokenGenerator, UserManager<User> userManager, SignInManager<User> signInManager, IRefreshTokenRepository refreshTokenRepository)
{
_jwtTokenGenerator = jwtTokenGenerator;
_userManager = userManager;
Expand All @@ -34,10 +34,10 @@ public async Task<ErrorOr<LoginResult>> Handle(LoginCommand query, CancellationT
if (!result.Succeeded)
return Errors.Authentication.InvalidCredentials;

string accessToken = _jwtTokenGenerator.GenerateAccessToken(user);
string refreshToken = _jwtTokenGenerator.GenerateRefreshToken(user);
string accessToken = await _jwtTokenGenerator.GenerateAccessToken(user);
string refreshToken = await _jwtTokenGenerator.GenerateRefreshToken(user);

var token = Domain.RefreshTokenAggregate.RefreshToken.Create(refreshToken);
var token = Domain.RefreshTokenAggregate.RefreshToken.Create(new Guid(user.Id), refreshToken);
await _refreshTokenRepository.Add(token);

return new LoginResult(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ namespace Quizer.Application.Authentication.Commands.RefreshToken;
public class RefreshTokenCommandHandler : IRequestHandler<RefreshTokenCommand, ErrorOr<string>>
{
private readonly ILogger<RefreshTokenCommandHandler> _logger;
private readonly IJwtTokenGenerator _jwtTokenGenerator;
private readonly IJwtTokenProvider _jwtTokenGenerator;
private readonly IRefreshTokenRepository _refreshTokenRepository;

public RefreshTokenCommandHandler(ILogger<RefreshTokenCommandHandler> logger, IJwtTokenGenerator jwtTokenGenerator, IRefreshTokenRepository refreshTokenRepository)
public RefreshTokenCommandHandler(ILogger<RefreshTokenCommandHandler> logger, IJwtTokenProvider jwtTokenGenerator, IRefreshTokenRepository refreshTokenRepository)
{
_logger = logger;
_jwtTokenGenerator = jwtTokenGenerator;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

namespace Quizer.Application.Common.Interfaces.Authentication;

public interface IJwtTokenGenerator
public interface IJwtTokenProvider
{
string GenerateAccessToken(User user);
string GenerateRefreshToken(User user);
Task<string> GenerateAccessToken(User user);
Task<string> GenerateRefreshToken(User user);
string GenerateAccessToken(string refreshToken);
Task<bool> ValidateRefreshToken(string refreshToken);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
namespace Quizer.Application.Quizes.Commands.CreateQuestion;

public record CreateQuestionCommand(
Guid UserId,
Guid QuizId,
string QuestionText,
List<CreateQuestionAnswer> Answers
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public async Task<ErrorOr<QuestionId>> Handle(CreateQuestionCommand request, Can
return Errors.Quiz.NotFound;

var result = Question.Create(
request.UserId,
(QuizId)quiz.Id,
request.QuestionText,
request.Answers
Expand All @@ -37,7 +38,9 @@ public async Task<ErrorOr<QuestionId>> Handle(CreateQuestionCommand request, Can

await _questionRepository.Add(question);

quiz.AddQuestion(question);
quiz.AddQuestion(
request.UserId,
question);

return (QuestionId)question.Id;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ public async Task<ErrorOr<QuizId>> Handle(CreateQuizCommand request, Cancellatio
string slug = _slugifyService.GenerateSlug(request.Name);

var result = Quiz.Create(
request.UserId,
request.Name,
slug,
request.Description,
request.UserId,
userName
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
namespace Quizer.Application.Quizes.Commands.DeleteQuestion;

public record DeleteQuestionCommand(
Guid UserId,
Guid QuestionId
) : IRequest<ErrorOr<QuestionId>>;
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public async Task<ErrorOr<QuestionId>> Handle(DeleteQuestionCommand request, Can
var quiz = await _quizRepository.Get(question.QuizId);
if (quiz is null) return Errors.Quiz.NotFound;

quiz.DeleteQuestion(question);
quiz.DeleteQuestion(request.UserId, question);
_questionRepository.Delete(question);
question.Delete();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
namespace Quizer.Application.Quizes.Commands.UpdateQuestion;

public record UpdateQuestionCommand(
Guid UserId,
Guid QuestionId,
string QuestionText,
List<CreateQuestionAnswer> Answers
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public async Task<ErrorOr<QuestionId>> Handle(UpdateQuestionCommand request, Can
if (question is null) return Errors.Question.NotFound;

var result = question.Update(
request.UserId,
request.QuestionText,
request.Answers
.ConvertAll(a => Answer.Create(a.Text, a.IsCorrect).Value));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Quizer.Application.Quizes.Commands.UpdateQuiz;

public record UpdateQuizCommand(
Guid UserId,
Guid QuizId,
string Name,
string Description) : IRequest<ErrorOr<QuizId>>;
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@

namespace Quizer.Application.Quizes.Commands.UpdateQuiz;

public class UpdateQuizImageCommandHandler : IRequestHandler<UpdateQuizCommand, ErrorOr<QuizId>>
public class UpdateQuizCommandHandler : IRequestHandler<UpdateQuizCommand, ErrorOr<QuizId>>
{
private readonly IQuizRepository _quizRepository;
private readonly ISlugifyService _slugifyService;

public UpdateQuizImageCommandHandler(IQuizRepository quizRepository, ISlugifyService slugifyService)
public UpdateQuizCommandHandler(IQuizRepository quizRepository, ISlugifyService slugifyService)
{
_quizRepository = quizRepository;
_slugifyService = slugifyService;
Expand All @@ -29,7 +29,12 @@ public async Task<ErrorOr<QuizId>> Handle(UpdateQuizCommand request, Cancellatio

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

var result = quiz.Update(request.Name, slug, request.Description);
var result = quiz.Update(
request.UserId,
request.Name,
slug,
request.Description);

if (result.IsError) return result.Errors;

return id;
Expand Down
Loading

0 comments on commit 6312d6b

Please sign in to comment.