Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add cancellation tokens #38

Merged
merged 8 commits into from
Aug 28, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ namespace YourTutor.Application.Abstractions.Email
{
public interface IEmailSender
{
Task SendEmailAsync(EmailBase email);
Task SendEmailAsync(EmailBase email, CancellationToken cancellationToken);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
{
public interface IUnitOfWork
{
Task SaveChangesAsync();
Task SaveChangesAsync(CancellationToken cancellationToken);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public async Task<Unit> Handle(Contact request, CancellationToken cancellationTo
var body = $"From: {vm.Email} \nName: {vm.Name} \nDescription: {vm.Description}";
var email = new ContactEmail(body, vm.To, _emailSettings.From);

await _emailSender.SendEmailAsync(email);
await _emailSender.SendEmailAsync(email, cancellationToken);

return Unit.Value;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ public async Task<Guid> Handle(CreateOffer request, CancellationToken cancellati
var vm = request.CreateOfferVm;
var offer = new Offer(Guid.NewGuid(), vm.Description, vm.Subject, vm.Price, vm.IsRemotely, vm.Location, request.UserId);

await _offerRepository.CreateOffer(offer);
await _unitOfWork.SaveChangesAsync();
await _offerRepository.CreateOffer(offer, cancellationToken);
await _unitOfWork.SaveChangesAsync(cancellationToken);

return offer.Id;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ public DeleteOfferHandler(IOfferRepository offerRepository, IUnitOfWork unitOfWo

public async Task<Unit> Handle(DeleteOffer request, CancellationToken cancellationToken)
{
await _offerRepository.RemoveOfferById(request.Id);
await _unitOfWork.SaveChangesAsync();
await _offerRepository.RemoveOfferById(request.Id, cancellationToken);
await _unitOfWork.SaveChangesAsync(cancellationToken);

_logger.LogInformation("Offer with id: {offerId} has been removed", request.Id.ToString());
return Unit.Value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,13 @@ public EditTutorHandler(ITutorRepository tutorRepository, IUnitOfWork unitOfWork

public async Task<Unit> Handle(EditTutor request, CancellationToken cancellationToken)
{
var tutor = await _tutorRepository.GetTutorById(request.UserId);
if (tutor is null)
throw new NotFoundTutorException(request.UserId);
var tutor = await _tutorRepository.GetTutorById(request.UserId, cancellationToken) ?? throw new NotFoundTutorException(request.UserId);

tutor.UpdateDescription(request.EditTutorVm.Description);
tutor.UpdateCountry(request.EditTutorVm.Country);
tutor.UpdateLanguage(request.EditTutorVm.Language);

await _unitOfWork.SaveChangesAsync();
await _unitOfWork.SaveChangesAsync(cancellationToken);

return Unit.Value;
}
Expand Down
2 changes: 1 addition & 1 deletion src/YourTutor.Application/Commands/SignIn/LoginHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public LoginHandler(IUserRepository userRepository, ISignInManager signInManager
public async Task<LoginResponse> Handle(Login request, CancellationToken cancellationToken)
{
var loginResponse = new LoginResponse();
var user = await _userRepository.GetUserByEmailAsync(request.LoginVm.Email.ToLower());
var user = await _userRepository.GetUserByEmailAsync(request.LoginVm.Email.ToLower(), cancellationToken);
if (user is null)
{
loginResponse.Errors.Add("Invalid credentials");
Expand Down
7 changes: 3 additions & 4 deletions src/YourTutor.Application/Commands/SignUp/RegisterHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public async Task<RegisterResponse> Handle(Register command, CancellationToken c
{
var registerVm = command.RegisterVm;
var response = new RegisterResponse();
if (await _userRepository.IsEmailAlreadyExistsAsync(registerVm.Email))
if (await _userRepository.IsEmailAlreadyExistsAsync(registerVm.Email, cancellationToken))
{
response.Errors.Add($"Email already exists: {registerVm.Email}");
_logger.LogError(AppLogEvent.SignUp, "Problem with registering user, email already exists, email {@email}", registerVm.Email);
Expand Down Expand Up @@ -67,11 +67,10 @@ public async Task<RegisterResponse> Handle(Register command, CancellationToken c
if (response.Errors.Count > 0)
return response;

await _userRepository.AddUserAsync(user);
await _userRepository.AddUserAsync(user, cancellationToken);
await _signInManager.SignInAsync(false, user.Id, $"{user.FirstName.Value} {user.LastName.Value}");

if (_emailSettings.RegistrationNotificationIsEnabled)
await _emailSender.SendEmailAsync(new RegisterEmail(user.Email, _emailSettings.From));
await _emailSender.SendEmailAsync(new RegisterEmail(user.Email, _emailSettings.From), cancellationToken);

return response;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public GetOfferDetailsHandler(ILogger<GetOfferDetailsHandler> logger, IOfferRepo

public async Task<OfferDetailsVm> Handle(GetOfferDetails request, CancellationToken cancellationToken)
{
var offer = await _offerRepository.GetOfferDetails(request.id);
var offer = await _offerRepository.GetOfferDetails(request.id, cancellationToken);

if (offer == null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public async Task<SmallOffersListViewModel> Handle(GetSmallOffers request, Cance
: pagination;

var smallOffersGroup = await _offerRepository.GetSmallOffers(offer.IsRemotely, offer.IsRemotelyFiltered, offer.PriceFrom, offer.PriceTo,
_pageSize, ExcludeRecords(pagination.PageNumber, _pageSize), pagination.SearchString);
_pageSize, ExcludeRecords(pagination.PageNumber, _pageSize), pagination.SearchString, cancellationToken);


var results = smallOffersGroup.Offers
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public GetTutorByUserIdHandler(ITutorRepository tutorRepository)

public async Task<TutorDetailsVm> Handle(GetTutorByUserId request, CancellationToken cancellationToken)
{
var details = await _tutorRepository.GetTutorDetailsByUserId(request.UserId) ?? default;
var details = await _tutorRepository.GetTutorDetailsByUserId(request.UserId, cancellationToken) ?? default;

if (details is null)
return default;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public GetTutorEditDetailsHandler(ITutorRepository tutorRepository)

public async Task<EditTutorVm> Handle(GetTutorEditDetails request, CancellationToken cancellationToken)
{
var details = await _tutorRepository.GetTutorDetailsForEdit(request.TutorId);
var details = await _tutorRepository.GetTutorDetailsForEdit(request.TutorId, cancellationToken);

return new()
{
Expand Down
11 changes: 6 additions & 5 deletions src/YourTutor.Core/Repositories/IOfferRepository.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
using YourTutor.Core.Entities;
using System.Threading;
using YourTutor.Core.Entities;
using YourTutor.Core.ReadModels;
using YourTutor.Core.ValueObjects;

namespace YourTutor.Core.Repositories;

public interface IOfferRepository
{
Task CreateOffer(Offer offer);
Task CreateOffer(Offer offer, CancellationToken cancellationToken);

Task RemoveOfferById(OfferId id);
Task RemoveOfferById(OfferId id, CancellationToken cancellationToken);

Task<OfferDetailsReadmodel> GetOfferDetails(OfferId id);
Task<OfferDetailsReadmodel> GetOfferDetails(OfferId id, CancellationToken cancellationToken);

Task<bool> CheckIfUserHasAccessToOffer(OfferId offerId, UserId userId);

Task<SmallOfferPaginationReadModel> GetSmallOffers(bool isRemotely, bool isRemotelyFiltered, int priceFrom, int priceTo, int pageSize, int excludeRecords, string searchString);
Task<SmallOfferPaginationReadModel> GetSmallOffers(bool isRemotely, bool isRemotelyFiltered, int priceFrom, int priceTo, int pageSize, int excludeRecords, string searchString, CancellationToken cancellationToken);
}
6 changes: 3 additions & 3 deletions src/YourTutor.Core/Repositories/ITutorRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ namespace YourTutor.Core.Repositories
{
public interface ITutorRepository
{
Task<TutorDetailsReadModel> GetTutorDetailsByUserId(Guid userId);
Task<Tutor> GetTutorById(Guid userId);
Task<TutorDetailsReadModel> GetTutorDetailsByUserId(Guid userId, CancellationToken cancellationToken);
Task<Tutor> GetTutorById(Guid userId, CancellationToken cancellationToken);

Task<TutorDetailsForEditReadModel> GetTutorDetailsForEdit(UserId userId);
Task<TutorDetailsForEditReadModel> GetTutorDetailsForEdit(UserId userId, CancellationToken cancellationToken);
}
}
6 changes: 3 additions & 3 deletions src/YourTutor.Core/Repositories/IUserRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ namespace YourTutor.Core.Repositories
{
public interface IUserRepository
{
Task<User> GetUserByEmailAsync(string email);
Task<User> GetUserByEmailAsync(string email, CancellationToken cancellationToken);

Task AddUserAsync(User user);
Task AddUserAsync(User user, CancellationToken cancellationToken);

Task<bool> IsEmailAlreadyExistsAsync(string email);
Task<bool> IsEmailAlreadyExistsAsync(string email, CancellationToken cancellationToken);
}
}
21 changes: 9 additions & 12 deletions src/YourTutor.Infrastructure/DAL/DatabaseInitializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,49 +14,46 @@ internal sealed class DatabaseInitializer : IHostedService
private readonly IServiceProvider _serviceProvider;
private readonly ILogger<DatabaseInitializer> _logger;
private readonly IYourTutorSeeder _seeder;
private readonly DbInitializerSettings _dbInitSettings;

public DatabaseInitializer(IServiceProvider serviceProvider, ILogger<DatabaseInitializer> logger,
IYourTutorSeeder seeder, IOptions<DbInitializerSettings> dbInitSettings)
IYourTutorSeeder seeder)
{
_serviceProvider = serviceProvider;
_logger = logger;
_seeder = seeder;
_dbInitSettings = dbInitSettings.Value;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
if (!_dbInitSettings.IsEnabled)
return;

using var scope = _serviceProvider.CreateAsyncScope();
var dbContext = scope.ServiceProvider.GetRequiredService<YourTutorDbContext>();

if (!dbContext.Database.IsRelational())
{
_logger.LogInformation(AppLogEvent.DbInit, "Database isn't relational, migations haven't been added to database");
return;
}

_logger.LogInformation(AppLogEvent.DbInit, "Check migrations...");
var pendingMigrations = await dbContext.Database.GetPendingMigrationsAsync();
var pendingMigrations = await dbContext.Database.GetPendingMigrationsAsync(cancellationToken);
if (pendingMigrations != null && pendingMigrations.Any())
{
await dbContext.Database.MigrateAsync();
await dbContext.Database.MigrateAsync(cancellationToken);
_logger.LogInformation(AppLogEvent.DbInit, "Migrations have been added to database");

if (!await dbContext.Users.AnyAsync())
if (!await dbContext.Users.AnyAsync(cancellationToken))
{
_logger.LogInformation(AppLogEvent.DbInit, "Database need to be seeded");
_logger.LogInformation(AppLogEvent.DbInit, "Seeding...");
var users = _seeder.GetSeedData();
await dbContext.Users.AddRangeAsync(users);
await dbContext.SaveChangesAsync();
await dbContext.Users.AddRangeAsync(users, cancellationToken);
await dbContext.SaveChangesAsync(cancellationToken);
_logger.LogInformation(AppLogEvent.DbInit, "Database has been seeded");
}
}
else
{
_logger.LogInformation(AppLogEvent.DbInit, "Database is up to date, do not need add any migrations");
}

}

public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
Expand Down
9 changes: 9 additions & 0 deletions src/YourTutor.Infrastructure/DAL/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using YourTutor.Core.Repositories;
using YourTutor.Infrastructure.DAL.Repositories;
using YourTutor.Infrastructure.DAL.Seeds;
using YourTutor.Infrastructure.Settings;

namespace YourTutor.Infrastructure.DAL
{
Expand Down Expand Up @@ -34,6 +35,14 @@ internal static IServiceCollection AddSeeders(this IServiceCollection services)
return services
.AddSingleton<IYourTutorSeeder, YourTutorSeeder>();
}

internal static IServiceCollection AddDbInitializerHostedService(this IServiceCollection services, IConfiguration configuration)
{
if (configuration.GetSettings<DbInitializerSettings>().IsEnabled)
services.AddHostedService<DatabaseInitializer>();

return services;
}
}
}

Expand Down
18 changes: 9 additions & 9 deletions src/YourTutor.Infrastructure/DAL/Repositories/OfferRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ public OfferRepository(YourTutorDbContext yourTutorDbContext)
_db = yourTutorDbContext;
}

public async Task CreateOffer(Offer offer)
public async Task CreateOffer(Offer offer, CancellationToken cancellationToken)
{
await _db
.AddAsync(offer);
.AddAsync(offer, cancellationToken);
}

public async Task<OfferDetailsReadmodel> GetOfferDetails(OfferId id)
public async Task<OfferDetailsReadmodel> GetOfferDetails(OfferId id, CancellationToken cancellationToken)
{
var offer = await _db
.Offers
Expand All @@ -30,7 +30,7 @@ public async Task<OfferDetailsReadmodel> GetOfferDetails(OfferId id)
.Where(o => o.Id == id)
.Select(o => new OfferDetailsReadmodel(o.Id, o.Description, o.Subject, o.Price, o.Location, o.IsRemotely, o.Tutor.User.FirstName + " " + o.Tutor.User.LastName,
o.Tutor.User.Email, o.Tutor.Country, o.Tutor.Language, o.Tutor.UserId))
.FirstOrDefaultAsync();
.FirstOrDefaultAsync(cancellationToken);

return offer;
}
Expand All @@ -46,15 +46,15 @@ public async Task<bool> CheckIfUserHasAccessToOffer(OfferId offerId, UserId user
return result;
}

public async Task RemoveOfferById(OfferId id)
public async Task RemoveOfferById(OfferId id, CancellationToken cancellationToken)
{
var offer = await _db.Offers
.FirstAsync(o => o.Id == id);
.FirstAsync(o => o.Id == id, cancellationToken);

_db.Remove(offer);
}

public async Task<SmallOfferPaginationReadModel> GetSmallOffers(bool isRemotely, bool isRemotelyFiltered, int priceFrom, int priceTo, int pageSize, int excludeRecords, string searchString)
public async Task<SmallOfferPaginationReadModel> GetSmallOffers(bool isRemotely, bool isRemotelyFiltered, int priceFrom, int priceTo, int pageSize, int excludeRecords, string searchString, CancellationToken cancellationToken)
{
var query = _db.
Offers
Expand Down Expand Up @@ -89,15 +89,15 @@ public async Task<SmallOfferPaginationReadModel> GetSmallOffers(bool isRemotely,
.Where(o => o.Price >= new Price(priceFrom) && o.Price <= new Price(priceTo));
}

var quantity = await query.CountAsync();
var quantity = await query.CountAsync(cancellationToken);

query = query
.Skip(excludeRecords)
.Take(pageSize);

var items = await query
.Select(o => new SmallOffersReadModel(o.Id, o.Subject, o.Description, o.Price, o.Location, o.IsRemotely, o.Tutor.User.FirstName + " " + o.Tutor.User.LastName, o.Tutor.User.Email))
.ToListAsync();
.ToListAsync(cancellationToken);

return new SmallOfferPaginationReadModel(items, quantity);
}
Expand Down
12 changes: 6 additions & 6 deletions src/YourTutor.Infrastructure/DAL/Repositories/TutorRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,32 @@ public TutorRepository(YourTutorDbContext dbContext)
_dbContext = dbContext;
}

public async Task<TutorDetailsReadModel> GetTutorDetailsByUserId(Guid userId)
public async Task<TutorDetailsReadModel> GetTutorDetailsByUserId(Guid userId, CancellationToken cancellationToken)
{
var details = await _dbContext.Tutor
.Include(t => t.User)
.Where(t => t.UserId == new UserId(userId))
.Select(t => new TutorDetailsReadModel(t.UserId, $"{t.User.FirstName.Value} {t.User.LastName.Value}", t.User.Email, t.Description, t.Country, t.Language))
.FirstOrDefaultAsync();
.FirstOrDefaultAsync(cancellationToken);

return details;
}

public async Task<Tutor> GetTutorById(Guid userId)
public async Task<Tutor> GetTutorById(Guid userId, CancellationToken cancellationToken)
{
var tutor = await _dbContext
.Tutor
.FirstOrDefaultAsync(t => t.UserId == new UserId(userId));
.FirstOrDefaultAsync(t => t.UserId == new UserId(userId), cancellationToken);
return tutor;
}

public async Task<TutorDetailsForEditReadModel> GetTutorDetailsForEdit(UserId userId)
public async Task<TutorDetailsForEditReadModel> GetTutorDetailsForEdit(UserId userId, CancellationToken cancellationToken)
{
var details = await _dbContext
.Tutor
.Where(t => t.UserId == userId)
.Select(t => new TutorDetailsForEditReadModel(t.Description, t.Country, t.Language))
.FirstOrDefaultAsync();
.FirstOrDefaultAsync(cancellationToken);

return details;
}
Expand Down
15 changes: 8 additions & 7 deletions src/YourTutor.Infrastructure/DAL/Repositories/UserRepository.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.EntityFrameworkCore;
using System.Threading;
using YourTutor.Core.Entities;
using YourTutor.Core.Repositories;

Expand All @@ -13,17 +14,17 @@ public UserRepository(YourTutorDbContext dbContext)
_dbContext = dbContext;
}

public async Task AddUserAsync(User user)
public async Task AddUserAsync(User user, CancellationToken cancellationToken)
{
await _dbContext.AddAsync<User>(user);
await _dbContext.SaveChangesAsync();
await _dbContext.AddAsync(user, cancellationToken);
await _dbContext.SaveChangesAsync(cancellationToken);
}

public Task<User> GetUserByEmailAsync(string email) => _dbContext.Users
.FirstOrDefaultAsync(u => u.Email == email);
public Task<User> GetUserByEmailAsync(string email, CancellationToken cancellationToken) => _dbContext.Users
.FirstOrDefaultAsync(u => u.Email == email, cancellationToken);

public Task<bool> IsEmailAlreadyExistsAsync(string email) =>
_dbContext.Users.AnyAsync(u => u.Email == email);
public Task<bool> IsEmailAlreadyExistsAsync(string email, CancellationToken cancellationToken) =>
_dbContext.Users.AnyAsync(u => u.Email == email, cancellationToken);
}
}

Expand Down
Loading