Files
TakeoutSaaS.TenantApi/src/Api/TakeoutSaaS.AdminApi/Controllers/DictionaryLabelOverridesController.cs

177 lines
7.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using TakeoutSaaS.Application.Dictionary.Models;
using TakeoutSaaS.Application.Dictionary.Services;
using TakeoutSaaS.Domain.Dictionary.Enums;
using TakeoutSaaS.Module.Authorization.Attributes;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Results;
using TakeoutSaaS.Shared.Abstractions.Security;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
using TakeoutSaaS.Shared.Web.Api;
namespace TakeoutSaaS.AdminApi.Controllers;
/// <summary>
/// 字典标签覆盖管理。
/// </summary>
[ApiVersion("1.0")]
[Authorize]
[Route("api/admin/v{version:apiVersion}/dictionary/label-overrides")]
public sealed class DictionaryLabelOverridesController(
DictionaryLabelOverrideService labelOverrideService,
ITenantProvider tenantProvider,
ICurrentUserAccessor currentUserAccessor)
: BaseApiController
{
private const string TenantIdHeaderName = "X-Tenant-Id";
#region API
/// <summary>
/// 获取当前租户的标签覆盖列表。
/// </summary>
[HttpGet("tenant")]
[PermissionAuthorize("dictionary:override:read")]
[ProducesResponseType(typeof(ApiResponse<IReadOnlyList<LabelOverrideDto>>), StatusCodes.Status200OK)]
public async Task<ApiResponse<IReadOnlyList<LabelOverrideDto>>> ListTenantOverrides(
[FromQuery] OverrideType? overrideType,
CancellationToken cancellationToken)
{
var headerError = EnsureTenantHeader<IReadOnlyList<LabelOverrideDto>>();
if (headerError != null)
{
return headerError;
}
var tenantId = tenantProvider.GetCurrentTenantId();
var result = await labelOverrideService.GetOverridesAsync(tenantId, overrideType, cancellationToken);
return ApiResponse<IReadOnlyList<LabelOverrideDto>>.Ok(result);
}
/// <summary>
/// 租户覆盖系统字典项的标签。
/// </summary>
[HttpPost("tenant")]
[PermissionAuthorize("dictionary:override:update")]
[ProducesResponseType(typeof(ApiResponse<LabelOverrideDto>), StatusCodes.Status200OK)]
public async Task<ApiResponse<LabelOverrideDto>> CreateTenantOverride(
[FromBody] UpsertLabelOverrideRequest request,
CancellationToken cancellationToken)
{
var headerError = EnsureTenantHeader<LabelOverrideDto>();
if (headerError != null)
{
return headerError;
}
var tenantId = tenantProvider.GetCurrentTenantId();
var operatorId = currentUserAccessor.UserId;
var result = await labelOverrideService.UpsertTenantOverrideAsync(tenantId, request, operatorId, cancellationToken);
return ApiResponse<LabelOverrideDto>.Ok(result);
}
/// <summary>
/// 租户删除自己的标签覆盖。
/// </summary>
[HttpDelete("tenant/{dictionaryItemId:long}")]
[PermissionAuthorize("dictionary:override:delete")]
[ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status404NotFound)]
public async Task<ApiResponse<object>> DeleteTenantOverride(long dictionaryItemId, CancellationToken cancellationToken)
{
var headerError = EnsureTenantHeader<object>();
if (headerError != null)
{
return headerError;
}
var tenantId = tenantProvider.GetCurrentTenantId();
var operatorId = currentUserAccessor.UserId;
var success = await labelOverrideService.DeleteOverrideAsync(
tenantId,
dictionaryItemId,
operatorId,
allowPlatformEnforcement: false,
cancellationToken);
return success
? ApiResponse.Success()
: ApiResponse.Error(ErrorCodes.NotFound, "覆盖配置不存在");
}
#endregion
#region API
/// <summary>
/// 获取指定租户的所有标签覆盖(平台管理员用)。
/// </summary>
[HttpGet("platform/{targetTenantId:long}")]
[PermissionAuthorize("dictionary:override:platform:read")]
[ProducesResponseType(typeof(ApiResponse<IReadOnlyList<LabelOverrideDto>>), StatusCodes.Status200OK)]
public async Task<ApiResponse<IReadOnlyList<LabelOverrideDto>>> ListPlatformOverrides(
long targetTenantId,
[FromQuery] OverrideType? overrideType,
CancellationToken cancellationToken)
{
var result = await labelOverrideService.GetOverridesAsync(targetTenantId, overrideType, cancellationToken);
return ApiResponse<IReadOnlyList<LabelOverrideDto>>.Ok(result);
}
/// <summary>
/// 平台强制覆盖租户字典项的标签。
/// </summary>
[HttpPost("platform/{targetTenantId:long}")]
[PermissionAuthorize("dictionary:override:platform:update")]
[ProducesResponseType(typeof(ApiResponse<LabelOverrideDto>), StatusCodes.Status200OK)]
public async Task<ApiResponse<LabelOverrideDto>> CreatePlatformOverride(
long targetTenantId,
[FromBody] UpsertLabelOverrideRequest request,
CancellationToken cancellationToken)
{
var operatorId = currentUserAccessor.UserId;
var result = await labelOverrideService.UpsertPlatformOverrideAsync(targetTenantId, request, operatorId, cancellationToken);
return ApiResponse<LabelOverrideDto>.Ok(result);
}
/// <summary>
/// 平台删除对租户的强制覆盖。
/// </summary>
[HttpDelete("platform/{targetTenantId:long}/{dictionaryItemId:long}")]
[PermissionAuthorize("dictionary:override:platform:delete")]
[ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status404NotFound)]
public async Task<ApiResponse<object>> DeletePlatformOverride(
long targetTenantId,
long dictionaryItemId,
CancellationToken cancellationToken)
{
var operatorId = currentUserAccessor.UserId;
var success = await labelOverrideService.DeleteOverrideAsync(
targetTenantId,
dictionaryItemId,
operatorId,
cancellationToken: cancellationToken);
return success
? ApiResponse.Success()
: ApiResponse.Error(ErrorCodes.NotFound, "覆盖配置不存在");
}
#endregion
private ApiResponse<T>? EnsureTenantHeader<T>()
{
if (!Request.Headers.TryGetValue(TenantIdHeaderName, out var tenantHeader) || string.IsNullOrWhiteSpace(tenantHeader))
{
return ApiResponse<T>.Error(StatusCodes.Status400BadRequest, $"缺少租户标识,请在请求头 {TenantIdHeaderName} 指定租户");
}
if (!long.TryParse(tenantHeader.FirstOrDefault(), out _))
{
return ApiResponse<T>.Error(StatusCodes.Status400BadRequest, $"租户标识无效,请在请求头 {TenantIdHeaderName} 指定正确的租户 ID");
}
return null;
}
}