Skip to content

Commit 776c77a

Browse files
authored
Merge pull request #4 from yazilimacademy/Application
[Feature]: Category/GetAll and Create operations completed.
2 parents 5731171 + b172f6d commit 776c77a

23 files changed

+334
-8
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
1+
using Microsoft.EntityFrameworkCore;
2+
using YazilimAcademy.Domain.Entities;
3+
14
namespace YazilimAcademy.Application.Common.Interfaces;
25

36
public interface IApplicationDbContext
47
{
8+
DbSet<Category> Categories { get; }
9+
DbSet<Course> Courses { get; }
10+
DbSet<CourseCategory> CourseCategories { get; }
11+
DbSet<CourseSection> CourseSections { get; }
12+
DbSet<CourseLecture> CourseLectures { get; }
13+
DbSet<CourseLectureResource> CourseLectureResources { get; }
514

15+
Task<int> SaveChangesAsync(CancellationToken cancellationToken);
16+
int SaveChanges();
617
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
using System.Data;
2+
3+
namespace YazilimAcademy.Application.Common.Interfaces;
4+
5+
public interface ISqlConnectionFactory
6+
{
7+
IDbConnection CreateConnection();
8+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
namespace YazilimAcademy.Application.Common.Models.Errors;
2+
3+
public sealed record ValidationError
4+
{
5+
public string PropertyName { get; init; }
6+
public IEnumerable<string> ErrorMessages { get; init; }
7+
8+
public ValidationError(string propertyName, IEnumerable<string> errorMessages)
9+
{
10+
PropertyName = propertyName;
11+
ErrorMessages = errorMessages;
12+
}
13+
14+
public ValidationError(string propertyName, string errorMessage)
15+
: this(propertyName, new List<string> { errorMessage })
16+
{
17+
}
18+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
using System.Text.Json.Serialization;
2+
using Microsoft.EntityFrameworkCore;
3+
4+
namespace YazilimAcademy.Application.Common.Models.Pagination;
5+
6+
public sealed record PaginatedList<T>
7+
{
8+
public IReadOnlyCollection<T> Items { get; }
9+
public int PageNumber { get; }
10+
public int TotalPages { get; }
11+
public int TotalCount { get; }
12+
public int PageSize { get; set; }
13+
14+
public PaginatedList(IEnumerable<T> items, int totalCount, int pageNumber, int pageSize)
15+
{
16+
Items = items.ToList().AsReadOnly();
17+
18+
TotalCount = totalCount;
19+
20+
PageNumber = pageNumber;
21+
22+
PageSize = pageSize;
23+
24+
TotalPages = (int)Math.Ceiling(totalCount / (double)pageSize);
25+
}
26+
27+
[JsonConstructor]
28+
public PaginatedList(IReadOnlyCollection<T> items, int totalCount, int pageNumber, int pageSize)
29+
{
30+
PageNumber = pageNumber;
31+
TotalPages = (int)Math.Ceiling(totalCount / (double)pageSize);
32+
TotalCount = totalCount;
33+
Items = items;
34+
PageSize = pageSize;
35+
}
36+
37+
public bool HasPreviousPage => PageNumber > 1;
38+
39+
public bool HasNextPage => PageNumber < TotalPages;
40+
41+
public static async Task<PaginatedList<T>> CreateAsync(IQueryable<T> source, int pageNumber, int pageSize)
42+
{
43+
var count = await source.CountAsync();
44+
45+
var items = await source
46+
.Skip((pageNumber - 1) * pageSize)
47+
.Take(pageSize)
48+
.ToListAsync();
49+
50+
return new PaginatedList<T>(items, count, pageNumber, pageSize);
51+
}
52+
53+
public static PaginatedList<T> Create(IEnumerable<T> source, int pageNumber, int pageSize)
54+
{
55+
var count = source.Count();
56+
57+
var items = source.Skip((pageNumber - 1) * pageSize).Take(pageSize).ToList();
58+
59+
return new PaginatedList<T>(items, count, pageNumber, pageSize);
60+
}
61+
62+
public static PaginatedList<T> Create(List<T> source, int totalCount, int pageNumber, int pageSize)
63+
{
64+
return new PaginatedList<T>(source, totalCount, pageNumber, pageSize);
65+
}
66+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using YazilimAcademy.Application.Common.Models.Errors;
2+
3+
namespace YazilimAcademy.Application.Common.Models.Responses;
4+
5+
public sealed record ResponseDto<T>
6+
{
7+
public T? Data { get; init; }
8+
public string? Message { get; init; }
9+
public bool IsSuccess { get; init; }
10+
public IReadOnlyList<ValidationError> ValidationErrors { get; init; }
11+
12+
public ResponseDto(T? data, string? message, bool isSuccess, IReadOnlyList<ValidationError>? validationErrors = null)
13+
{
14+
Data = data;
15+
Message = message;
16+
IsSuccess = isSuccess;
17+
ValidationErrors = validationErrors ?? Array.Empty<ValidationError>();
18+
}
19+
20+
public static ResponseDto<T> Success(T data, string message)
21+
=> new(data, message, true);
22+
23+
public static ResponseDto<T?> Success(string message)
24+
=> new(default, message, true);
25+
26+
public static ResponseDto<T> Error(string message, List<ValidationError>? validationErrors = null)
27+
=> new(default, message, false, validationErrors);
28+
29+
public static ResponseDto<T> Error(string message, ValidationError validationError)
30+
=> new(default, message, false, new[] { validationError });
31+
}
32+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
using MediatR;
2+
3+
namespace YazilimAcademy.Application.Features.Categories.Commands.Create;
4+
5+
public sealed record CreateCategoryCommand(string Name, string Description) : IRequest<Guid>;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System;
2+
using MediatR;
3+
using YazilimAcademy.Application.Common.Interfaces;
4+
using YazilimAcademy.Domain.Entities;
5+
6+
namespace YazilimAcademy.Application.Features.Categories.Commands.Create;
7+
8+
public sealed class CreateCategoryCommandHandler : IRequestHandler<CreateCategoryCommand, Guid>
9+
{
10+
private readonly IApplicationDbContext _dbContext;
11+
12+
public CreateCategoryCommandHandler(IApplicationDbContext dbContext)
13+
{
14+
_dbContext = dbContext;
15+
}
16+
17+
public async Task<Guid> Handle(CreateCategoryCommand request, CancellationToken cancellationToken)
18+
{
19+
var category = Category.Create(request.Name, request.Description);
20+
21+
_dbContext.Categories.Add(category);
22+
23+
await _dbContext.SaveChangesAsync(cancellationToken);
24+
25+
return category.Id;
26+
}
27+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
using System;
2+
using FluentValidation;
3+
using Microsoft.EntityFrameworkCore;
4+
using YazilimAcademy.Application.Common.Interfaces;
5+
namespace YazilimAcademy.Application.Features.Categories.Commands.Create;
6+
7+
public sealed class CreateCategoryCommandValidator : AbstractValidator<CreateCategoryCommand>
8+
{
9+
private readonly IApplicationDbContext _dbContext;
10+
11+
public CreateCategoryCommandValidator(IApplicationDbContext dbContext)
12+
{
13+
_dbContext = dbContext;
14+
15+
RuleFor(c => c.Name)
16+
.NotEmpty()
17+
.WithMessage("Kategori adı boş olamaz.")
18+
.MaximumLength(100)
19+
.WithMessage("Kategori adı en fazla 100 karakter olmalıdır.")
20+
.MinimumLength(3)
21+
.WithMessage("Kategori adı en az 3 karakter olmalıdır.");
22+
23+
RuleFor(c => c.Description)
24+
.NotEmpty()
25+
.When(c => !string.IsNullOrWhiteSpace(c.Description))
26+
.WithMessage("Kategori açıklaması boş olamaz.")
27+
.MaximumLength(1000)
28+
.WithMessage("Kategori açıklaması en fazla 1000 karakter olmalıdır.")
29+
.MinimumLength(10)
30+
.WithMessage("Kategori açıklaması en az 10 karakter olmalıdır.");
31+
32+
RuleFor(c => c.Name)
33+
.MustAsync(IsCategoryNameUniqueAsync)
34+
.WithMessage("Bu kategori adı zaten mevcuttur.");
35+
}
36+
37+
private async Task<bool> IsCategoryNameUniqueAsync(string name, CancellationToken cancellationToken)
38+
{
39+
return !await _dbContext
40+
.Categories
41+
.AnyAsync(c => c.Name.ToLower() == name.ToLower(), cancellationToken);
42+
}
43+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
namespace YazilimAcademy.Application.Features.Categories.Queries.GetAll;
2+
3+
public sealed record GetAllCategoriesDto
4+
{
5+
public Guid Id { get; set; }
6+
public string Name { get; set; }
7+
8+
public GetAllCategoriesDto(Guid id, string name)
9+
{
10+
Id = id;
11+
Name = name;
12+
}
13+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
using MediatR;
2+
using YazilimAcademy.Application.Common.Models.Pagination;
3+
4+
namespace YazilimAcademy.Application.Features.Categories.Queries.GetAll;
5+
6+
public sealed record GetAllCategoriesQuery(int PageNumber, int PageSize) : IRequest<PaginatedList<GetAllCategoriesDto>>;

0 commit comments

Comments
 (0)