< Summary

Information
Class: Backend.Model.UserSerivce
Assembly: Backend
File(s): D:\a\smart-meal-planner\smart-meal-planner\backend\Backend\Services\Impl\UserService.cs
Line coverage
98%
Covered lines: 61
Uncovered lines: 1
Coverable lines: 62
Total lines: 134
Line coverage: 98.3%
Branch coverage
100%
Covered branches: 22
Total branches: 22
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
.ctor(...)100%1100%
CreateUserAsync()100%2100%
GetByEmailAsync()100%4100%
GetByIdAsync()100%4100%
VerifyPasswordHash(...)100%4100%
ChangePasswordAsync()100%6100%
UpdatePasswordAsync()100%2100%
UpdateUserDtoAsync(...)100%10%

File(s)

D:\a\smart-meal-planner\smart-meal-planner\backend\Backend\Services\Impl\UserService.cs

#LineLine coverage
 1using Microsoft.EntityFrameworkCore;
 2using Backend.DTOs;
 3using Backend.Services;
 4
 5namespace Backend.Model
 6{
 7    public class UserSerivce: IUserService
 8    {
 9        private readonly PlannerContext _context;
 10        private readonly ILogger<UserSerivce> _logger;
 11
 1612        public UserSerivce(PlannerContext context, ILogger<UserSerivce> logger)
 13        {
 1614            _context = context;
 1615            _logger = logger;
 1616        }
 17
 18        public async Task<User> CreateUserAsync(string email, string password)
 19        {
 20            // Check if user already exists
 821            if (await GetByEmailAsync(email) != null)
 22            {
 123                _logger.LogInformation("Attempt to create a user that already exists: {Email}", email);
 124                throw new InvalidOperationException("User already exists.");
 25            }
 26
 27            // Hash password
 728            string hashedPassword = BCrypt.Net.BCrypt.HashPassword(password);
 729            _logger.LogDebug("Password hashed for user: {Email}; hash: {hash}", email, hashedPassword);
 30
 731            var user = new User
 732            {
 733                Email = email,
 734                PasswordHash = hashedPassword
 735            };
 36
 737            _context.Users.Add(user);
 738            await _context.SaveChangesAsync();
 39
 740            _logger.LogInformation("User created successfully: {user}", user);
 41
 742            return user;
 743        }
 44
 45        public async Task<User> GetByEmailAsync(string email)
 46        {
 1047            var user = await _context.Users.FirstOrDefaultAsync(u => u.Email == email) ?? null!;
 1048            if (user == null)
 49            {
 850                _logger.LogInformation("User not found with email: {Email}", email);
 851                return null!;
 52            }
 53
 254            return user;
 1055        }
 56
 57        public async Task<User> GetByIdAsync(int id)
 58        {
 959            var user = await _context.Users.FirstOrDefaultAsync(u => u.Id == id) ?? null!;
 960            if (user == null)
 61            {
 362                _logger.LogInformation("User not found with ID: {Id}", id);
 363                return null!;
 64            }
 65
 666            return user;
 967        }
 68
 69        public bool VerifyPasswordHash(string password, User user)
 70        {
 71            // Verify the password against the stored hash
 1172            if (user == null || string.IsNullOrEmpty(user.PasswordHash))
 73            {
 374                _logger.LogWarning("User or password hash is null or empty.");
 375                return false;
 76            }
 77
 878            return BCrypt.Net.BCrypt.Verify(password, user.PasswordHash);
 79        }
 80
 81        public async Task ChangePasswordAsync(string userId, string oldPassword, string newPassword)
 82        {
 583            if (!int.TryParse(userId, out int id))
 84            {
 285                _logger.LogWarning("Invalid user ID format: {UserId}", userId);
 286                throw new ArgumentException("Invalid user ID format.");
 87            }
 88
 389            var user = await GetByIdAsync(id);
 390            if (user == null)
 91            {
 192                _logger.LogWarning("User not found with ID: {UserId}", userId);
 193                throw new InvalidOperationException("User not found.");
 94            }
 95
 296            if (!VerifyPasswordHash(oldPassword, user))
 97            {
 198                _logger.LogWarning("Old password does not match for user ID: {UserId}", userId);
 199                throw new UnauthorizedAccessException("Old password is incorrect.");
 100            }
 101
 102            // Hash the new password
 1103            string newHashedPassword = BCrypt.Net.BCrypt.HashPassword(newPassword);
 1104            user.PasswordHash = newHashedPassword;
 105
 1106            _context.Users.Update(user);
 1107            await _context.SaveChangesAsync();
 108
 1109            _logger.LogInformation("Password changed successfully for user ID: {UserId}", userId);
 1110        }
 111
 112        public async Task<bool> UpdatePasswordAsync(int userId, string newPassword)
 113        {
 2114            var user = await GetByIdAsync(userId);
 2115            if (user == null)
 116            {
 1117                _logger.LogWarning("User not found with ID: {UserId}", userId);
 1118                return false;
 119            }
 120
 1121            user.PasswordHash = BCrypt.Net.BCrypt.HashPassword(newPassword);
 1122            _context.Users.Update(user);
 1123            await _context.SaveChangesAsync();
 124
 1125            _logger.LogInformation("Password updated successfully for user ID: {UserId}", userId);
 1126            return true;
 2127        }
 128
 129        public Task<UserDto> UpdateUserDtoAsync(UserDto userDto)
 130        {
 0131            throw new NotImplementedException();
 132        }
 133    }
 134}