using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.ComponentModel.DataAnnotations;
using TakeoutSaaS.Application.Identity.Commands;
using TakeoutSaaS.Application.Identity.Contracts;
using TakeoutSaaS.Application.Identity.Queries;
using TakeoutSaaS.Module.Authorization.Attributes;
using TakeoutSaaS.Shared.Abstractions.Results;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
using TakeoutSaaS.Shared.Web.Api;
namespace TakeoutSaaS.AdminApi.Controllers;
///
/// 租户角色管理(实例层)。
///
[ApiVersion("1.0")]
[Authorize]
[Route("api/admin/v{version:apiVersion}/tenants/{tenantId:long}/roles")]
public sealed class TenantRolesController(IMediator mediator, ITenantProvider tenantProvider) : BaseApiController
{
private const long PlatformRootTenantId = 1000000000001;
///
/// 租户角色分页。
///
[HttpGet]
[PermissionAuthorize("identity:role:read")]
[ProducesResponseType(typeof(ApiResponse>), StatusCodes.Status200OK)]
public async Task>> List(
long tenantId,
[FromQuery] SearchRolesQuery query,
CancellationToken cancellationToken)
{
// 1. 校验路由租户与上下文一致(超管租户 1000000000001 放行)
var currentTenantId = tenantProvider.GetCurrentTenantId();
if (currentTenantId != PlatformRootTenantId && tenantId != currentTenantId)
{
return ApiResponse>.Error(StatusCodes.Status400BadRequest, "租户上下文不一致");
}
// 2. 绑定租户并查询角色分页
var request = new SearchRolesQuery
{
TenantId = tenantId,
Keyword = query.Keyword,
Page = query.Page,
PageSize = query.PageSize,
SortBy = query.SortBy,
SortDescending = query.SortDescending
};
var result = await mediator.Send(request, cancellationToken);
// 3. 返回分页数据
return ApiResponse>.Ok(result);
}
///
/// 角色详情(含权限)。
///
[HttpGet("{roleId:long}")]
[PermissionAuthorize("identity:role:read")]
[ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)]
public async Task> Detail(long tenantId, long roleId, CancellationToken cancellationToken)
{
// 1. 校验租户上下文(超管租户 1000000000001 放行)
var currentTenantId = tenantProvider.GetCurrentTenantId();
if (currentTenantId != PlatformRootTenantId && tenantId != currentTenantId)
{
return ApiResponse.Error(StatusCodes.Status400BadRequest, "租户上下文不一致");
}
// 2. 查询角色详情
var result = await mediator.Send(new RoleDetailQuery { RoleId = roleId, TenantId = tenantId }, cancellationToken);
// 3. 返回数据或 404
return result is null
? ApiResponse.Error(StatusCodes.Status404NotFound, "角色不存在")
: ApiResponse.Ok(result);
}
///
/// 创建角色。
///
[HttpPost]
[PermissionAuthorize("identity:role:create")]
[ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)]
public async Task> Create(
long tenantId,
[FromBody, Required] CreateRoleCommand command,
CancellationToken cancellationToken)
{
// 1. 校验租户上下文(超管租户 1000000000001 放行)
var currentTenantId = tenantProvider.GetCurrentTenantId();
if (currentTenantId != PlatformRootTenantId && tenantId != currentTenantId)
{
return ApiResponse.Error(StatusCodes.Status400BadRequest, "租户上下文不一致");
}
// 2. 创建角色
var result = await mediator.Send(command with { TenantId = tenantId }, cancellationToken);
// 3. 返回创建结果
return ApiResponse.Ok(result);
}
///
/// 更新角色。
///
[HttpPut("{roleId:long}")]
[PermissionAuthorize("identity:role:update")]
[ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)]
public async Task> Update(
long tenantId,
long roleId,
[FromBody, Required] UpdateRoleCommand command,
CancellationToken cancellationToken)
{
// 1. 校验租户上下文(超管租户 1000000000001 放行)
var currentTenantId = tenantProvider.GetCurrentTenantId();
if (currentTenantId != PlatformRootTenantId && tenantId != currentTenantId)
{
return ApiResponse.Error(StatusCodes.Status400BadRequest, "租户上下文不一致");
}
// 2. 绑定角色 ID
command = command with { RoleId = roleId, TenantId = tenantId };
// 3. 执行更新
var result = await mediator.Send(command, cancellationToken);
// 4. 返回结果或 404
return result is null
? ApiResponse.Error(StatusCodes.Status404NotFound, "角色不存在")
: ApiResponse.Ok(result);
}
///
/// 删除角色。
///
[HttpDelete("{roleId:long}")]
[PermissionAuthorize("identity:role:delete")]
[ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)]
public async Task> Delete(long tenantId, long roleId, CancellationToken cancellationToken)
{
// 1. 校验租户上下文(超管租户 1000000000001 放行)
var currentTenantId = tenantProvider.GetCurrentTenantId();
if (currentTenantId != PlatformRootTenantId && tenantId != currentTenantId)
{
return ApiResponse.Error(StatusCodes.Status400BadRequest, "租户上下文不一致");
}
// 2. 执行删除
var command = new DeleteRoleCommand { RoleId = roleId, TenantId = tenantId };
var result = await mediator.Send(command, cancellationToken);
// 3. 返回结果
return ApiResponse.Ok(result);
}
///
/// 获取角色权限列表。
///
[HttpGet("{roleId:long}/permissions")]
[PermissionAuthorize("identity:role:read")]
[ProducesResponseType(typeof(ApiResponse>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ApiResponse>), StatusCodes.Status404NotFound)]
public async Task>> GetPermissions(
long tenantId,
long roleId,
CancellationToken cancellationToken)
{
// 1. 校验租户上下文(超管租户 1000000000001 放行)
var currentTenantId = tenantProvider.GetCurrentTenantId();
if (currentTenantId != PlatformRootTenantId && tenantId != currentTenantId)
{
return ApiResponse>.Error(StatusCodes.Status400BadRequest, "租户上下文不一致");
}
// 2. 查询角色详情并提取权限
var detail = await mediator.Send(new RoleDetailQuery { RoleId = roleId, TenantId = tenantId }, cancellationToken);
if (detail is null)
{
return ApiResponse>.Error(StatusCodes.Status404NotFound, "角色不存在");
}
// 3. 返回权限集合
return ApiResponse>.Ok(detail.Permissions);
}
///
/// 覆盖角色权限。
///
[HttpPut("{roleId:long}/permissions")]
[PermissionAuthorize("identity:role:bind-permission")]
[ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)]
public async Task> BindPermissions(
long tenantId,
long roleId,
[FromBody, Required] BindRolePermissionsCommand command,
CancellationToken cancellationToken)
{
// 1. 校验租户上下文(超管租户 1000000000001 放行)
var currentTenantId = tenantProvider.GetCurrentTenantId();
if (currentTenantId != PlatformRootTenantId && tenantId != currentTenantId)
{
return ApiResponse.Error(StatusCodes.Status400BadRequest, "租户上下文不一致");
}
// 2. 绑定角色 ID
command = command with { RoleId = roleId, TenantId = tenantId };
// 3. 覆盖授权
var result = await mediator.Send(command, cancellationToken);
return ApiResponse.Ok(result);
}
}