Skip to content

Commit

Permalink
Squashed commit of the following:
Browse files Browse the repository at this point in the history
commit 3ac8542
Merge: 9f8efe2 c371eb9
Author: DustSwiffer
Date:   Tue Jul 23 21:05:20 2024 +0200

    Merge branch 'feature/user-related-endpoints' into develop

commit c371eb9
Author: DustSwiffer
Date:   Tue Jul 23 21:04:28 2024 +0200

    Small fix within the UserService and UpdateLastSeen unit tests added

commit fb4ad70
Author: DustSwiffer
Date:   Tue Jul 23 20:54:21 2024 +0200

    Unit tests added for GetUserProfile

commit 5127a94
Author: DustSwiffer
Date:   Tue Jul 23 00:43:09 2024 +0200

    User last seen is being created or updated & shown in the user profile

commit 704738f
Author: DustSwiffer
Date:   Mon Jul 22 22:41:02 2024 +0200

    user profile  added
  • Loading branch information
DustSwiffer committed Jul 23, 2024
1 parent 9f8efe2 commit 04e10b9
Show file tree
Hide file tree
Showing 41 changed files with 1,706 additions and 258 deletions.
3 changes: 3 additions & 0 deletions AdvancedAPI.Business/MappingProfile.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using AdvancedAPI.Data.Models;
using AdvancedAPI.Data.ViewModels.NewsArticle;
using AdvancedAPI.Data.ViewModels.User;
using AutoMapper;

namespace Business;
Expand All @@ -15,5 +16,7 @@ public class MappingProfile : Profile
public MappingProfile()
{
CreateMap<NewsArticleRequestModel, NewsArticle>();
CreateMap<User, UserProfileResponseModel>(MemberList.None)
.ForMember(d => d.Gender, opt => opt.MapFrom(s => s.Gender.Name));
}
}
1 change: 1 addition & 0 deletions AdvancedAPI.Business/ServiceExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public static IServiceCollection AddBusinessServices(this IServiceCollection ser

services.AddScoped<IAuthenticationService, AuthenticationService>();
services.AddScoped<INewsArticleService, NewsArticleService>();
services.AddScoped<IUserService, UserService>();

return services;
}
Expand Down
6 changes: 3 additions & 3 deletions AdvancedAPI.Business/Services/AuthenticationService.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using AdvancedAPI.Data.Models;
using AdvancedAPI.Data.Repositories.Interfaces;
using AdvancedAPI.Data.ViewModels.Authentication;
using Business.Services.Interfaces;
using Microsoft.AspNetCore.Identity;
using Microsoft.IdentityModel.Tokens;

