Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,40 +1,40 @@
ο»Ώusing System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Blog.Core.Entities;
using Blog.Core.Helpers;
using Microsoft.IdentityModel.Tokens;
namespace Blog.Core.Services;
public class JwtService
{
public string GenerateJwtToken(User user)
{
var claims = new[]
{
new Claim("guid", user.Id.ToString()),
new Claim(JwtRegisteredClaimNames.Email, user.Email),
new Claim("name", user.Name),
};
var jwtKey = EnvironmentHelper.GetEnvironmentVariableOrFile("JWT_KEY");
if (jwtKey == null)
{
throw new InvalidOperationException("JWT_KEY environment variable is not set.");
}
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtKey));
var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: EnvironmentHelper.GetEnvironmentVariableOrFile("JWT_ISSUER"),
audience: EnvironmentHelper.GetEnvironmentVariableOrFile("JWT_AUDIENCE"),
claims: claims,
expires: DateTime.UtcNow.AddHours(2),
signingCredentials: credentials
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
}
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Blog.Core.Domain.Entities;
using Blog.Core.Helpers;
using Microsoft.IdentityModel.Tokens;

namespace Blog.Core.Application.Services;

public class JwtService
{
public string GenerateJwtToken(User user)
{
var claims = new[]
{
new Claim("guid", user.Id.ToString()),
new Claim(JwtRegisteredClaimNames.Email, user.Email.Value),
new Claim("name", user.Name),
};
var jwtKey = EnvironmentHelper.GetEnvironmentVariableOrFile("JWT_KEY");

if (jwtKey == null)
{
throw new InvalidOperationException("JWT_KEY environment variable is not set.");
}

var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtKey));
var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

var token = new JwtSecurityToken(
issuer: EnvironmentHelper.GetEnvironmentVariableOrFile("JWT_ISSUER"),
audience: EnvironmentHelper.GetEnvironmentVariableOrFile("JWT_AUDIENCE"),
claims: claims,
expires: DateTime.UtcNow.AddHours(2),
signingCredentials: credentials
);

return new JwtSecurityTokenHandler().WriteToken(token);
}
}
Original file line number Diff line number Diff line change
@@ -1,78 +1,78 @@
ο»Ώusing Blog.Core.Entities;
using Blog.Core.UseCases;
namespace Blog.Core.Services;
public abstract record RegisterResult
{
public record Success(User User) : RegisterResult;
public record UserAlreadyExists(string Message) : RegisterResult;
public record UserRepositoryError(string Message) : RegisterResult;
}
public abstract record LoginResult
{
public record Success(string Token, User User) : LoginResult;
public record WrongPassword(string Message) : LoginResult;
public record UserNotFound(string Message) : LoginResult;
}
public class UserService
{
private readonly IUserRepository _userRepository;
private readonly JwtService _jwtService;
public UserService(IUserRepository userRepository, JwtService jwtService)
{
_userRepository = userRepository;
_jwtService = jwtService;
}
public async Task<RegisterResult> Register(string name, string email, string password)
{
var existingUser = await _userRepository.FindByEmailAsync(email);
if (existingUser != null)
{
return new RegisterResult.UserAlreadyExists("User already exists with this email.");
}
var user = new User
{
Id = Guid.NewGuid(),
Email = email,
Name = name,
PasswordHash = BCrypt.Net.BCrypt.HashPassword(password),
};
var addedUser = await _userRepository.AddAsync(user);
if (addedUser == null)
{
return new RegisterResult.UserRepositoryError("Failed to add user to the repository.");
}
return new RegisterResult.Success(addedUser);
}
public async Task<LoginResult> Login(string email, string password)
{
var user = await _userRepository.FindByEmailAsync(email);
if (user == null)
{
return new LoginResult.UserNotFound($"User not found: {user}");
}
if (!BCrypt.Net.BCrypt.Verify(password, user.PasswordHash))
{
return new LoginResult.WrongPassword("Wrong password");
}
var token = _jwtService.GenerateJwtToken(user);
return new LoginResult.Success(token, user);
}
}
using Blog.Core.Domain.Entities;
using Blog.Core.Domain.Repositories;

namespace Blog.Core.Application.Services;

public abstract record RegisterResult
{
public record Success(User User) : RegisterResult;
public record UserAlreadyExists(string Message) : RegisterResult;
public record UserRepositoryError(string Message) : RegisterResult;
}

public abstract record LoginResult
{
public record Success(string Token, User User) : LoginResult;
public record WrongPassword(string Message) : LoginResult;
public record UserNotFound(string Message) : LoginResult;
}

