Add project files

This commit is contained in:
2025-10-04 13:27:29 +03:00
parent 75eba696c9
commit cc53824229
46 changed files with 3328 additions and 7 deletions

View File

@@ -0,0 +1,68 @@
using Microsoft.EntityFrameworkCore;
using T120B165_ImgBoard.Data;
using T120B165_ImgBoard.Models;
using T120B165_ImgBoard.Utils;
namespace T120B165_ImgBoard.Services;
public interface ICommentService
{
Task<Comment> Create(string text, User author, Post post);
Task<Comment?> GetById(int commentId);
Task<PagedList<Comment>> GetAll(int pageNumber = 1);
Task<bool> Delete(Comment comment);
Task<Comment> Update(Comment comment);
}
public class CommentService(ImgBoardContext context): ICommentService
{
private const int PageSize = 20;
public async Task<Comment> Create(string text, User author, Post post)
{
var entry = new Comment
{
Text = text,
Author = author,
OriginalPost = post,
Created = DateTime.Now,
};
await context.Comments.AddAsync(entry);
await context.SaveChangesAsync();
return entry;
}
public async Task<Comment?> GetById(int commentId)
{
return await context.Comments.Where(t => t.Id == commentId)
.Include(b => b.Author)
.Include(b => b.OriginalPost)
.FirstOrDefaultAsync();
}
public async Task<PagedList<Comment>> GetAll(int pageNumber = 1)
{
var totalCount = await context.Comments.CountAsync();
var items = await context.Comments
.Skip((pageNumber - 1) * PageSize)
.Take(PageSize)
.Include(b => b.Author)
.Include(b => b.OriginalPost)
.ToListAsync();
return new PagedList<Comment>(items, pageNumber, PageSize, totalCount);
}
public async Task<bool> Delete(Comment comment)
{
context.Comments.Remove(comment);
await context.SaveChangesAsync();
return true;
}
public async Task<Comment> Update(Comment comment)
{
context.Comments.Update(comment);
await context.SaveChangesAsync();
return comment;
}
}

View File

@@ -0,0 +1,34 @@
using Microsoft.EntityFrameworkCore;
using T120B165_ImgBoard.Data;
using File = T120B165_ImgBoard.Models.File;
namespace T120B165_ImgBoard.Services;
public interface IFileService
{
public Task<File?> GetFileById(long id);
Task<File> Update(File file);
Task Delete(File file);
}
public class FileService(ImgBoardContext context): IFileService
{
public async Task<File?> GetFileById(long id)
{
return await context.Files.Where(f => f.Id == id).FirstOrDefaultAsync();
}
public async Task<File> Update(File file)
{
context.Files.Update(file);
await context.SaveChangesAsync();
return file;
}
public async Task Delete(File file)
{
var actualFile = await GetFileById(file.Id);
context.Files.Remove(actualFile);
await context.SaveChangesAsync();
}
}

View File

@@ -0,0 +1,100 @@
using Microsoft.EntityFrameworkCore;
using T120B165_ImgBoard.Data;
using T120B165_ImgBoard.Models;
using T120B165_ImgBoard.Utils;
using File = T120B165_ImgBoard.Models.File;
namespace T120B165_ImgBoard.Services;
public interface IPostService
{
Task<CreatedPost> Create(
string title, string description, List<Tag> tags, User author,
string fileName, string fileContentType, long fileSize);
Task<Post?> GetById(int postId, bool includeUnfinished = false);
Task<PagedList<Post>> GetAll(int pageNumber = 1);
Task<bool> Delete(Post post);
Task<Post> Update(Post post);
}
public record CreatedPost(Post Post, File File);
public class PostService(ImgBoardContext context): IPostService
{
private const int PageSize = 20;
public async Task<CreatedPost> Create(
string title,
string description,
List<Tag> tags,
User author,
string fileName,
string fileContentType,
long fileSize
)
{
var file = new File
{
OriginalFileName = fileName,
Size = fileSize,
ContentType = fileContentType,
FilePath = Path.GetTempFileName(),
CreatedDate = DateTime.Now,
};
await context.Files.AddAsync(file);
var entry = new Post
{
Title = title,
Description = description,
Author = author,
Created = DateTime.Now,
Tags = tags,
File = file
};
await context.Posts.AddAsync(entry);
await context.SaveChangesAsync();
return new CreatedPost(entry, file);
}
public async Task<Post?> GetById(int postId, bool includeUnfinished = false)
{
var query = context.Posts.Where(t => t.Id == postId);
if (!includeUnfinished)
{
query = query.Where(t => t.File.FinishedDate != null);
}
return await query.Include(b => b.Author)
.Include(b => b.Tags)
.Include(b => b.File)
.FirstOrDefaultAsync();
}
public async Task<PagedList<Post>> GetAll(int pageNumber = 1)
{
var totalCount = await context.Posts.Where(p => p.File.FinishedDate != null).CountAsync();
var items = await context.Posts
.Skip((pageNumber - 1) * PageSize)
.Take(PageSize)
.Where(p => p.File.FinishedDate != null)
.Include(b => b.Author)
.Include(b => b.Tags)
.Include(b => b.File)
.ToListAsync();
return new PagedList<Post>(items, pageNumber, PageSize, totalCount);
}
public async Task<bool> Delete(Post post)
{
context.Posts.Remove(post);
await context.SaveChangesAsync();
return true;
}
public async Task<Post> Update(Post post)
{
context.Posts.Update(post);
await context.SaveChangesAsync();
return post;
}
}

