Skip to content
1 change: 1 addition & 0 deletions server/StudySharp.API/Controllers/CourseController.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Threading.Tasks;
using AutoMapper;
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using StudySharp.API.Requests.Courses;
using StudySharp.API.Requests.PracticalBlocks;
Expand Down
24 changes: 21 additions & 3 deletions server/StudySharp.ApplicationServices/Commands/AddCourseCommand.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
using System.Threading;
using System.Threading.Tasks;
using FluentValidation;
using MediatR;
using Microsoft.EntityFrameworkCore;
using StudySharp.Domain.Constants;
using StudySharp.Domain.General;
using StudySharp.Domain.Models;
using StudySharp.Domain.ValidationRules;
using StudySharp.DomainServices;

namespace StudySharp.ApplicationServices.Commands
Expand All @@ -15,6 +17,24 @@ public sealed class AddCourseCommand : IRequest<OperationResult>
public int TeacherId { get; set; }
}

public class AddCourseCommandValidator : AbstractValidator<AddCourseCommand>
{
public AddCourseCommandValidator(ICourseRules rules)
{
RuleFor(_ => new { _.Name, _.TeacherId })
.NotEmpty()
.WithMessage(string.Format(ErrorConstants.FieldIsRequired, nameof(Course.Name)))
.MustAsync((courseTeacherAndName, token) => rules.IsNameUniqueAsync(courseTeacherAndName.Name, courseTeacherAndName.TeacherId, token))
.WithMessage(_ => string.Format(ErrorConstants.EntityAlreadyExists, nameof(Course), nameof(Course.Name), _.Name));

RuleFor(_ => _.TeacherId)
.NotEmpty()
.WithMessage(string.Format(ErrorConstants.FieldIsRequired, nameof(Course.TeacherId)))
.MustAsync(rules.IsTeacherIdExistAsync)
.WithMessage(_ => string.Format(ErrorConstants.EntityNotFound, nameof(Teacher), nameof(Teacher.Id), _.TeacherId));
}
}

