Skip to content

Commit

Permalink
feat(authentication,groups): configured authentication & added groups…
Browse files Browse the repository at this point in the history
… creation
  • Loading branch information
Samuel Verdejo committed Nov 17, 2023
1 parent 814cfc4 commit 7781dcf
Show file tree
Hide file tree
Showing 31 changed files with 936 additions and 21 deletions.
2 changes: 1 addition & 1 deletion Application/Groups/CreateGroupCommand.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using Application.Shared.Command;

namespace Application;
namespace Application.Groups;

public sealed record CreateGroupCommand(Guid GroupId, string GroupName, Guid UserId) : ICommand;
2 changes: 1 addition & 1 deletion Application/Groups/Handlers/CreateGroupCommandHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using Domain;
using Domain.Groups;

namespace Application;
namespace Application.Groups;

public class CreateGroupCommandHandler : ICommandHandler<CreateGroupCommand>
{
Expand Down
30 changes: 30 additions & 0 deletions Application/Groups/Handlers/JoinGroupCommandHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Application.Shared.Command;
using Domain;
using Domain.Groups;
using MediatR;

namespace Application;

public class JoinGroupCommandHandler : ICommandHandler<JoinGroupCommand>
{
private readonly IGroupRepository _groupRepository;

private readonly ISender sender;

Check warning on line 12 in Application/Groups/Handlers/JoinGroupCommandHandler.cs

View workflow job for this annotation

GitHub Actions / Build project and run Architectural and Unit testing

The field 'JoinGroupCommandHandler.sender' is never used

public JoinGroupCommandHandler(IGroupRepository groupRepository)

Check warning on line 14 in Application/Groups/Handlers/JoinGroupCommandHandler.cs

View workflow job for this annotation

GitHub Actions / Build project and run Architectural and Unit testing

Non-nullable field 'sender' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.
{
_groupRepository = groupRepository;
}

public async Task Handle(JoinGroupCommand request, CancellationToken cancellationToken = default)
{
var groupId = GroupId.Create(request.GroupId);
var memberId = UserId.Create(request.NewMember);

var criteria = new GroupByIdCriteria(groupId);

var group = await _groupRepository.MatchFirst(criteria);

group.Join(memberId);
}
}
18 changes: 18 additions & 0 deletions Application/Groups/JoinGroupCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using Application.Shared.Command;

namespace Application;

public sealed record JoinGroupCommand : ICommand
{
public JoinGroupCommand(Guid newMember, Guid groupId)
{
NewMember = newMember;
GroupId = groupId;
}

public Guid NewMember { get; set; }

public Guid GroupId { get; set; }


}
11 changes: 11 additions & 0 deletions Application/Users/Commands/CreateUserCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

using Application.Shared.Command;

namespace Application;

public sealed record CreateUserCommand : ICommand
{
public Guid Id { get; set; }

public string Mail { get; set; }

Check warning on line 10 in Application/Users/Commands/CreateUserCommand.cs

View workflow job for this annotation

GitHub Actions / Build project and run Architectural and Unit testing

Non-nullable property 'Mail' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
}
24 changes: 24 additions & 0 deletions Application/Users/Commands/Handlers/CreateUserCommandHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using Application.Shared.Command;
using Domain;

namespace Application;

public class CreateUserCommandHandler : ICommandHandler<CreateUserCommand>
{
private readonly IUserRepository _userRepository;

public CreateUserCommandHandler(IUserRepository userRepository)
{
_userRepository = userRepository;
}

public async Task Handle(CreateUserCommand request, CancellationToken cancellationToken)
{
var id = UserId.Create(request.Id);
var mail = UserMail.Create(request.Mail);

var user = User.Create(id, mail);

await _userRepository.Add(user);
}
}
5 changes: 4 additions & 1 deletion Domain/Groups/Entities/Group.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,17 @@ public class Group : AggregateRoot<Group>

public HashSet<UserId> Members { get; private set; } = new();

public List<GroupRecords> Records { get; private set; } = new();
public List<GroupRecord> Records { get; private set; } = new();

private Group()
{
}

protected Group(GroupId id, GroupName name, UserId admin)
{
Id = id;
Name = name;
Admin = admin;
}

public static Group Create(GroupId id, GroupName name, UserId admin)
Expand Down
11 changes: 11 additions & 0 deletions Domain/Groups/Repository/Criteria/GroupByIdCriteria.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System.Linq.Expressions;
using Domain.Shared.Base;

namespace Domain.Groups;

public class GroupByIdCriteria : Criteria<Group>
{
public GroupByIdCriteria(GroupId groupId) : base(group => group.Id == groupId)
{
}
}
10 changes: 10 additions & 0 deletions Domain/Groups/ValueObjects/GroupRecord.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace Domain.Groups;

public class GroupRecord
{
public Decimal Amount { get; private set; }

public UserId Creator { get; private set; }

Check warning on line 7 in Domain/Groups/ValueObjects/GroupRecord.cs

View workflow job for this annotation

GitHub Actions / Build project and run Architectural and Unit testing

Non-nullable property 'Creator' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.

public List<RecordPercentage> Percentages { get; private set; }

Check warning on line 9 in Domain/Groups/ValueObjects/GroupRecord.cs

View workflow job for this annotation

GitHub Actions / Build project and run Architectural and Unit testing

Non-nullable property 'Percentages' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
}
6 changes: 0 additions & 6 deletions Domain/Groups/ValueObjects/GroupRecords.cs

This file was deleted.

26 changes: 26 additions & 0 deletions Domain/Groups/ValueObjects/RecordPercentage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
namespace Domain;

public class RecordPercentage
{
public UserId Member { get; set; }

public Decimal Percentage { get; set; }

private RecordPercentage()
{
}

private RecordPercentage(UserId member, Decimal percentage)
{
Member = member;
Percentage = percentage;
}

public static RecordPercentage Create(UserId member, Decimal percentage)
{
if (percentage < 0 || percentage > 1)
throw new ArgumentOutOfRangeException(nameof(percentage));

return new RecordPercentage(member, percentage);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

namespace Infrastructure;

public class JwtBearerOptionsSetup : IConfigureOptions<JwtBearerOptions>
public class JwtBearerOptionsSetup : IConfigureNamedOptions<JwtBearerOptions>
{
private readonly JwtOptions _options;

Expand All @@ -14,6 +14,11 @@ public JwtBearerOptionsSetup(IOptions<JwtOptions> options)
_options = options.Value;
}

public void Configure(string? name, JwtBearerOptions options)
{
Configure(options);
}

public void Configure(JwtBearerOptions options)
{
options.TokenValidationParameters = new()
Expand Down
3 changes: 2 additions & 1 deletion Persistance/DependencyInjection.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using Domain.Shared.Base;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Persistance.Jobs;
Expand All @@ -12,6 +11,7 @@
using Domain.Expenses;
using Domain.Budgets;
using Domain;
using Domain.Groups;

namespace Persistance;
public static class DependencyInjection
Expand Down Expand Up @@ -59,6 +59,7 @@ public static IServiceCollection AddPersistance(this IServiceCollection services
services.AddScoped<IExpenseRepository, ExpenseRepository>();
services.AddScoped<IBudgetRepository, BudgetRepository>();
services.AddScoped<IUserRepository, UserRepository>();
services.AddScoped<IGroupRepository, GroupRepository>();

services.AddQuartzHostedService();

Expand Down
71 changes: 71 additions & 0 deletions Persistance/Entities/Groups/Configuration/GroupConfiguration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using Domain;
using Domain.Groups;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace Persistance;

public class GroupConfiguration : IEntityTypeConfiguration<Group>
{
public void Configure(EntityTypeBuilder<Group> builder)
{
builder.HasKey(group => group.Id);
builder.HasIndex(group => group.Id);
builder.Property(group => group.Id)
.HasConversion(
src => src.Value,
raw => GroupId.Create(raw));

builder.Property(group => group.Admin)
.HasConversion(
src => src.Value,
raw => UserId.Create(raw));

builder.Property(group => group.Name)
.HasMaxLength(50)
.HasConversion(
src => src.Value,
raw => GroupName.Create(raw));

builder.OwnsMany(
group => group.Members,
membersBuilder => {
// TODO: review how to change this name from Value to MemberId
membersBuilder.HasKey(memberId => memberId.Value);
membersBuilder.ToTable("GroupMembers");
});

builder.OwnsMany(group => group.Records,
recordBuilder => {
var identityProperty = "GroupRecordId";
recordBuilder.Property<Guid>(identityProperty)
.ValueGeneratedOnAdd();
recordBuilder.HasKey(identityProperty);
recordBuilder.Property(record => record.Creator)
.HasConversion(
src => src.Value,
raw => UserId.Create(raw));
recordBuilder.Property(record => record.Amount);
recordBuilder.OwnsMany(record => record.Percentages,
percentagesBuilder => {
var percentageIdentityProperty = "MemberPercentageId";
percentagesBuilder.Property<Guid>(percentageIdentityProperty)
.ValueGeneratedOnAdd();
percentagesBuilder.HasKey(percentageIdentityProperty);
percentagesBuilder.Property(percentage => percentage.Member)
.HasConversion(
src => src.Value,
raw => UserId.Create(raw));
percentagesBuilder.Property(percentage => percentage.Percentage);
});
});
}
}
17 changes: 17 additions & 0 deletions Persistance/Entities/Groups/Repository/GroupRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using Domain.Groups;
using Persistance.Shared;

namespace Persistance;

internal class GroupRepository : AbstractRepository<Group>, IGroupRepository
{
public GroupRepository(ApplicationDbContext dbContext) : base(dbContext)
{
}

public Task Delete(Group group)
{
_context.Set<Group>().Remove(group);
return Task.CompletedTask;
}
}
Loading

0 comments on commit 7781dcf

Please sign in to comment.