Skip to content
Merged
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
Expand Up @@ -29,10 +29,10 @@ public AppointmentService(IAppointmentRepository repository, IUserRepository use
_userContext = userContext;
}

private void EnsureAdmin()
private void EnsureSuperAdmin()
{
if (_userContext.Role!=UserRole.Admin)
throw new UnauthorizedAccessException("Only Admin Access");
if (_userContext.Role!=UserRole.SuperAdmin)
throw new UnauthorizedAccessException("Only SuperAdmin Access");
}
public async Task<string> CreateAppointmentAsync(CreateAppointment dto)
{
Expand Down Expand Up @@ -93,7 +93,7 @@ await _appointmenServiceLinkRepository

public async Task<List<ViewAppointments>> ViewAppointments()
{
EnsureAdmin();
EnsureSuperAdmin();
return await _appointmentRepository.ViewAppointments();
}

Expand Down
2 changes: 2 additions & 0 deletions Application/Features/Auth/Interfaces/IUserService.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
using Application.Features.Auth.DTOs;
using Domain.Enums;

namespace Application.Features.Auth.Interfaces;

public interface IUserService
{
Task<string> RegisterUserAsync(RegisterUserRequestDto registerUserRequestDto);
Task<LoginUserResponseDto> LoginUserAsync(LoginUserRequestDto loginUserRequestDto);
Task ChangeRoleTo(UserRole role);
Task<string> LogoutUserAsync();
Task<LoginUserResponseDto> RefreshTokenAsync(string refreshToken);
Task<ProfileResponseDto> ViewProfileAsync();
Expand Down
8 changes: 8 additions & 0 deletions Application/Features/Auth/Services/UserService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Application.Features.Auth.DTOs;
using Application.Features.Auth.Interfaces;
using Domain.Entities;
using Domain.Enums;

namespace Application.Features.Auth.Services;

Expand Down Expand Up @@ -68,6 +69,13 @@ public async Task<LoginUserResponseDto> LoginUserAsync(LoginUserRequestDto login
return new LoginUserResponseDto(token, refreshTokenValue);
}

public async Task ChangeRoleTo(UserRole role)
{
var userId =_userContext.UserId;
var user =await _userRepository.GetUserByIdAsync(userId);
user?.ChangeRoleTo(role);
}

public async Task<string> LogoutUserAsync()
{
var userId = _userContext.UserId;
Expand Down
10 changes: 5 additions & 5 deletions Application/Features/Service/Services/ServiceAppService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,22 @@ public ServiceAppService(IServiceRepository repository, IUSerContext context)
_userContext = context;
}

private void EnsureAdmin()
private void EnsureSuperAdmin()
{
if (_userContext.Role != UserRole.Admin)
if (_userContext.Role != UserRole.SuperAdmin)
throw new ForbiddenAccessException("Only Admin Access");
}
public async Task<string> CreateServiceAsync(CreateService createService)
{
EnsureAdmin();
EnsureSuperAdmin();
var service=new Domain.Entities.Service(createService.Title,createService.DurationMinutes);
await _repository.CreatServiceAsync(service);
return $"{service.Title} created";
}

public async Task<string> EditServiceAsync(Guid serviceId,EditService editService)
{
EnsureAdmin();
EnsureSuperAdmin();
var appointment = await _repository.GetServiceByIdAsync(serviceId) ?? throw new NotFoundException("Service not found");

appointment.Edit(editService.DurationMinutes,editService.Title);
Expand All @@ -41,7 +41,7 @@ public async Task<string> EditServiceAsync(Guid serviceId,EditService editServic

public async Task<string> DeleteServiceAsync(Guid serviceId)
{
EnsureAdmin();
EnsureSuperAdmin();
await _repository.DeleteServiceAsync(serviceId);
return $"{serviceId} deleted";
}
Expand Down
26 changes: 24 additions & 2 deletions Application/Features/Tenant/Services/TenantService.cs
Original file line number Diff line number Diff line change
@@ -1,24 +1,46 @@
using Application.Common.Interfaces;
using Application.Features.Auth.Interfaces;
using Application.Features.Auth.Services;
using Application.Features.Tenant.DTO_s;
using Application.Features.Tenant.Interfaces;
using Domain.Entities;
using Domain.Enums;
using Domain.Exceptions;
using Microsoft.Extensions.Configuration;

namespace Application.Features.Tenant.Services;

public class TenantService:TenantServiceContract
{
private readonly TenantRepositoryContract _tenantRepository;
private readonly IUSerContext _userContext;
private readonly IUserRepository _userRepository;

public TenantService(TenantRepositoryContract tenantRepository)
public TenantService(TenantRepositoryContract tenantRepository, IUSerContext userContext, IUserRepository userRepository)
{
_tenantRepository = tenantRepository;
_userContext = userContext;
_userRepository = userRepository;
}

public async Task<string> Register(RegisterTenantDTO dto)
{
//Todo: slug maker
// Todo : Date manager
// Todo : if for duplicate slug
var tenant = new Domain.Entities.Tenant(dto.Name,dto.Slug,dto.SubscriptionExpireDate);

var userId=_userContext.UserId;
var user = await _userRepository.GetUserByIdAsync(userId);

if(user==null)
throw new NotFoundException("User not found");

await _tenantRepository.RegisterTenant(tenant);
user.ChangeRoleTo(UserRole.Admin);
user.AssignTenantToUser(tenant.Id);
await _tenantRepository.SaveAsync();
return $"{tenant.Name} Registered";

return $"{tenant.Name} Registered belong to user {user.FullName} created";
}
}
8 changes: 8 additions & 0 deletions Domain/Entities/User.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
public ICollection<RefreshToken> RefreshTokens { get; private set; } = new List<RefreshToken>();
public ICollection<Appointment> Appointments { get; private set; } = new List<Appointment>();

public User()

Check warning on line 21 in Domain/Entities/User.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Password' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.

Check warning on line 21 in Domain/Entities/User.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'PhoneNumber' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.

Check warning on line 21 in Domain/Entities/User.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Email' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.

Check warning on line 21 in Domain/Entities/User.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'FullName' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.
{
}

Expand All @@ -42,6 +42,14 @@
Password = password;
}

public void AssignTenantToUser(Guid tenantId)
{
TenantId = tenantId;
}
public void ChangeRoleTo(UserRole role)
{
Role = role;
}
public void UpdateProfile(string fullName, string phoneNumber)
{
FullName = fullName;
Expand Down
4 changes: 3 additions & 1 deletion Domain/Enums/UserRole.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ namespace Domain.Enums;

public enum UserRole
{
SuperAdmin,
User,
Admin,
User
Customer
}
12 changes: 6 additions & 6 deletions Infrastructure/Persistence/DbInitializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ public class DbInitializer

public static void Seed(AppDbContext context, IPasswordHasher passwordHasher,IConfiguration configuration)
{
if (!context.Users.Any(u => u.Role == UserRole.Admin))
if (!context.Users.Any(u => u.Role == UserRole.SuperAdmin))
{
var FullName=configuration["SeedAdmin:FullName"];
var Email=configuration["SeedAdmin:Email"];
var PhoneNumber=configuration["SeedAdmin:PhoneNumber"];
var Password=passwordHasher.Hash(configuration["SeedAdmin:Password"]);
var role=UserRole.Admin;
var FullName=configuration["SeedSuperAdmin:FullName"];
var Email=configuration["SeedSuperAdmin:Email"];
var PhoneNumber=configuration["SeedSuperAdmin:PhoneNumber"];
var Password=passwordHasher.Hash(configuration["SeedSuperAdmin:Password"]);
var role=UserRole.SuperAdmin;

var User=new User(FullName,Email,PhoneNumber,role,Password);

Expand Down
2 changes: 1 addition & 1 deletion api/Controllers/AppointmentController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public async Task<IActionResult> Cancel([FromRoute]Guid appointmentId)

[HttpGet]
[Route("ViewAppointments")]
[Authorize(Roles = "Admin")]
[Authorize(Roles = "SuperAdmin")]
public async Task<IActionResult> ViewAppointments()
{
var appointments=await _service.ViewAppointments();
Expand Down
6 changes: 3 additions & 3 deletions api/Controllers/ServiceController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ public ServiceController(IServiceAppService serviceAppService)
}

[HttpPost]
[Authorize(Roles = "Admin")]
[Authorize(Roles = "SuperAdmin")]
public async Task<IActionResult> Create([FromBody] CreateService service)
{
var res=await _serviceAppService.CreateServiceAsync(service);
return Ok(res);
}

[HttpPatch("{serviceId}")]
[Authorize(Roles = "Admin")]
[Authorize(Roles = "SuperAdmin")]
public async Task<IActionResult> Edit([FromRoute] Guid serviceId,[FromBody] EditService service)
{
var res= await _serviceAppService.EditServiceAsync(serviceId,service);
Expand All @@ -39,7 +39,7 @@ public async Task<List<ViewServices>> ViewServices()
}

[HttpDelete("{serviceId}")]
[Authorize(Roles = "Admin")]
[Authorize(Roles = "SuperAdmin")]
public async Task<IActionResult> Delete([FromRoute] Guid serviceId)
{
var res = await _serviceAppService.DeleteServiceAsync(serviceId);
Expand Down
2 changes: 2 additions & 0 deletions api/Controllers/TenantController.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Application.Features.Tenant.DTO_s;
using Application.Features.Tenant.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace api.Controllers;
Expand All @@ -15,6 +16,7 @@ public TenantController(TenantServiceContract tenantService)
}

[HttpPost]
[Authorize(Roles = "User,Admin")]
public async Task<IActionResult> RegisterTenant([FromBody] RegisterTenantDTO dto)
{
// Todo: expire date base on plan
Expand Down
2 changes: 1 addition & 1 deletion api/Controllers/UserController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public async Task<IActionResult> Refresh([FromBody]RefreshTokenRequest dto)
return Ok(await _service.RefreshTokenAsync(dto.RefreshToken));
}
[HttpGet("ViewUsers")]
[Authorize(Roles = "Admin")]
[Authorize(Roles = "SuperAdmin")]
public async Task<IActionResult> ViewUsers()
{
var res= await _service.GetAllUsersAsync();
Expand Down
Loading