namespace Business.Services;
Expand All @@ -27,12 +27,12 @@ public AuthenticationService(IIdentityRepository identityRepository, IConfigurat
/// <inheritdoc />
public async Task<JwtSecurityToken?> Login(LoginRequestModel requestModel, CancellationToken ct = default)
{
IdentityUser? user = await _identityRepository.GetUser(requestModel.Username);
User? user = await _identityRepository.GetUserByName(requestModel.Username);
if (user != null && await _identityRepository.CheckPassword(user, requestModel.Password))
{
List<Claim> authClaims = new()
{
new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
new Claim(JwtRegisteredClaimNames.Sub, user.Id),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
};

Expand Down
33 changes: 0 additions & 33 deletions AdvancedAPI.Business/Services/HouseService.cs

This file was deleted.

14 changes: 0 additions & 14 deletions AdvancedAPI.Business/Services/Interfaces/IHouseService.cs

This file was deleted.

19 changes: 19 additions & 0 deletions AdvancedAPI.Business/Services/Interfaces/IUserService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using AdvancedAPI.Data.ViewModels.User;

namespace Business.Services.Interfaces;

/// <summary>
/// User service.
/// </summary>
public interface IUserService
{
/// <summary>
/// Gets the user profile of the given user id.
/// </summary>
public Task<UserProfileResponseModel?> GetUserProfile(string userId);

/// <summary>
/// Updates the last seen state of the user.
/// </summary>
public Task UpdateLastSeen(string userId);
}
2 changes: 1 addition & 1 deletion AdvancedAPI.Business/Services/NewsArticleService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public NewsArticleService(ILogger<NewsArticleService> logger, IMapper mapper, IN
/// <inheritdoc />
public async Task<bool> CreateNewsArticle(NewsArticleRequestModel requestModel)
{
var mapped = _mapper.Map<NewsArticle>(requestModel);
NewsArticle? mapped = _mapper.Map<NewsArticle>(requestModel);
mapped.ReleaseDate = DateTime.Now;

try
Expand Down
76 changes: 76 additions & 0 deletions AdvancedAPI.Business/Services/UserService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
using System.Globalization;
using AdvancedAPI.Data.Models;
using AdvancedAPI.Data.Repositories.Interfaces;
using AdvancedAPI.Data.ViewModels.User;
using AutoMapper;
using Business.Services.Interfaces;

namespace Business.Services;

/// <inheritdoc />
public class UserService : IUserService
{
private readonly IIdentityRepository _identityRepository;
private readonly IGenderRepository _genderRepository;
private readonly ILastSeenRepository _lastSeenRepository;
private readonly IMapper _mapper;

/// <summary>
/// Constructor.
/// </summary>
public UserService(
IMapper mapper,
IIdentityRepository identityRepository,
IGenderRepository genderRepository,
ILastSeenRepository lastSeenRepository)
{
_identityRepository = identityRepository;
_genderRepository = genderRepository;
_lastSeenRepository = lastSeenRepository;
_mapper = mapper;
}

/// <inheritdoc />
public async Task<UserProfileResponseModel?> GetUserProfile(string userId)
{
User? user = await _identityRepository.GetUserById(userId);

if (user == null)
{
return null;
}

user.Gender = await _genderRepository.GetByIdAsync(user.GenderId);

UserProfileResponseModel responseModel = _mapper.Map<UserProfileResponseModel>(user);

responseModel.Birthday = user.DateOfBirth.ToString("MMMM d");
LastSeen? lastSeen = await _lastSeenRepository.GetByUserId(user.Id);

responseModel.LastSeen = lastSeen != null ? lastSeen.DateTime.ToString(CultureInfo.InvariantCulture) : "unknown";
return responseModel;
}

/// <inheritdoc />
public async Task UpdateLastSeen(string userId)
{
LastSeen? lastSeen = await _lastSeenRepository.GetByUserId(userId);

if (lastSeen != null)
{
lastSeen.DateTime = DateTime.Now;
_lastSeenRepository.Update(lastSeen);
}
else
{
await _lastSeenRepository.AddAsync(
new LastSeen()
{
UserId = userId,
DateTime = DateTime.Now,
});
}

await _lastSeenRepository.SaveAsync();
}
}
31 changes: 27 additions & 4 deletions AdvancedAPI.Data/AdvancedApiContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace AdvancedAPI.Data;
/// <summary>
/// Database context.
/// </summary>
public class AdvancedApiContext : IdentityDbContext<IdentityUser>
public class AdvancedApiContext : IdentityDbContext<User>
{
/// <summary>
/// Constructor.
Expand All @@ -22,20 +22,43 @@ public AdvancedApiContext(DbContextOptions<AdvancedApiContext> options)
/// News article database objects.
/// </summary>
public DbSet<NewsArticle> NewsArticles { get; set; }


/// <summary>
/// Gender database objects.
/// </summary>
public DbSet<Gender> Genders { get; set; }

/// <summary>
/// LastSeen database objects.
/// </summary>
public DbSet<LastSeen> LastSeens { get; set; }

/// <summary>
/// when creating models.
/// </summary>
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);

// Ensure primary keys are defined for IdentityUserLogin
modelBuilder.Entity<IdentityUserLogin<string>>(entity =>
{
entity.HasKey(e => new { e.LoginProvider, e.ProviderKey });
});

// Additional model configurations
modelBuilder.Entity<User>()
.HasOne(u => u.Gender)
.WithMany()
.HasForeignKey(u => u.GenderId);

modelBuilder.Entity<Gender>().HasData(
new Gender { Id = 1, Name = "Male" },
new Gender { Id = 2, Name = "Female" },
new Gender { Id = 3, Name = "Non-Binary" },
new Gender { Id = 4, Name = "Other" });

modelBuilder.Entity<LastSeen>()
.HasOne(u => u.User)
.WithMany()
.HasForeignKey(u => u.UserId);
}
}
21 changes: 21 additions & 0 deletions AdvancedAPI.Data/DataExtension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using AdvancedAPI.Data.Repositories;
using AdvancedAPI.Data.Repositories.Interfaces;

namespace AdvancedAPI.Data;

/// <summary>
/// Service extension used to prepare the data layer for usage.
/// </summary>
public static class DataExtension
{
/// <summary>
/// Registers everything data layer related.
/// </summary>
public static void AddDataRepositories(this IServiceCollection services)
{
services.AddScoped<IIdentityRepository, IdentityRepository>();
services.AddScoped<INewsArticleRepository, NewsArticleRepository>();
services.AddScoped<IGenderRepository, GenderRepository>();
services.AddScoped<ILastSeenRepository, LastSeenRepository>();
}
}
29 changes: 18 additions & 11 deletions AdvancedAPI.Data/DbInitializer.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Identity;
using AdvancedAPI.Data.Models;
using Microsoft.AspNetCore.Identity;

namespace AdvancedAPI.Data
{
Expand All @@ -12,7 +13,7 @@ public class DbInitializer
/// </summary>
public static async Task Initialize(IServiceProvider serviceProvider)
{
UserManager<IdentityUser> userManager = serviceProvider.GetRequiredService<UserManager<IdentityUser>>();
UserManager<User> userManager = serviceProvider.GetRequiredService<UserManager<User>>();
RoleManager<IdentityRole> roleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();

// Seed roles
Expand Down Expand Up @@ -44,15 +45,18 @@ private static async Task SeedRoles(RoleManager<IdentityRole> roleManager)
/// <summary>
/// Seeding admin user into the database.
/// </summary>
private static async Task SeedAdminUser(UserManager<IdentityUser> userManager)
private static async Task SeedAdminUser(UserManager<User> userManager)
{
IdentityUser? adminUser = await userManager.FindByEmailAsync("admin@example.com");
User? adminUser = await userManager.FindByEmailAsync("admin@example.com");
if (adminUser == null)
{
adminUser = new IdentityUser
adminUser = new User
{
UserName = "admin@example.com",
Email = "admin@example.com",
DateOfBirth = new DateTime(1980, 1, 1),
DisplayName = "Admin User",
GenderId = 1 // Assuming 1 is the ID for Male
};

IdentityResult? result = await userManager.CreateAsync(adminUser, "P@ssw0rd");
Expand All @@ -66,21 +70,24 @@ private static async Task SeedAdminUser(UserManager<IdentityUser> userManager)
/// <summary>
/// Seeding user user into the database.
/// </summary>
private static async Task SeedUserUser(UserManager<IdentityUser> userManager)
private static async Task SeedUserUser(UserManager<User> userManager)
{
IdentityUser? adminUser = await userManager.FindByEmailAsync("user@example.com");
if (adminUser == null)
User? userUser = await userManager.FindByEmailAsync("user@example.com");
if (userUser == null)
{
adminUser = new IdentityUser
userUser = new User
{
UserName = "user@example.com",
Email = "user@example.com",
DateOfBirth = new DateTime(1990, 1, 1),
DisplayName = "Regular User",
GenderId = 2 // Assuming 2 is the ID for Female
};

IdentityResult? result = await userManager.CreateAsync(adminUser, "P@ssw0rd");
IdentityResult? result = await userManager.CreateAsync(userUser, "P@ssw0rd");
if (result.Succeeded)
{
await userManager.AddToRoleAsync(adminUser, "User");
await userManager.AddToRoleAsync(userUser, "User");
}
}
}
Expand Down
Loading

0 comments on commit 04e10b9

Please sign in to comment.