fix: 服务渠道分组软删同名可恢复,并修正 COS 自定义域名签名
All checks were successful
Build and Deploy / deploy (push) Successful in 1m44s
All checks were successful
Build and Deploy / deploy (push) Successful in 1m44s
同名软删分组创建时恢复记录,更新时释放唯一键冲突;COS 自定义 CDN 域名关闭 signHost,并补充常见图片 Content-Type。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
8ce8b82f48
commit
623db4ffdb
@ -64,6 +64,21 @@ public partial class ServiceChannelService
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新时若目标名称被软删记录占用,则改名释放唯一键,避免 uk_scg_name 冲突。
|
||||
/// </summary>
|
||||
private async Task FreeSoftDeletedNameIfNeededAsync(string name, int currentId)
|
||||
{
|
||||
var conflict = await ServiceChannelGroupRepository.GetByNameIncludingDeletedAsync(name);
|
||||
if (conflict == null || !conflict.IsDeleted || conflict.Id == currentId)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
conflict.Name = $"{name}__deleted_{conflict.Id}";
|
||||
await ServiceChannelGroupRepository.UpdateAsync(conflict);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 校验渠道编码唯一性。
|
||||
/// </summary>
|
||||
|
||||
@ -128,9 +128,21 @@ public partial class ServiceChannelService : ApplicationService
|
||||
public async Task CreateGroupAsync(ServiceChannelGroupSaveInput input)
|
||||
{
|
||||
await ValidateGroupInputAsync(input, null);
|
||||
var name = input.Name.Trim();
|
||||
var deleted = await ServiceChannelGroupRepository.GetByNameIncludingDeletedAsync(name);
|
||||
if (deleted != null && deleted.IsDeleted)
|
||||
{
|
||||
deleted.IsDeleted = false;
|
||||
deleted.Name = name;
|
||||
deleted.AppId = input.AppId;
|
||||
deleted.ApiServiceProviderId = input.ApiServiceProviderId;
|
||||
await ServiceChannelGroupRepository.UpdateAsync(deleted);
|
||||
return;
|
||||
}
|
||||
|
||||
await ServiceChannelGroupRepository.InsertAsync(new ServiceChannelGroup
|
||||
{
|
||||
Name = input.Name.Trim(),
|
||||
Name = name,
|
||||
AppId = input.AppId,
|
||||
ApiServiceProviderId = input.ApiServiceProviderId
|
||||
});
|
||||
@ -146,7 +158,9 @@ public partial class ServiceChannelService : ApplicationService
|
||||
{
|
||||
var group = await GetGroupOrThrowAsync(input.Id);
|
||||
await ValidateGroupInputAsync(input, group.Id);
|
||||
group.Name = input.Name.Trim();
|
||||
var name = input.Name.Trim();
|
||||
await FreeSoftDeletedNameIfNeededAsync(name, group.Id);
|
||||
group.Name = name;
|
||||
group.AppId = input.AppId;
|
||||
group.ApiServiceProviderId = input.ApiServiceProviderId;
|
||||
await ServiceChannelGroupRepository.UpdateAsync(group);
|
||||
|
||||
@ -245,6 +245,32 @@ public class FileStorageService : ApplicationService
|
||||
return "text/html; charset=utf-8";
|
||||
}
|
||||
|
||||
if (path.EndsWith(".png", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return "image/png";
|
||||
}
|
||||
|
||||
if (path.EndsWith(".webp", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return "image/webp";
|
||||
}
|
||||
|
||||
if (path.EndsWith(".gif", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return "image/gif";
|
||||
}
|
||||
|
||||
if (path.EndsWith(".bmp", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return "image/bmp";
|
||||
}
|
||||
|
||||
if (path.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase)
|
||||
|| path.EndsWith(".jpeg", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return "image/jpeg";
|
||||
}
|
||||
|
||||
return "application/octet-stream";
|
||||
}
|
||||
|
||||
|
||||
@ -365,8 +365,11 @@ public sealed class TencentCosFileStorage : IFileStorage, IDisposable
|
||||
if (!string.IsNullOrWhiteSpace(_customHost)
|
||||
&& !_customHost.EndsWith(".myqcloud.com", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// 自定义 CDN 域名:URL 走 cos.ideship.com,但不要把 Host 签进 q-header-list。
|
||||
// signHost=true 时浏览器直开签名链常因 CDN 回源 Host 不一致而 403(img naturalWidth=0),
|
||||
// 对象其实在桶里(/file-storage/stream 可读)。
|
||||
preSign.host = _customHost;
|
||||
preSign.signHost = true;
|
||||
preSign.signHost = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -6,4 +6,9 @@ namespace Oms.Domain.ChannelsAggregate.Repositories;
|
||||
public interface IServiceChannelGroupRepository : IRepository<ServiceChannelGroup>
|
||||
{
|
||||
Task<ServiceChannelGroup?> GetByNameAsync(string name, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// 按名称查询分组(含软删除),用于唯一名冲突时恢复或释放名称。
|
||||
/// </summary>
|
||||
Task<ServiceChannelGroup?> GetByNameIncludingDeletedAsync(string name, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ using Fake.DependencyInjection;
|
||||
using Oms.Domain.ChannelsAggregate.Entities;
|
||||
using Oms.Domain.ChannelsAggregate.Repositories;
|
||||
using Oms.SqlSugarCore.Repositories;
|
||||
using SqlSugar;
|
||||
|
||||
namespace Oms.SqlSugarCore.Channels;
|
||||
|
||||
@ -11,4 +12,17 @@ public class ServiceChannelGroupRepository : OmsSqlSugarRepository<ServiceChanne
|
||||
{
|
||||
return FirstOrDefaultAsync(x => x.Name == name, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<ServiceChannelGroup?> GetByNameIncludingDeletedAsync(
|
||||
string name,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var db = await GetDbContextAsync(cancellationToken);
|
||||
var rows = await db.Queryable<ServiceChannelGroup>()
|
||||
.ClearFilter()
|
||||
.Where(x => x.Name == name)
|
||||
.Take(1)
|
||||
.ToListAsync(cancellationToken);
|
||||
return rows.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user