public sealed class AddCourseCommandHandler : IRequestHandler<AddCourseCommand, OperationResult>
{
private readonly StudySharpDbContext _context;
Expand All @@ -26,9 +46,7 @@ public AddCourseCommandHandler(StudySharpDbContext sharpDbContext)

public async Task<OperationResult> Handle(AddCourseCommand request, CancellationToken cancellationToken)
{
if (await _context.Courses.AnyAsync(
_ => _.Name.ToLower().Equals(request.Name.ToLower()) && _.TeacherId == request.TeacherId,
cancellationToken))
if (await _context.Courses.AnyAsync(_ => _.Name.ToLower().Equals(request.Name.ToLower()) && _.TeacherId == request.TeacherId))
{
return OperationResult.Fail(string.Format(ErrorConstants.EntityAlreadyExists, nameof(Course), nameof(Course.Name), request.Name));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
using System.Threading;
using System.Threading.Tasks;
using FluentValidation;
using MediatR;
using StudySharp.Domain.Constants;
using StudySharp.Domain.General;
using StudySharp.Domain.Models;
using StudySharp.Domain.ValidationRules;
using StudySharp.DomainServices;

namespace StudySharp.ApplicationServices.Commands
Expand All @@ -13,6 +15,16 @@ public sealed class RemoveCourseByIdCommand : IRequest<OperationResult>
public int Id { get; set; }
}

public class RemoveCourseByIdCommandValidator : AbstractValidator<RemoveCourseByIdCommand>
{
public RemoveCourseByIdCommandValidator(ICourseRules rules)
{
RuleFor(_ => _.Id)
.MustAsync(rules.IsCourseIdExistAsync)
.WithMessage(_ => string.Format(ErrorConstants.EntityNotFound, nameof(Course), nameof(Course.Id), _.Id));
}
}

public sealed class RemoveCourseByIdCommandHandler : IRequestHandler<RemoveCourseByIdCommand, OperationResult>
{
private readonly StudySharpDbContext _context;
Expand All @@ -24,12 +36,7 @@ public RemoveCourseByIdCommandHandler(StudySharpDbContext sharpDbContext)

public async Task<OperationResult> Handle(RemoveCourseByIdCommand request, CancellationToken cancellationToken)
{
var course = await _context.Courses.FindAsync(request.Id, cancellationToken);
if (course == null)
{
return OperationResult.Fail(string.Format(ErrorConstants.EntityNotFound, nameof(Course), nameof(Course.Name), request.Id));
}

var course = await _context.Courses.FindAsync(request.Id);
_context.Courses.Remove(course);
await _context.SaveChangesAsync(cancellationToken);
return OperationResult.Ok();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
using System.Threading;
using System.Threading.Tasks;
using FluentValidation;
using MediatR;
using Microsoft.EntityFrameworkCore;
using StudySharp.Domain.Constants;
using StudySharp.Domain.General;
using StudySharp.Domain.Models;
using StudySharp.Domain.ValidationRules;
using StudySharp.DomainServices;

namespace StudySharp.ApplicationServices.Commands
Expand All @@ -16,6 +18,28 @@ public class UpdateCourseCommand : IRequest<OperationResult>
public int TeacherId { get; set; }
}

public partial class UpdateCourseCommandValidator : AbstractValidator<UpdateCourseCommand>
{
public UpdateCourseCommandValidator(ICourseRules rules)
{
RuleFor(_ => _.Id)
.MustAsync(rules.IsCourseIdExistAsync)
.WithMessage(_ => string.Format(ErrorConstants.EntityNotFound, nameof(Course), nameof(Course.Id), _.Id));

RuleFor(_ => new { _.Name, _.TeacherId })
.NotEmpty()
.WithMessage(string.Format(ErrorConstants.FieldIsRequired, nameof(Course.Name)))
.MustAsync((courseTeacherAndName, token) => rules.IsNameUniqueAsync(courseTeacherAndName.Name, courseTeacherAndName.TeacherId, token))
.WithMessage(_ => string.Format(ErrorConstants.EntityAlreadyExists, nameof(Course), nameof(Course.Name), _.Name));

RuleFor(_ => _.TeacherId)
.NotEmpty()
.WithMessage(string.Format(ErrorConstants.FieldIsRequired, nameof(Course.TeacherId)))
.MustAsync(rules.IsTeacherIdExistAsync)
.WithMessage(_ => string.Format(ErrorConstants.EntityNotFound, nameof(Teacher), nameof(Teacher.Id), _.TeacherId));
}
}

public sealed class UpdateCourseCommandHandler : IRequestHandler<UpdateCourseCommand, OperationResult>
{
private readonly StudySharpDbContext _context;
Expand All @@ -28,17 +52,6 @@ public UpdateCourseCommandHandler(StudySharpDbContext sharpDbContext)
public async Task<OperationResult> Handle(UpdateCourseCommand request, CancellationToken cancellationToken)
{
var course = await _context.Courses.FirstOrDefaultAsync(_ => _.Id == request.Id, cancellationToken);
if (course == null)
{
return OperationResult.Fail(string.Format(ErrorConstants.EntityNotFound, nameof(Course), nameof(Course.Id), request.Id));
}

var teacherExistent = await _context.Teachers.AnyAsync(_ => _.Id == request.TeacherId, cancellationToken);
if (!teacherExistent)
{
return OperationResult.Fail(string.Format(ErrorConstants.EntityNotFound, nameof(Teacher), nameof(Teacher.Id), request.TeacherId));
}

course.Name = request.Name;
course.TeacherId = request.TeacherId;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
using System.Threading;
using System.Threading.Tasks;
using FluentValidation;
using MediatR;
using StudySharp.Domain.Constants;
using StudySharp.Domain.General;
using StudySharp.Domain.Models;
using StudySharp.Domain.ValidationRules;
using StudySharp.DomainServices;

namespace StudySharp.ApplicationServices.Queries
Expand All @@ -13,6 +15,16 @@ public sealed class GetCourseByIdQuery : IRequest<OperationResult<Course>>
public int Id { get; set; }
}

public partial class GetCourseByIdQueryValidator : AbstractValidator<GetCourseByIdQuery>
{
public GetCourseByIdQueryValidator(ICourseRules rules)
{
RuleFor(_ => _.Id)
.MustAsync(rules.IsCourseIdExistAsync)
.WithMessage(_ => string.Format(ErrorConstants.EntityNotFound, nameof(Course), nameof(Course.Id), _.Id));
}
}

public sealed class GetCourseByIdQueryHandler : IRequestHandler<GetCourseByIdQuery, OperationResult<Course>>
{
private readonly StudySharpDbContext _context;
Expand All @@ -24,12 +36,7 @@ public GetCourseByIdQueryHandler(StudySharpDbContext studySharpDbContext)

public async Task<OperationResult<Course>> Handle(GetCourseByIdQuery request, CancellationToken cancellationToken)
{
var course = await _context.Courses.FindAsync(request.Id, cancellationToken);
if (course == null)
{
return OperationResult.Fail<Course>(string.Format(ErrorConstants.EntityNotFound, nameof(Course), nameof(Course.Id), request.Id));
}

var course = await _context.Courses.FindAsync(request.Id);
return OperationResult.Ok(course);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using FluentValidation;
using MediatR;
using Microsoft.EntityFrameworkCore;
using StudySharp.Domain.Constants;
using StudySharp.Domain.General;
using StudySharp.Domain.Models;
using StudySharp.Domain.ValidationRules;
using StudySharp.DomainServices;

namespace StudySharp.ApplicationServices.Queries
Expand All @@ -16,6 +18,16 @@ public sealed class GetCoursesByTeacherIdQuery : IRequest<OperationResult<List<C
public int TeacherId { get; set; }
}

public partial class GetCoursesByTeacherIdQueryValidator : AbstractValidator<GetCoursesByTeacherIdQuery>
{
public GetCoursesByTeacherIdQueryValidator(ICourseRules rules)
{
RuleFor(_ => _.TeacherId)
.MustAsync(rules.IsTeacherIdExistAsync)
.WithMessage(_ => string.Format(ErrorConstants.EntityNotFound, nameof(Teacher), nameof(Teacher.Id), _.TeacherId));
}
}

public sealed class GetCoursesByTeacherIdQueryHandler : IRequestHandler<GetCoursesByTeacherIdQuery, OperationResult<List<Course>>>
{
private readonly StudySharpDbContext _context;
Expand All @@ -27,12 +39,6 @@ public GetCoursesByTeacherIdQueryHandler(StudySharpDbContext studySharpDbContext

public async Task<OperationResult<List<Course>>> Handle(GetCoursesByTeacherIdQuery request, CancellationToken cancellationToken)
{
var isTeacherExistent = await _context.Teachers.AnyAsync(_ => _.Id == request.TeacherId, cancellationToken);
if (!isTeacherExistent)
{
return OperationResult.Fail<List<Course>>(string.Format(ErrorConstants.EntityNotFound, nameof(Teacher), nameof(Teacher.Id), request.TeacherId));
}

var courses = await _context.Courses.Where(_ => _.TeacherId == request.TeacherId).ToListAsync(cancellationToken);
return OperationResult.Ok(courses);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using StudySharp.Domain.ValidationRules;
using StudySharp.DomainServices;

namespace StudySharp.ApplicationServices.ValidationRules
{
public class CourseRules : ICourseRules
{
private readonly StudySharpDbContext _context;

public CourseRules(StudySharpDbContext context)
{
_context = context;
}

public async Task<bool> IsNameUniqueAsync(string name, int teacherId, CancellationToken cancellationToken)
{
return !await _context.Courses.AnyAsync(_ => _.Name == name && _.TeacherId == teacherId, cancellationToken);
}

public async Task<bool> IsCourseIdExistAsync(int id, CancellationToken cancellationToken)
{
return await _context.Courses.AnyAsync(_ => _.Id == id, cancellationToken);
}

public async Task<bool> IsTeacherIdExistAsync(int teacherId, CancellationToken cancellationToken)
{
return await _context.Teachers.AnyAsync(_ => _.Id == teacherId, cancellationToken);
}
}
}
12 changes: 12 additions & 0 deletions server/StudySharp.Domain/ValidationRules/ICourseRules.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System.Threading;
using System.Threading.Tasks;

namespace StudySharp.Domain.ValidationRules
{
public interface ICourseRules : IValidationRule
{
Task<bool> IsCourseIdExistAsync(int id, CancellationToken cancellationToken);
Task<bool> IsTeacherIdExistAsync(int teacherId, CancellationToken cancellationToken);
Task<bool> IsNameUniqueAsync(string name, int teacherId, CancellationToken cancellationToken);
}
}