修复公告过时警告并补齐用户权限
This commit is contained in:
@@ -58,8 +58,7 @@ public sealed class CreateTenantAnnouncementCommandHandler(
|
|||||||
PublisherUserId = publisherUserId,
|
PublisherUserId = publisherUserId,
|
||||||
Status = AnnouncementStatus.Draft,
|
Status = AnnouncementStatus.Draft,
|
||||||
TargetType = request.TargetType.Trim(),
|
TargetType = request.TargetType.Trim(),
|
||||||
TargetParameters = request.TargetParameters,
|
TargetParameters = request.TargetParameters
|
||||||
IsActive = false
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 3. 持久化并返回 DTO
|
// 3. 持久化并返回 DTO
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ public sealed class MarkAnnouncementAsReadCommandHandler(
|
|||||||
|
|
||||||
// 2. 仅允许已发布且在有效期内的公告标记已读
|
// 2. 仅允许已发布且在有效期内的公告标记已读
|
||||||
var now = DateTime.UtcNow;
|
var now = DateTime.UtcNow;
|
||||||
if (announcement.Status != AnnouncementStatus.Published || !announcement.IsActive)
|
if (announcement.Status != AnnouncementStatus.Published)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,6 @@ public sealed class PublishAnnouncementCommandHandler(
|
|||||||
announcement.Status = AnnouncementStatus.Published;
|
announcement.Status = AnnouncementStatus.Published;
|
||||||
announcement.PublishedAt = DateTime.UtcNow;
|
announcement.PublishedAt = DateTime.UtcNow;
|
||||||
announcement.RevokedAt = null;
|
announcement.RevokedAt = null;
|
||||||
announcement.IsActive = true;
|
|
||||||
announcement.RowVersion = request.RowVersion;
|
announcement.RowVersion = request.RowVersion;
|
||||||
|
|
||||||
await announcementRepository.UpdateAsync(announcement, cancellationToken);
|
await announcementRepository.UpdateAsync(announcement, cancellationToken);
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ public sealed class RevokeAnnouncementCommandHandler(
|
|||||||
// 3. 撤销公告
|
// 3. 撤销公告
|
||||||
announcement.Status = AnnouncementStatus.Revoked;
|
announcement.Status = AnnouncementStatus.Revoked;
|
||||||
announcement.RevokedAt = DateTime.UtcNow;
|
announcement.RevokedAt = DateTime.UtcNow;
|
||||||
announcement.IsActive = false;
|
|
||||||
announcement.RowVersion = request.RowVersion;
|
announcement.RowVersion = request.RowVersion;
|
||||||
|
|
||||||
await announcementRepository.UpdateAsync(announcement, cancellationToken);
|
await announcementRepository.UpdateAsync(announcement, cancellationToken);
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ public sealed class UpdateTenantAnnouncementCommandHandler(ITenantAnnouncementRe
|
|||||||
announcement.Content = request.Content;
|
announcement.Content = request.Content;
|
||||||
announcement.TargetType = string.IsNullOrWhiteSpace(request.TargetType) ? announcement.TargetType : request.TargetType.Trim();
|
announcement.TargetType = string.IsNullOrWhiteSpace(request.TargetType) ? announcement.TargetType : request.TargetType.Trim();
|
||||||
announcement.TargetParameters = request.TargetParameters;
|
announcement.TargetParameters = request.TargetParameters;
|
||||||
announcement.IsActive = false;
|
|
||||||
announcement.RowVersion = request.RowVersion;
|
announcement.RowVersion = request.RowVersion;
|
||||||
|
|
||||||
// 4. 持久化
|
// 4. 持久化
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using TakeoutSaaS.Application.App.Tenants.Dto;
|
using TakeoutSaaS.Application.App.Tenants.Dto;
|
||||||
using TakeoutSaaS.Domain.Tenants.Entities;
|
using TakeoutSaaS.Domain.Tenants.Entities;
|
||||||
|
using TakeoutSaaS.Domain.Tenants.Enums;
|
||||||
|
|
||||||
namespace TakeoutSaaS.Application.App.Tenants;
|
namespace TakeoutSaaS.Application.App.Tenants;
|
||||||
|
|
||||||
@@ -193,7 +194,7 @@ internal static class TenantMapping
|
|||||||
TargetType = announcement.TargetType,
|
TargetType = announcement.TargetType,
|
||||||
TargetParameters = announcement.TargetParameters,
|
TargetParameters = announcement.TargetParameters,
|
||||||
RowVersion = announcement.RowVersion,
|
RowVersion = announcement.RowVersion,
|
||||||
IsActive = announcement.IsActive,
|
IsActive = announcement.Status == AnnouncementStatus.Published,
|
||||||
IsRead = isRead,
|
IsRead = isRead,
|
||||||
ReadAt = readAt
|
ReadAt = readAt
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -774,14 +774,14 @@ public sealed class TakeoutAppDbContext(
|
|||||||
builder.Property(x => x.TargetType).HasMaxLength(64).IsRequired();
|
builder.Property(x => x.TargetType).HasMaxLength(64).IsRequired();
|
||||||
builder.Property(x => x.TargetParameters).HasColumnType("text");
|
builder.Property(x => x.TargetParameters).HasColumnType("text");
|
||||||
builder.Property(x => x.Priority).IsRequired();
|
builder.Property(x => x.Priority).IsRequired();
|
||||||
builder.Property(x => x.IsActive).IsRequired();
|
builder.Property<bool>("IsActive").IsRequired();
|
||||||
builder.Property(x => x.RowVersion)
|
builder.Property(x => x.RowVersion)
|
||||||
.IsRowVersion()
|
.IsRowVersion()
|
||||||
.IsConcurrencyToken()
|
.IsConcurrencyToken()
|
||||||
.HasColumnType("bytea");
|
.HasColumnType("bytea");
|
||||||
ConfigureAuditableEntity(builder);
|
ConfigureAuditableEntity(builder);
|
||||||
ConfigureSoftDeleteEntity(builder);
|
ConfigureSoftDeleteEntity(builder);
|
||||||
builder.HasIndex(x => new { x.TenantId, x.AnnouncementType, x.IsActive });
|
builder.HasIndex("TenantId", "AnnouncementType", "IsActive");
|
||||||
builder.HasIndex(x => new { x.TenantId, x.EffectiveFrom, x.EffectiveTo });
|
builder.HasIndex(x => new { x.TenantId, x.EffectiveFrom, x.EffectiveTo });
|
||||||
builder.HasIndex(x => new { x.TenantId, x.Status, x.EffectiveFrom });
|
builder.HasIndex(x => new { x.TenantId, x.Status, x.EffectiveFrom });
|
||||||
builder.HasIndex(x => new { x.Status, x.EffectiveFrom })
|
builder.HasIndex(x => new { x.Status, x.EffectiveFrom })
|
||||||
|
|||||||
@@ -50,7 +50,9 @@ public sealed class EfTenantAnnouncementRepository(TakeoutAppDbContext context)
|
|||||||
|
|
||||||
if (isActive.HasValue)
|
if (isActive.HasValue)
|
||||||
{
|
{
|
||||||
query = query.Where(x => x.IsActive == isActive.Value);
|
query = isActive.Value
|
||||||
|
? query.Where(x => x.Status == AnnouncementStatus.Published)
|
||||||
|
: query.Where(x => x.Status != AnnouncementStatus.Published);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (effectiveFrom.HasValue)
|
if (effectiveFrom.HasValue)
|
||||||
@@ -114,7 +116,9 @@ public sealed class EfTenantAnnouncementRepository(TakeoutAppDbContext context)
|
|||||||
|
|
||||||
if (isActive.HasValue)
|
if (isActive.HasValue)
|
||||||
{
|
{
|
||||||
announcementQuery = announcementQuery.Where(x => x.IsActive == isActive.Value);
|
announcementQuery = isActive.Value
|
||||||
|
? announcementQuery.Where(x => x.Status == AnnouncementStatus.Published)
|
||||||
|
: announcementQuery.Where(x => x.Status != AnnouncementStatus.Published);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (effectiveAt.HasValue)
|
if (effectiveAt.HasValue)
|
||||||
|
|||||||
@@ -0,0 +1,726 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
using TakeoutSaaS.Infrastructure.Identity.Persistence;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace TakeoutSaaS.Infrastructure.Migrations.IdentityDb
|
||||||
|
{
|
||||||
|
[DbContext(typeof(IdentityDbContext))]
|
||||||
|
[Migration("20251226231440_GrantIdentityUserPermissionsToSuperAdmin")]
|
||||||
|
partial class GrantIdentityUserPermissionsToSuperAdmin
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "10.0.0")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("TakeoutSaaS.Domain.Identity.Entities.IdentityUser", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("实体唯一标识。");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("Account")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("character varying(64)")
|
||||||
|
.HasComment("登录账号。");
|
||||||
|
|
||||||
|
b.Property<string>("Avatar")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasComment("头像地址。");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("创建时间(UTC)。");
|
||||||
|
|
||||||
|
b.Property<long?>("CreatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DeletedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("软删除时间(UTC),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("DeletedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("删除人用户标识(软删除),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<string>("DisplayName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("character varying(64)")
|
||||||
|
.HasComment("展示名称。");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.HasMaxLength(128)
|
||||||
|
.HasColumnType("character varying(128)")
|
||||||
|
.HasComment("邮箱(租户内唯一)。");
|
||||||
|
|
||||||
|
b.Property<int>("FailedLoginCount")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasComment("登录失败次数。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("LastLoginAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("最近登录时间(UTC)。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("LockedUntil")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("锁定截止时间(UTC)。");
|
||||||
|
|
||||||
|
b.Property<long?>("MerchantId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("所属商户(平台管理员为空)。");
|
||||||
|
|
||||||
|
b.Property<bool>("MustChangePassword")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasComment("是否强制修改密码。");
|
||||||
|
|
||||||
|
b.Property<string>("PasswordHash")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("character varying(256)")
|
||||||
|
.HasComment("密码哈希。");
|
||||||
|
|
||||||
|
b.Property<string>("Phone")
|
||||||
|
.HasMaxLength(32)
|
||||||
|
.HasColumnType("character varying(32)")
|
||||||
|
.HasComment("手机号(租户内唯一)。");
|
||||||
|
|
||||||
|
b.Property<byte[]>("RowVersion")
|
||||||
|
.IsConcurrencyToken()
|
||||||
|
.IsRequired()
|
||||||
|
.ValueGeneratedOnAddOrUpdate()
|
||||||
|
.HasColumnType("bytea")
|
||||||
|
.HasComment("并发控制字段。");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasComment("账号状态。");
|
||||||
|
|
||||||
|
b.Property<long>("TenantId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("所属租户 ID。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("最近一次更新时间(UTC),从未更新时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("UpdatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("TenantId");
|
||||||
|
|
||||||
|
b.HasIndex("TenantId", "Account")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("TenantId", "Email")
|
||||||
|
.IsUnique()
|
||||||
|
.HasFilter("\"Email\" IS NOT NULL");
|
||||||
|
|
||||||
|
b.HasIndex("TenantId", "Phone")
|
||||||
|
.IsUnique()
|
||||||
|
.HasFilter("\"Phone\" IS NOT NULL");
|
||||||
|
|
||||||
|
b.ToTable("identity_users", null, t =>
|
||||||
|
{
|
||||||
|
t.HasComment("管理后台账户实体(平台管理员、租户管理员或商户员工)。");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TakeoutSaaS.Domain.Identity.Entities.MenuDefinition", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("实体唯一标识。");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("AuthListJson")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasComment("按钮权限列表 JSON(存储 MenuAuthItemDto 数组)。");
|
||||||
|
|
||||||
|
b.Property<string>("Component")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("character varying(256)")
|
||||||
|
.HasComment("组件路径(不含 .vue)。");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("创建时间(UTC)。");
|
||||||
|
|
||||||
|
b.Property<long?>("CreatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DeletedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("软删除时间(UTC),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("DeletedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("删除人用户标识(软删除),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<string>("Icon")
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("character varying(64)")
|
||||||
|
.HasComment("图标标识。");
|
||||||
|
|
||||||
|
b.Property<bool>("IsIframe")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasComment("是否 iframe。");
|
||||||
|
|
||||||
|
b.Property<bool>("KeepAlive")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasComment("是否缓存。");
|
||||||
|
|
||||||
|
b.Property<string>("Link")
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("character varying(512)")
|
||||||
|
.HasComment("外链或 iframe 地址。");
|
||||||
|
|
||||||
|
b.Property<string>("MetaPermissions")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(1024)
|
||||||
|
.HasColumnType("character varying(1024)")
|
||||||
|
.HasComment("Meta.permissions(逗号分隔)。");
|
||||||
|
|
||||||
|
b.Property<string>("MetaRoles")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(1024)
|
||||||
|
.HasColumnType("character varying(1024)")
|
||||||
|
.HasComment("Meta.roles(逗号分隔)。");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("character varying(64)")
|
||||||
|
.HasComment("菜单名称(前端路由 name)。");
|
||||||
|
|
||||||
|
b.Property<long>("ParentId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("父级菜单 ID,根节点为 0。");
|
||||||
|
|
||||||
|
b.Property<string>("Path")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("character varying(256)")
|
||||||
|
.HasComment("路由路径。");
|
||||||
|
|
||||||
|
b.Property<string>("RequiredPermissions")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(1024)
|
||||||
|
.HasColumnType("character varying(1024)")
|
||||||
|
.HasComment("访问该菜单所需的权限集合(逗号分隔)。");
|
||||||
|
|
||||||
|
b.Property<int>("SortOrder")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasComment("排序。");
|
||||||
|
|
||||||
|
b.Property<long>("TenantId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("所属租户 ID。");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(128)
|
||||||
|
.HasColumnType("character varying(128)")
|
||||||
|
.HasComment("标题。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("最近一次更新时间(UTC),从未更新时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("UpdatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("TenantId", "ParentId", "SortOrder");
|
||||||
|
|
||||||
|
b.ToTable("menu_definitions", null, t =>
|
||||||
|
{
|
||||||
|
t.HasComment("管理端菜单定义。");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TakeoutSaaS.Domain.Identity.Entities.MiniUser", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("实体唯一标识。");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("Avatar")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasComment("头像地址。");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("创建时间(UTC)。");
|
||||||
|
|
||||||
|
b.Property<long?>("CreatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DeletedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("软删除时间(UTC),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("DeletedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("删除人用户标识(软删除),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<string>("Nickname")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("character varying(64)")
|
||||||
|
.HasComment("昵称。");
|
||||||
|
|
||||||
|
b.Property<string>("OpenId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(128)
|
||||||
|
.HasColumnType("character varying(128)")
|
||||||
|
.HasComment("微信 OpenId。");
|
||||||
|
|
||||||
|
b.Property<long>("TenantId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("所属租户 ID。");
|
||||||
|
|
||||||
|
b.Property<string>("UnionId")
|
||||||
|
.HasMaxLength(128)
|
||||||
|
.HasColumnType("character varying(128)")
|
||||||
|
.HasComment("微信 UnionId,可能为空。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("最近一次更新时间(UTC),从未更新时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("UpdatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("TenantId");
|
||||||
|
|
||||||
|
b.HasIndex("TenantId", "OpenId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("mini_users", null, t =>
|
||||||
|
{
|
||||||
|
t.HasComment("小程序用户实体。");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TakeoutSaaS.Domain.Identity.Entities.Permission", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("实体唯一标识。");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("Code")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(128)
|
||||||
|
.HasColumnType("character varying(128)")
|
||||||
|
.HasComment("权限编码(租户内唯一)。");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("创建时间(UTC)。");
|
||||||
|
|
||||||
|
b.Property<long?>("CreatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DeletedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("软删除时间(UTC),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("DeletedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("删除人用户标识(软删除),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("character varying(256)")
|
||||||
|
.HasComment("描述。");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("character varying(64)")
|
||||||
|
.HasComment("权限名称。");
|
||||||
|
|
||||||
|
b.Property<long>("ParentId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("父级权限 ID,根节点为 0。");
|
||||||
|
|
||||||
|
b.Property<int>("SortOrder")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasComment("排序值,值越小越靠前。");
|
||||||
|
|
||||||
|
b.Property<long>("TenantId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("所属租户 ID。");
|
||||||
|
|
||||||
|
b.Property<string>("Type")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(16)
|
||||||
|
.HasColumnType("character varying(16)")
|
||||||
|
.HasComment("权限类型(group/leaf)。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("最近一次更新时间(UTC),从未更新时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("UpdatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("TenantId");
|
||||||
|
|
||||||
|
b.HasIndex("TenantId", "Code")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("TenantId", "ParentId", "SortOrder");
|
||||||
|
|
||||||
|
b.ToTable("permissions", null, t =>
|
||||||
|
{
|
||||||
|
t.HasComment("权限定义。");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TakeoutSaaS.Domain.Identity.Entities.Role", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("实体唯一标识。");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("Code")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("character varying(64)")
|
||||||
|
.HasComment("角色编码(租户内唯一)。");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("创建时间(UTC)。");
|
||||||
|
|
||||||
|
b.Property<long?>("CreatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DeletedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("软删除时间(UTC),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("DeletedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("删除人用户标识(软删除),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("character varying(256)")
|
||||||
|
.HasComment("描述。");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("character varying(64)")
|
||||||
|
.HasComment("角色名称。");
|
||||||
|
|
||||||
|
b.Property<long>("TenantId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("所属租户 ID。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("最近一次更新时间(UTC),从未更新时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("UpdatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("TenantId");
|
||||||
|
|
||||||
|
b.HasIndex("TenantId", "Code")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("roles", null, t =>
|
||||||
|
{
|
||||||
|
t.HasComment("角色定义。");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TakeoutSaaS.Domain.Identity.Entities.RolePermission", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("实体唯一标识。");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("创建时间(UTC)。");
|
||||||
|
|
||||||
|
b.Property<long?>("CreatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DeletedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("软删除时间(UTC),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("DeletedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("删除人用户标识(软删除),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<long>("PermissionId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("权限 ID。");
|
||||||
|
|
||||||
|
b.Property<long>("RoleId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("角色 ID。");
|
||||||
|
|
||||||
|
b.Property<long>("TenantId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("所属租户 ID。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("最近一次更新时间(UTC),从未更新时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("UpdatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("TenantId");
|
||||||
|
|
||||||
|
b.HasIndex("TenantId", "RoleId", "PermissionId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("role_permissions", null, t =>
|
||||||
|
{
|
||||||
|
t.HasComment("角色-权限关系。");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TakeoutSaaS.Domain.Identity.Entities.RoleTemplate", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("实体唯一标识。");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("创建时间(UTC)。");
|
||||||
|
|
||||||
|
b.Property<long?>("CreatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DeletedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("软删除时间(UTC),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("DeletedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("删除人用户标识(软删除),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("character varying(256)")
|
||||||
|
.HasComment("模板描述。");
|
||||||
|
|
||||||
|
b.Property<bool>("IsActive")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasComment("是否启用。");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(128)
|
||||||
|
.HasColumnType("character varying(128)")
|
||||||
|
.HasComment("模板名称。");
|
||||||
|
|
||||||
|
b.Property<string>("TemplateCode")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("character varying(64)")
|
||||||
|
.HasComment("模板编码(唯一)。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("最近一次更新时间(UTC),从未更新时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("UpdatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("TemplateCode")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("role_templates", null, t =>
|
||||||
|
{
|
||||||
|
t.HasComment("角色模板定义(平台级)。");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TakeoutSaaS.Domain.Identity.Entities.RoleTemplatePermission", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("实体唯一标识。");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("创建时间(UTC)。");
|
||||||
|
|
||||||
|
b.Property<long?>("CreatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DeletedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("软删除时间(UTC),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("DeletedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("删除人用户标识(软删除),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<string>("PermissionCode")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(128)
|
||||||
|
.HasColumnType("character varying(128)")
|
||||||
|
.HasComment("权限编码。");
|
||||||
|
|
||||||
|
b.Property<long>("RoleTemplateId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("模板 ID。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("最近一次更新时间(UTC),从未更新时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("UpdatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("RoleTemplateId", "PermissionCode")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("role_template_permissions", null, t =>
|
||||||
|
{
|
||||||
|
t.HasComment("角色模板-权限关系(平台级)。");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TakeoutSaaS.Domain.Identity.Entities.UserRole", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("实体唯一标识。");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("创建时间(UTC)。");
|
||||||
|
|
||||||
|
b.Property<long?>("CreatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DeletedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("软删除时间(UTC),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("DeletedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("删除人用户标识(软删除),未删除时为 null。");
|
||||||
|
|
||||||
|
b.Property<long>("RoleId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("角色 ID。");
|
||||||
|
|
||||||
|
b.Property<long>("TenantId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("所属租户 ID。");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasComment("最近一次更新时间(UTC),从未更新时为 null。");
|
||||||
|
|
||||||
|
b.Property<long?>("UpdatedBy")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
|
||||||
|
|
||||||
|
b.Property<long>("UserId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasComment("用户 ID。");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("TenantId");
|
||||||
|
|
||||||
|
b.HasIndex("TenantId", "UserId", "RoleId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("user_roles", null, t =>
|
||||||
|
{
|
||||||
|
t.HasComment("用户-角色关系。");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace TakeoutSaaS.Infrastructure.Migrations.IdentityDb
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class GrantIdentityUserPermissionsToSuperAdmin : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.Sql(
|
||||||
|
@"WITH target_roles AS (
|
||||||
|
SELECT ""Id"" AS role_id, ""TenantId"" AS tenant_id
|
||||||
|
FROM ""roles""
|
||||||
|
WHERE ""Code"" IN ('super-admin', 'SUPER_ADMIN', 'PlatformAdmin', 'platform-admin')
|
||||||
|
AND ""DeletedAt"" IS NULL
|
||||||
|
),
|
||||||
|
target_permissions AS (
|
||||||
|
SELECT DISTINCT tr.tenant_id, pc.code
|
||||||
|
FROM target_roles tr
|
||||||
|
CROSS JOIN (VALUES
|
||||||
|
('identity:user:read'),
|
||||||
|
('identity:user:create'),
|
||||||
|
('identity:user:update'),
|
||||||
|
('identity:user:delete'),
|
||||||
|
('identity:user:status'),
|
||||||
|
('identity:user:reset-password'),
|
||||||
|
('identity:user:batch')
|
||||||
|
) AS pc(code)
|
||||||
|
)
|
||||||
|
INSERT INTO ""permissions"" (
|
||||||
|
""TenantId"",
|
||||||
|
""Name"",
|
||||||
|
""Code"",
|
||||||
|
""Description"",
|
||||||
|
""CreatedAt"",
|
||||||
|
""CreatedBy"",
|
||||||
|
""UpdatedAt"",
|
||||||
|
""UpdatedBy"",
|
||||||
|
""DeletedAt"",
|
||||||
|
""DeletedBy""
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
tp.tenant_id,
|
||||||
|
tp.code,
|
||||||
|
tp.code,
|
||||||
|
CONCAT('Seed permission ', tp.code),
|
||||||
|
NOW(),
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
|
FROM target_permissions tp
|
||||||
|
ON CONFLICT (""TenantId"", ""Code"") DO NOTHING;"
|
||||||
|
);
|
||||||
|
migrationBuilder.Sql(
|
||||||
|
@"WITH target_roles AS (
|
||||||
|
SELECT ""Id"" AS role_id, ""TenantId"" AS tenant_id
|
||||||
|
FROM ""roles""
|
||||||
|
WHERE ""Code"" IN ('super-admin', 'SUPER_ADMIN', 'PlatformAdmin', 'platform-admin')
|
||||||
|
AND ""DeletedAt"" IS NULL
|
||||||
|
)
|
||||||
|
INSERT INTO ""role_permissions"" (
|
||||||
|
""TenantId"",
|
||||||
|
""RoleId"",
|
||||||
|
""PermissionId"",
|
||||||
|
""CreatedAt"",
|
||||||
|
""CreatedBy"",
|
||||||
|
""UpdatedAt"",
|
||||||
|
""UpdatedBy"",
|
||||||
|
""DeletedAt"",
|
||||||
|
""DeletedBy""
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
tr.tenant_id,
|
||||||
|
tr.role_id,
|
||||||
|
p.""Id"",
|
||||||
|
NOW(),
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
|
FROM target_roles tr
|
||||||
|
JOIN ""permissions"" p
|
||||||
|
ON p.""TenantId"" = tr.tenant_id
|
||||||
|
AND p.""Code"" IN (
|
||||||
|
'identity:user:read',
|
||||||
|
'identity:user:create',
|
||||||
|
'identity:user:update',
|
||||||
|
'identity:user:delete',
|
||||||
|
'identity:user:status',
|
||||||
|
'identity:user:reset-password',
|
||||||
|
'identity:user:batch'
|
||||||
|
)
|
||||||
|
WHERE p.""DeletedAt"" IS NULL
|
||||||
|
ON CONFLICT (""TenantId"", ""RoleId"", ""PermissionId"") DO NOTHING;"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.Sql(
|
||||||
|
@"WITH target_roles AS (
|
||||||
|
SELECT ""Id"" AS role_id, ""TenantId"" AS tenant_id
|
||||||
|
FROM ""roles""
|
||||||
|
WHERE ""Code"" IN ('super-admin', 'SUPER_ADMIN', 'PlatformAdmin', 'platform-admin')
|
||||||
|
AND ""DeletedAt"" IS NULL
|
||||||
|
),
|
||||||
|
target_permissions AS (
|
||||||
|
SELECT ""Id"" AS permission_id, ""TenantId"" AS tenant_id
|
||||||
|
FROM ""permissions""
|
||||||
|
WHERE ""Code"" IN (
|
||||||
|
'identity:user:read',
|
||||||
|
'identity:user:create',
|
||||||
|
'identity:user:update',
|
||||||
|
'identity:user:delete',
|
||||||
|
'identity:user:status',
|
||||||
|
'identity:user:reset-password',
|
||||||
|
'identity:user:batch'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
DELETE FROM ""role_permissions"" rp
|
||||||
|
USING target_roles tr, target_permissions tp
|
||||||
|
WHERE rp.""TenantId"" = tr.tenant_id
|
||||||
|
AND rp.""RoleId"" = tr.role_id
|
||||||
|
AND rp.""PermissionId"" = tp.permission_id;"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,9 +25,9 @@ public sealed class GetUnreadAnnouncementsQueryHandlerTests
|
|||||||
|
|
||||||
var announcements = new List<TakeoutSaaS.Domain.Tenants.Entities.TenantAnnouncement>
|
var announcements = new List<TakeoutSaaS.Domain.Tenants.Entities.TenantAnnouncement>
|
||||||
{
|
{
|
||||||
AnnouncementTestData.CreateAnnouncement(1, 55, priority: 1, effectiveFrom: DateTime.UtcNow.AddDays(-1), status: AnnouncementStatus.Published, isActive: true),
|
AnnouncementTestData.CreateAnnouncement(1, 55, priority: 1, effectiveFrom: DateTime.UtcNow.AddDays(-1), status: AnnouncementStatus.Published),
|
||||||
AnnouncementTestData.CreateAnnouncement(2, 55, priority: 3, effectiveFrom: DateTime.UtcNow.AddDays(-2), status: AnnouncementStatus.Published, isActive: true),
|
AnnouncementTestData.CreateAnnouncement(2, 55, priority: 3, effectiveFrom: DateTime.UtcNow.AddDays(-2), status: AnnouncementStatus.Published),
|
||||||
AnnouncementTestData.CreateAnnouncement(3, 55, priority: 2, effectiveFrom: DateTime.UtcNow, status: AnnouncementStatus.Published, isActive: true)
|
AnnouncementTestData.CreateAnnouncement(3, 55, priority: 2, effectiveFrom: DateTime.UtcNow, status: AnnouncementStatus.Published)
|
||||||
};
|
};
|
||||||
|
|
||||||
var announcementRepository = new Mock<ITenantAnnouncementRepository>();
|
var announcementRepository = new Mock<ITenantAnnouncementRepository>();
|
||||||
|
|||||||
@@ -52,8 +52,7 @@ public static class AnnouncementTestData
|
|||||||
long tenantId,
|
long tenantId,
|
||||||
int priority,
|
int priority,
|
||||||
DateTime effectiveFrom,
|
DateTime effectiveFrom,
|
||||||
AnnouncementStatus status = AnnouncementStatus.Draft,
|
AnnouncementStatus status = AnnouncementStatus.Draft)
|
||||||
bool isActive = false)
|
|
||||||
=> new()
|
=> new()
|
||||||
{
|
{
|
||||||
Id = id,
|
Id = id,
|
||||||
@@ -68,7 +67,6 @@ public static class AnnouncementTestData
|
|||||||
Status = status,
|
Status = status,
|
||||||
TargetType = string.Empty,
|
TargetType = string.Empty,
|
||||||
TargetParameters = null,
|
TargetParameters = null,
|
||||||
IsActive = isActive,
|
|
||||||
RowVersion = new byte[] { 1, 1, 1 }
|
RowVersion = new byte[] { 1, 1, 1 }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,15 +11,14 @@ namespace TakeoutSaaS.Integration.Tests.App.Tenants;
|
|||||||
public sealed class AnnouncementRegressionTests
|
public sealed class AnnouncementRegressionTests
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task GivenLegacyIsActiveAnnouncement_WhenSearchByIsActive_ThenReturns()
|
public async Task GivenPublishedAnnouncement_WhenSearchByIsActive_ThenReturns()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
using var database = new SqliteTestDatabase();
|
using var database = new SqliteTestDatabase();
|
||||||
using var context = database.CreateContext(tenantId: 600, userId: 12);
|
using var context = database.CreateContext(tenantId: 600, userId: 12);
|
||||||
|
|
||||||
var legacy = CreateAnnouncement(tenantId: 600, id: 9100);
|
var legacy = CreateAnnouncement(tenantId: 600, id: 9100);
|
||||||
legacy.Status = AnnouncementStatus.Draft;
|
legacy.Status = AnnouncementStatus.Published;
|
||||||
legacy.IsActive = true;
|
|
||||||
|
|
||||||
context.TenantAnnouncements.Add(legacy);
|
context.TenantAnnouncements.Add(legacy);
|
||||||
await context.SaveChangesAsync();
|
await context.SaveChangesAsync();
|
||||||
@@ -52,7 +51,6 @@ public sealed class AnnouncementRegressionTests
|
|||||||
|
|
||||||
var announcement = CreateAnnouncement(tenantId: 700, id: 9101);
|
var announcement = CreateAnnouncement(tenantId: 700, id: 9101);
|
||||||
announcement.Status = AnnouncementStatus.Draft;
|
announcement.Status = AnnouncementStatus.Draft;
|
||||||
announcement.IsActive = false;
|
|
||||||
context.TenantAnnouncements.Add(announcement);
|
context.TenantAnnouncements.Add(announcement);
|
||||||
await context.SaveChangesAsync();
|
await context.SaveChangesAsync();
|
||||||
context.ChangeTracker.Clear();
|
context.ChangeTracker.Clear();
|
||||||
@@ -95,7 +93,6 @@ public sealed class AnnouncementRegressionTests
|
|||||||
Status = AnnouncementStatus.Draft,
|
Status = AnnouncementStatus.Draft,
|
||||||
TargetType = "ALL_TENANTS",
|
TargetType = "ALL_TENANTS",
|
||||||
TargetParameters = null,
|
TargetParameters = null,
|
||||||
IsActive = false,
|
|
||||||
RowVersion = new byte[] { 1 }
|
RowVersion = new byte[] { 1 }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ public sealed class AnnouncementWorkflowTests
|
|||||||
using var verifyContext = database.CreateContext(tenantId: 100);
|
using var verifyContext = database.CreateContext(tenantId: 100);
|
||||||
var persisted = await verifyContext.TenantAnnouncements.FirstAsync(x => x.Id == announcement.Id);
|
var persisted = await verifyContext.TenantAnnouncements.FirstAsync(x => x.Id == announcement.Id);
|
||||||
persisted.Status.Should().Be(AnnouncementStatus.Published);
|
persisted.Status.Should().Be(AnnouncementStatus.Published);
|
||||||
persisted.IsActive.Should().BeTrue();
|
|
||||||
persisted.PublishedAt.Should().NotBeNull();
|
persisted.PublishedAt.Should().NotBeNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,7 +59,6 @@ public sealed class AnnouncementWorkflowTests
|
|||||||
|
|
||||||
var announcement = CreateDraftAnnouncement(tenantId: 200, id: 9002);
|
var announcement = CreateDraftAnnouncement(tenantId: 200, id: 9002);
|
||||||
announcement.Status = AnnouncementStatus.Published;
|
announcement.Status = AnnouncementStatus.Published;
|
||||||
announcement.IsActive = true;
|
|
||||||
context.TenantAnnouncements.Add(announcement);
|
context.TenantAnnouncements.Add(announcement);
|
||||||
await context.SaveChangesAsync();
|
await context.SaveChangesAsync();
|
||||||
context.ChangeTracker.Clear();
|
context.ChangeTracker.Clear();
|
||||||
@@ -85,7 +83,6 @@ public sealed class AnnouncementWorkflowTests
|
|||||||
using var verifyContext = database.CreateContext(tenantId: 200);
|
using var verifyContext = database.CreateContext(tenantId: 200);
|
||||||
var persisted = await verifyContext.TenantAnnouncements.FirstAsync(x => x.Id == announcement.Id);
|
var persisted = await verifyContext.TenantAnnouncements.FirstAsync(x => x.Id == announcement.Id);
|
||||||
persisted.Status.Should().Be(AnnouncementStatus.Revoked);
|
persisted.Status.Should().Be(AnnouncementStatus.Revoked);
|
||||||
persisted.IsActive.Should().BeFalse();
|
|
||||||
persisted.RevokedAt.Should().NotBeNull();
|
persisted.RevokedAt.Should().NotBeNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,7 +95,6 @@ public sealed class AnnouncementWorkflowTests
|
|||||||
|
|
||||||
var announcement = CreateDraftAnnouncement(tenantId: 300, id: 9003);
|
var announcement = CreateDraftAnnouncement(tenantId: 300, id: 9003);
|
||||||
announcement.Status = AnnouncementStatus.Revoked;
|
announcement.Status = AnnouncementStatus.Revoked;
|
||||||
announcement.IsActive = false;
|
|
||||||
announcement.RevokedAt = DateTime.UtcNow.AddMinutes(-5);
|
announcement.RevokedAt = DateTime.UtcNow.AddMinutes(-5);
|
||||||
context.TenantAnnouncements.Add(announcement);
|
context.TenantAnnouncements.Add(announcement);
|
||||||
await context.SaveChangesAsync();
|
await context.SaveChangesAsync();
|
||||||
@@ -124,7 +120,6 @@ public sealed class AnnouncementWorkflowTests
|
|||||||
using var verifyContext = database.CreateContext(tenantId: 300);
|
using var verifyContext = database.CreateContext(tenantId: 300);
|
||||||
var persisted = await verifyContext.TenantAnnouncements.FirstAsync(x => x.Id == announcement.Id);
|
var persisted = await verifyContext.TenantAnnouncements.FirstAsync(x => x.Id == announcement.Id);
|
||||||
persisted.Status.Should().Be(AnnouncementStatus.Published);
|
persisted.Status.Should().Be(AnnouncementStatus.Published);
|
||||||
persisted.IsActive.Should().BeTrue();
|
|
||||||
persisted.RevokedAt.Should().BeNull();
|
persisted.RevokedAt.Should().BeNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,7 +132,6 @@ public sealed class AnnouncementWorkflowTests
|
|||||||
|
|
||||||
var announcement = CreateDraftAnnouncement(tenantId: 400, id: 9004);
|
var announcement = CreateDraftAnnouncement(tenantId: 400, id: 9004);
|
||||||
announcement.Status = AnnouncementStatus.Published;
|
announcement.Status = AnnouncementStatus.Published;
|
||||||
announcement.IsActive = true;
|
|
||||||
context.TenantAnnouncements.Add(announcement);
|
context.TenantAnnouncements.Add(announcement);
|
||||||
await context.SaveChangesAsync();
|
await context.SaveChangesAsync();
|
||||||
context.ChangeTracker.Clear();
|
context.ChangeTracker.Clear();
|
||||||
@@ -216,7 +210,6 @@ public sealed class AnnouncementWorkflowTests
|
|||||||
Status = AnnouncementStatus.Draft,
|
Status = AnnouncementStatus.Draft,
|
||||||
TargetType = "ALL_TENANTS",
|
TargetType = "ALL_TENANTS",
|
||||||
TargetParameters = null,
|
TargetParameters = null,
|
||||||
IsActive = false,
|
|
||||||
RowVersion = new byte[] { 1 }
|
RowVersion = new byte[] { 1 }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,6 @@ public sealed class TenantAnnouncementRepositoryScopeTests
|
|||||||
PublisherScope = PublisherScope.Tenant,
|
PublisherScope = PublisherScope.Tenant,
|
||||||
Status = AnnouncementStatus.Draft,
|
Status = AnnouncementStatus.Draft,
|
||||||
TargetType = "ALL_TENANTS",
|
TargetType = "ALL_TENANTS",
|
||||||
IsActive = false,
|
|
||||||
RowVersion = new byte[] { 1 }
|
RowVersion = new byte[] { 1 }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ public sealed class AnnouncementQueryPerformanceTests
|
|||||||
Status = AnnouncementStatus.Published,
|
Status = AnnouncementStatus.Published,
|
||||||
TargetType = targetType,
|
TargetType = targetType,
|
||||||
TargetParameters = targetParameters,
|
TargetParameters = targetParameters,
|
||||||
IsActive = true,
|
|
||||||
RowVersion = new byte[] { 1 }
|
RowVersion = new byte[] { 1 }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user