View File

@@ -0,0 +1,68 @@
using Microsoft.EntityFrameworkCore;
using T120B165_ImgBoard.Data;
using T120B165_ImgBoard.Dtos;
using T120B165_ImgBoard.Models;
using T120B165_ImgBoard.Utils;
namespace T120B165_ImgBoard.Services;
public interface ITagService
{
Task<Tag?> GetByName(string name);
Task<bool> DeleteByName(string name);
Task<PagedList<Tag>> GetAll(int pageNumber = 1);
Task<Tag> Update(Tag tag, TagType type);
Task<Tag> Create(TagType type, string name);
}
public class TagService(ImgBoardContext context): ITagService
{
public async Task<Tag?> GetByName(string name)
{
return await context.Tags.Where(t => t.Name == name).FirstOrDefaultAsync();
}
public async Task<PagedList<Tag>> GetAll(int pageNumber)
{
int pageSize = 20;
var totalCount = await context.Tags.CountAsync();
var products = await context.Tags
.Skip((pageNumber - 1) * pageSize)
.Take(pageSize)
.ToListAsync();
return new PagedList<Tag>(products, pageNumber, pageSize, totalCount);;
}
public async Task<Tag> Update(Tag tag, TagType type)
{
tag.Type = type;
context.Tags.Update(tag);
await context.SaveChangesAsync();
return tag;
}
public async Task<bool> DeleteByName(string name)
{
var tag = await context.Tags.FindAsync(name);
if (tag == null) return false;
context.Tags.Remove(tag);
await context.SaveChangesAsync();
return true;
}
public async Task<Tag> Create(TagType type, string name)
{
var tag = new Tag
{
Name = name,
Type = type,
};
await context.Tags.AddAsync(tag);
await context.SaveChangesAsync();
return tag;
}
}

View File

@@ -0,0 +1,74 @@
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using T120B165_ImgBoard.Data;
using T120B165_ImgBoard.Models;
namespace T120B165_ImgBoard.Services;
public interface ITokenService
{
Task<string> GenerateJwtToken(User user);
Task<string> GenerateRefreshToken(User user);
Task<RefreshToken?> GetRefreshTokenByValue(string refreshToken);
Task<bool> InvalidateRefreshToken(RefreshToken refreshToken);
}
public class TokenService(ImgBoardContext context, IConfiguration config, UserManager<User> userManager): ITokenService
{
public async Task<RefreshToken?> GetRefreshTokenByValue(string refreshToken)
{
return await context.RefreshTokens.Where(t => t.Token == refreshToken && t.Expires > DateTime.Now)
.Include(t => t.User)
.FirstOrDefaultAsync();
}
public async Task<bool> InvalidateRefreshToken(RefreshToken refreshToken)
{
context.RefreshTokens.Remove(refreshToken);
await context.SaveChangesAsync();
return true;
}
public async Task<string> GenerateJwtToken(User user)
{
var roles = await userManager.GetRolesAsync(user);
var claims = new List<Claim>
{
new(JwtRegisteredClaimNames.Sub, user.Id),
new(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new(JwtRegisteredClaimNames.Email, user.Email)
};
claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role)));
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config["Jwt:Key"]));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: config["Jwt:Issuer"],
audience: config["Jwt:Audience"],
claims: claims,
expires: DateTime.Now.AddMinutes(Convert.ToDouble(config["Jwt:DurationInMinutes"])),
signingCredentials: creds);
return new JwtSecurityTokenHandler().WriteToken(token);
}
public async Task<string> GenerateRefreshToken(User user)
{
var token = new RefreshToken
{
Expires = DateTime.Now.AddDays(30),
Token = Guid.NewGuid().ToString(),
User = user
};
await context.RefreshTokens.AddAsync(token);
await context.SaveChangesAsync();
return token.Token;
}
}

View File

@@ -0,0 +1,18 @@
using Microsoft.EntityFrameworkCore;
using T120B165_ImgBoard.Data;
using T120B165_ImgBoard.Models;
namespace T120B165_ImgBoard.Services;
public interface IUserService
{
public Task<User?> GetUserById(string id);
}
public class UserService(ImgBoardContext context): IUserService
{
public async Task<User?> GetUserById(string id)
{
return await context.Users.Where(u => u.Id == id).FirstOrDefaultAsync();
}
}