LocationSupportAppService.cs 5.22 KB
using FoodLabeling.Application.Contracts;
using FoodLabeling.Application.Contracts.Dtos.LocationSupport;
using FoodLabeling.Application.Contracts.IServices;
using FoodLabeling.Application.Services.DbModels;
using Microsoft.AspNetCore.Authorization;
using Volo.Abp;
using Volo.Abp.Application.Services;
using Volo.Abp.Guids;
using Volo.Abp.Uow;
using Yi.Framework.SqlSugarCore.Abstractions;

namespace FoodLabeling.Application.Services;

/// <summary>
/// 全局 Support 联系方式(全门店共用;Web 可增改查,App JWT 仅可读)
/// </summary>
[Authorize]
public class LocationSupportAppService : ApplicationService, ILocationSupportAppService
{
    private readonly ISqlSugarDbContext _dbContext;
    private readonly IGuidGenerator _guidGenerator;

    public LocationSupportAppService(ISqlSugarDbContext dbContext, IGuidGenerator guidGenerator)
    {
        _dbContext = dbContext;
        _guidGenerator = guidGenerator;
    }

    /// <inheritdoc />
    public async Task<LocationSupportGetOutputDto?> GetSupportAsync()
    {
        var rows = await _dbContext.SqlSugarClient.Queryable<FlLocationSupportDbEntity>()
            .Where(x => !x.IsDeleted)
            .ToListAsync();
        var entity = rows.FirstOrDefault();
        return MapOutput(entity);
    }

    /// <inheritdoc />
    [UnitOfWork]
    public async Task<LocationSupportGetOutputDto> CreateAsync(LocationSupportCreateInputVo input)
    {
        EnsureNotUsAppClient();

        if (input is null)
        {
            throw new UserFriendlyException("Request body is required.");
        }

        var phone = NormalizeRequired(input.SupportPhone, "Support phone is required.");
        var email = NormalizeRequired(input.SupportEmail, "Support email is required.");
        EnsureEmailFormat(email);

        var existed = await _dbContext.SqlSugarClient.Queryable<FlLocationSupportDbEntity>()
            .AnyAsync(x => !x.IsDeleted);
        if (existed)
        {
            throw new UserFriendlyException(
                "Global support contact already exists. Use update instead.");
        }

        var now = Clock.Now;
        var entity = new FlLocationSupportDbEntity
        {
            Id = _guidGenerator.Create().ToString(),
            IsDeleted = false,
            CreationTime = now,
            CreatorId = CurrentUser?.Id?.ToString(),
            LastModificationTime = now,
            LastModifierId = CurrentUser?.Id?.ToString(),
            SupportPhone = phone,
            SupportEmail = email
        };

        await _dbContext.SqlSugarClient.Insertable(entity).ExecuteCommandAsync();
        return MapOutput(entity)!;
    }

    /// <inheritdoc />
    [UnitOfWork]
    public async Task<LocationSupportGetOutputDto> UpdateAsync(string id, LocationSupportUpdateInputVo input)
    {
        EnsureNotUsAppClient();

        var supportId = id?.Trim();
        if (string.IsNullOrWhiteSpace(supportId))
        {
            throw new UserFriendlyException("Support record id is required.");
        }

        if (input is null)
        {
            throw new UserFriendlyException("Request body is required.");
        }

        var rows = await _dbContext.SqlSugarClient.Queryable<FlLocationSupportDbEntity>()
            .Where(x => !x.IsDeleted && x.Id == supportId)
            .ToListAsync();
        var entity = rows.FirstOrDefault();
        if (entity is null)
        {
            throw new UserFriendlyException("Support record not found.");
        }

        var phone = NormalizeRequired(input.SupportPhone, "Support phone is required.");
        var email = NormalizeRequired(input.SupportEmail, "Support email is required.");
        EnsureEmailFormat(email);

        entity.SupportPhone = phone;
        entity.SupportEmail = email;
        entity.LastModificationTime = Clock.Now;
        entity.LastModifierId = CurrentUser?.Id?.ToString();

        await _dbContext.SqlSugarClient.Updateable(entity).ExecuteCommandAsync();
        return MapOutput(entity)!;
    }

    private void EnsureNotUsAppClient()
    {
        if (CurrentUser.FindClaim(UsAppJwtClaims.ClientKind)?.Value == UsAppJwtClaims.ClientKindUsApp)
        {
            throw new UserFriendlyException(
                "The mobile app can only view support contacts. Please use the web console to edit.");
        }
    }

    private static string NormalizeRequired(string? value, string message)
    {
        var normalized = value?.Trim();
        if (string.IsNullOrWhiteSpace(normalized))
        {
            throw new UserFriendlyException(message);
        }

        return normalized;
    }

    private static void EnsureEmailFormat(string email)
    {
        if (!email.Contains("@", StringComparison.Ordinal) || email.StartsWith("@", StringComparison.Ordinal) ||
            email.EndsWith("@", StringComparison.Ordinal))
        {
            throw new UserFriendlyException("Support email format is invalid.");
        }
    }

    private static LocationSupportGetOutputDto? MapOutput(FlLocationSupportDbEntity? entity)
    {
        if (entity is null)
        {
            return null;
        }

        return new LocationSupportGetOutputDto
        {
            Id = entity.Id,
            SupportPhone = entity.SupportPhone,
            SupportEmail = entity.SupportEmail
        };
    }
}