Release/v2.1.0 #44
74
src/HopFrame.Api/Controller/GroupController.cs
Normal file
74
src/HopFrame.Api/Controller/GroupController.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
using HopFrame.Api.Logic;
|
||||
using HopFrame.Database.Models;
|
||||
using HopFrame.Database.Repositories;
|
||||
using HopFrame.Security.Authorization;
|
||||
using HopFrame.Security.Claims;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace HopFrame.Api.Controller;
|
||||
|
||||
[ApiController, Route("api/v1/groups")]
|
||||
public class GroupController(IOptions<AdminPermissionOptions> permissions, IPermissionRepository perms, ITokenContext context, IGroupLogic groups) : ControllerBase {
|
||||
|
||||
private async Task<bool> AuthorizeRequest(string permission) {
|
||||
return await perms.HasPermission(context.AccessToken, permission);
|
||||
}
|
||||
|
||||
[HttpGet, Authorized]
|
||||
public async Task<ActionResult<IList<PermissionGroup>>> GetGroups() {
|
||||
if (!await AuthorizeRequest(permissions.Value.Groups.Read))
|
||||
return Unauthorized();
|
||||
|
||||
return await groups.GetGroups();
|
||||
}
|
||||
|
||||
[HttpGet("default"), Authorized]
|
||||
public async Task<ActionResult<IList<PermissionGroup>>> GetDefaultGroups() {
|
||||
if (!await AuthorizeRequest(permissions.Value.Groups.Read))
|
||||
return Unauthorized();
|
||||
|
||||
return await groups.GetDefaultGroups();
|
||||
}
|
||||
|
||||
[HttpGet("user/{userId}"), Authorized]
|
||||
public async Task<ActionResult<IList<PermissionGroup>>> GetUserGroups(string userId) {
|
||||
if (!await AuthorizeRequest(permissions.Value.Groups.Read))
|
||||
return Unauthorized();
|
||||
|
||||
return await groups.GetUserGroups(userId);
|
||||
}
|
||||
|
||||
[HttpGet("{name}"), Authorized]
|
||||
public async Task<ActionResult<PermissionGroup>> GetGroup(string name) {
|
||||
if (!await AuthorizeRequest(permissions.Value.Groups.Read))
|
||||
return Unauthorized();
|
||||
|
||||
return await groups.GetGroup(name);
|
||||
}
|
||||
|
||||
[HttpPost, Authorized]
|
||||
public async Task<ActionResult<PermissionGroup>> CreateGroup([FromBody] PermissionGroup group) {
|
||||
if (!await AuthorizeRequest(permissions.Value.Groups.Create))
|
||||
return Unauthorized();
|
||||
|
||||
return await groups.CreateGroup(group);
|
||||
}
|
||||
|
||||
[HttpPut, Authorized]
|
||||
public async Task<ActionResult<PermissionGroup>> UpdateGroup([FromBody] PermissionGroup group) {
|
||||
if (!await AuthorizeRequest(permissions.Value.Groups.Update))
|
||||
return Unauthorized();
|
||||
|
||||
return await groups.UpdateGroup(group);
|
||||
}
|
||||
|
||||
[HttpDelete("{name}"), Authorized]
|
||||
public async Task<ActionResult> DeleteGroup(string name) {
|
||||
if (!await AuthorizeRequest(permissions.Value.Groups.Delete))
|
||||
return Unauthorized();
|
||||
|
||||
return await groups.DeleteGroup(name);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,7 +19,7 @@ public static class ServiceCollectionExtensions {
|
||||
/// <param name="configuration">The configuration used to configure HopFrame authentication</param>
|
||||
/// <typeparam name="TDbContext">The data source for all HopFrame entities</typeparam>
|
||||
public static void AddHopFrame<TDbContext>(this IServiceCollection services, ConfigurationManager configuration) where TDbContext : HopDbContextBase {
|
||||
var controllers = new List<Type> { typeof(UserController) };
|
||||
var controllers = new List<Type> { typeof(UserController), typeof(GroupController) };
|
||||
|
||||
var defaultAuthenticationSection = configuration.GetSection("HopFrame:Authentication:DefaultAuthentication");
|
||||
if (!defaultAuthenticationSection.Exists() || configuration.GetValue<bool>("HopFrame:Authentication:DefaultAuthentication"))
|
||||
@@ -48,6 +48,7 @@ public static class ServiceCollectionExtensions {
|
||||
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||
services.AddScoped<IAuthLogic, AuthLogic>();
|
||||
services.AddScoped<IUserLogic, UserLogic>();
|
||||
services.AddScoped<IGroupLogic, GroupLogic>();
|
||||
|
||||
services.AddHopFrameAuthentication(configuration);
|
||||
}
|
||||
|
||||
14
src/HopFrame.Api/Logic/IGroupLogic.cs
Normal file
14
src/HopFrame.Api/Logic/IGroupLogic.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using HopFrame.Database.Models;
|
||||
|
||||
namespace HopFrame.Api.Logic;
|
||||
|
||||
public interface IGroupLogic {
|
||||
Task<LogicResult<IList<PermissionGroup>>> GetGroups();
|
||||
Task<LogicResult<IList<PermissionGroup>>> GetDefaultGroups();
|
||||
Task<LogicResult<IList<PermissionGroup>>> GetUserGroups(string userId);
|
||||
Task<LogicResult<PermissionGroup>> GetGroup(string name);
|
||||
|
||||
Task<LogicResult<PermissionGroup>> CreateGroup(PermissionGroup group);
|
||||
Task<LogicResult<PermissionGroup>> UpdateGroup(PermissionGroup group);
|
||||
Task<LogicResult> DeleteGroup(string name);
|
||||
}
|
||||
66
src/HopFrame.Api/Logic/Implementation/GroupLogic.cs
Normal file
66
src/HopFrame.Api/Logic/Implementation/GroupLogic.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using HopFrame.Database.Models;
|
||||
using HopFrame.Database.Repositories;
|
||||
|
||||
namespace HopFrame.Api.Logic.Implementation;
|
||||
|
||||
internal sealed class GroupLogic(IGroupRepository groups, IUserRepository users) : IGroupLogic {
|
||||
public async Task<LogicResult<IList<PermissionGroup>>> GetGroups() {
|
||||
return LogicResult<IList<PermissionGroup>>.Ok(await groups.GetPermissionGroups());
|
||||
}
|
||||
|
||||
public async Task<LogicResult<IList<PermissionGroup>>> GetDefaultGroups() {
|
||||
return LogicResult<IList<PermissionGroup>>.Ok(await groups.GetDefaultGroups());
|
||||
}
|
||||
|
||||
public async Task<LogicResult<IList<PermissionGroup>>> GetUserGroups(string id) {
|
||||
if (!Guid.TryParse(id, out var userId))
|
||||
return LogicResult<IList<PermissionGroup>>.BadRequest("Invalid user id");
|
||||
|
||||
var user = await users.GetUser(userId);
|
||||
|
||||
if (user is null)
|
||||
return LogicResult<IList<PermissionGroup>>.NotFound("That user does not exist");
|
||||
|
||||
return LogicResult<IList<PermissionGroup>>.Ok(await groups.GetUserGroups(user));
|
||||
}
|
||||
|
||||
public async Task<LogicResult<PermissionGroup>> GetGroup(string name) {
|
||||
var group = await groups.GetPermissionGroup(name);
|
||||
|
||||
if (group is null)
|
||||
return LogicResult<PermissionGroup>.NotFound("That group does not exist");
|
||||
|
||||
return LogicResult<PermissionGroup>.Ok(group);
|
||||
}
|
||||
|
||||
public async Task<LogicResult<PermissionGroup>> CreateGroup(PermissionGroup group) {
|
||||
if (group is null)
|
||||
return LogicResult<PermissionGroup>.BadRequest("Provide a group");
|
||||
|
||||
if (!group.Name.StartsWith("group."))
|
||||
return LogicResult<PermissionGroup>.BadRequest("Group names must start with 'group.'");
|
||||
|
||||
if (await groups.GetPermissionGroup(group.Name) != null)
|
||||
return LogicResult<PermissionGroup>.Conflict("That group already exists");
|
||||
|
||||
return LogicResult<PermissionGroup>.Ok(await groups.CreatePermissionGroup(group));
|
||||
}
|
||||
|
||||
public async Task<LogicResult<PermissionGroup>> UpdateGroup(PermissionGroup group) {
|
||||
if (await groups.GetPermissionGroup(group.Name) == null)
|
||||
return LogicResult<PermissionGroup>.NotFound("That user does not exist");
|
||||
|
||||
await groups.EditPermissionGroup(group);
|
||||
return LogicResult<PermissionGroup>.Ok(group);
|
||||
}
|
||||
|
||||
public async Task<LogicResult> DeleteGroup(string name) {
|
||||
var group = await groups.GetPermissionGroup(name);
|
||||
|
||||
if (group is null)
|
||||
return LogicResult.NotFound("That group does not exist");
|
||||
|
||||
await groups.DeletePermissionGroup(group);
|
||||
return LogicResult.Ok();
|
||||
}
|
||||
}
|
||||
@@ -33,19 +33,38 @@ internal sealed class GroupRepository<TDbContext>(TDbContext context) : IGroupRe
|
||||
}
|
||||
|
||||
public async Task EditPermissionGroup(PermissionGroup group) {
|
||||
var orig = await context.Groups.SingleOrDefaultAsync(g => g.Name == group.Name);
|
||||
|
||||
var orig = await context.Groups
|
||||
.Include(g => g.Permissions) // Include related entities
|
||||
.SingleOrDefaultAsync(g => g.Name == group.Name);
|
||||
|
||||
if (orig is null) return;
|
||||
|
||||
var entity = context.Groups.Update(orig);
|
||||
// Update the main entity's properties
|
||||
orig.IsDefaultGroup = group.IsDefaultGroup;
|
||||
orig.Description = group.Description;
|
||||
|
||||
entity.Entity.IsDefaultGroup = group.IsDefaultGroup;
|
||||
entity.Entity.Description = group.Description;
|
||||
entity.Entity.Permissions = group.Permissions;
|
||||
// Update the permissions
|
||||
foreach (var permission in group.Permissions) {
|
||||
var existingPermission = orig.Permissions.FirstOrDefault(p => p.Id == permission.Id);
|
||||
if (existingPermission != null) {
|
||||
// Update existing permission
|
||||
context.Entry(existingPermission).CurrentValues.SetValues(permission);
|
||||
} else {
|
||||
// Add new permission
|
||||
orig.Permissions.Add(permission);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove deleted permissions
|
||||
foreach (var permission in orig.Permissions.ToList().Where(permission => group.Permissions.All(p => p.Id != permission.Id))) {
|
||||
orig.Permissions.Remove(permission);
|
||||
context.Permissions.Remove(permission); // Ensure it gets removed from the database
|
||||
}
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
|
||||
public async Task<PermissionGroup> CreatePermissionGroup(PermissionGroup group) {
|
||||
group.CreatedAt = DateTime.Now;
|
||||
await context.Groups.AddAsync(group);
|
||||
|
||||
@@ -69,10 +69,45 @@ internal sealed class UserRepository<TDbContext>(TDbContext context, IGroupRepos
|
||||
.SingleOrDefaultAsync(entry => entry.Id == user.Id);
|
||||
if (entry is null) return;
|
||||
|
||||
// Update the main entity's properties
|
||||
entry.Email = user.Email;
|
||||
entry.Username = user.Username;
|
||||
entry.Permissions = user.Permissions;
|
||||
entry.Tokens = user.Tokens;
|
||||
|
||||
// Update Permissions
|
||||
foreach (var permission in user.Permissions) {
|
||||
var existingPermission = entry.Permissions.FirstOrDefault(p => p.Id == permission.Id);
|
||||
if (existingPermission != null) {
|
||||
// Update existing permission
|
||||
context.Entry(existingPermission).CurrentValues.SetValues(permission);
|
||||
} else {
|
||||
// Add new permission
|
||||
entry.Permissions.Add(permission);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove deleted permissions
|
||||
foreach (var permission in entry.Permissions.ToList().Where(permission => user.Permissions.All(p => p.Id != permission.Id))) {
|
||||
entry.Permissions.Remove(permission);
|
||||
context.Permissions.Remove(permission); // Ensure it gets removed from the database
|
||||
}
|
||||
|
||||
// Update Tokens
|
||||
foreach (var token in user.Tokens) {
|
||||
var existingToken = entry.Tokens.FirstOrDefault(t => t.TokenId == token.TokenId);
|
||||
if (existingToken != null) {
|
||||
// Update existing token
|
||||
context.Entry(existingToken).CurrentValues.SetValues(token);
|
||||
} else {
|
||||
// Add new token
|
||||
entry.Tokens.Add(token);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove deleted tokens
|
||||
foreach (var token in entry.Tokens.ToList().Where(token => user.Tokens.All(t => t.TokenId != token.TokenId))) {
|
||||
entry.Tokens.Remove(token);
|
||||
context.Tokens.Remove(token); // Ensure it gets removed from the database
|
||||
}
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user