public class UserService
{
private readonly IUserRepository _userRepository;
private readonly JwtService _jwtService;

public UserService(IUserRepository userRepository, JwtService jwtService)
{
_userRepository = userRepository;
_jwtService = jwtService;
}

public async Task<RegisterResult> Register(string name, string email, string password)
{
var existingUser = await _userRepository.FindByEmailAsync(email);

if (existingUser != null)
{
return new RegisterResult.UserAlreadyExists("User already exists with this email.");
}

User user;
try
{
user = User.Create(name, email, password);
}
catch (ArgumentException ex)
{
return new RegisterResult.UserRepositoryError(ex.Message);
}

var addedUser = await _userRepository.AddAsync(user);

if (addedUser == null)
{
return new RegisterResult.UserRepositoryError("Failed to add user to the repository.");
}

return new RegisterResult.Success(addedUser);
}

public async Task<LoginResult> Login(string email, string password)
{
var user = await _userRepository.FindByEmailAsync(email);

if (user == null)
{
return new LoginResult.UserNotFound($"User not found: {email}");
}

if (!user.VerifyPassword(password))
{
return new LoginResult.WrongPassword("Wrong password");
}

var token = _jwtService.GenerateJwtToken(user);

return new LoginResult.Success(token, user);
}
}
76 changes: 76 additions & 0 deletions Backend/Blog.Core/Domain/Entities/Post.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
namespace Blog.Core.Domain.Entities;

public class Post
{
public Guid Id { get; private set; }
public string Name { get; private set; }
public string Description { get; private set; }
public string MarkdownContent { get; private set; }
public DateTime Created { get; private set; }
public Guid AuthorId { get; private set; }
public User? Author { get; private set; }

// EF Core constructor
private Post()
{
Name = null!;
Description = null!;
MarkdownContent = null!;
}

private Post(Guid id, string name, string description, string markdownContent, Guid authorId, DateTime created)
{
Id = id;
Name = name;
Description = description;
MarkdownContent = markdownContent;
AuthorId = authorId;
Created = created;
}

public static Post Create(string name, string description, string markdownContent, Guid authorId)
{
if (string.IsNullOrWhiteSpace(name))
throw new ArgumentException("Name cannot be empty", nameof(name));

if (string.IsNullOrWhiteSpace(description))
throw new ArgumentException("Description cannot be empty", nameof(description));

if (string.IsNullOrWhiteSpace(markdownContent))
throw new ArgumentException("Markdown content cannot be empty", nameof(markdownContent));

if (authorId == Guid.Empty)
throw new ArgumentException("Author ID cannot be empty", nameof(authorId));

return new Post(Guid.NewGuid(), name, description, markdownContent, authorId, DateTime.UtcNow);
}

public static Post Restore(Guid id, string name, string description, string markdownContent, Guid authorId, DateTime created)
{
return new Post(id, name, description, markdownContent, authorId, created);
}

public void Update(string? name, string? description, string? markdownContent)
{
if (name != null)
{
if (string.IsNullOrWhiteSpace(name))
throw new ArgumentException("Name cannot be empty", nameof(name));
Name = name;
}

if (description != null)
{
if (string.IsNullOrWhiteSpace(description))
throw new ArgumentException("Description cannot be empty", nameof(description));
Description = description;
}

if (markdownContent != null)
{
if (string.IsNullOrWhiteSpace(markdownContent))
throw new ArgumentException("Markdown content cannot be empty", nameof(markdownContent));
MarkdownContent = markdownContent;
}
}
}
76 changes: 76 additions & 0 deletions Backend/Blog.Core/Domain/Entities/User.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
using Blog.Core.Domain.ValueObjects;

namespace Blog.Core.Domain.Entities;

public class User
{
public Guid Id { get; private set; }
public Email Email { get; private set; }
public string Name { get; private set; }
public HashedPassword PasswordHash { get; private set; }
public ICollection<string> Permissions { get; private set; }

// EF Core constructor
private User()
{
Email = null!;
Name = null!;
PasswordHash = null!;
Permissions = new List<string>();
}

private User(Guid id, Email email, string name, HashedPassword passwordHash)
{
Id = id;
Email = email;
Name = name;
PasswordHash = passwordHash;
Permissions = new List<string>();
}

public static User Create(string name, string email, string password)
{
if (string.IsNullOrWhiteSpace(name))
throw new ArgumentException("Name cannot be empty", nameof(name));

var userEmail = Email.Create(email);
var hashedPassword = HashedPassword.Create(password);

return new User(Guid.NewGuid(), userEmail, name, hashedPassword);
}

public static User Restore(Guid id, Email email, string name, HashedPassword passwordHash, ICollection<string> permissions)
{
var user = new User(id, email, name, passwordHash)
{
Permissions = permissions
};
return user;
}

public bool VerifyPassword(string password)
{
return PasswordHash.Verify(password);
}

public void AddPermission(string permission)
{
if (string.IsNullOrWhiteSpace(permission))
throw new ArgumentException("Permission cannot be empty", nameof(permission));

if (!Permissions.Contains(permission))
{
Permissions.Add(permission);
}
}

public void RemovePermission(string permission)
{
Permissions.Remove(permission);
}

public bool HasPermission(string permission)
{
return Permissions.Contains(permission);
}
}
Loading