This commit is contained in:
owenchen committed 2026-10-21 15:05:55 +08:00
1 parent fd67fa8f63
commit 211d2cd253
31 files changed
+1830 -454

No files matched your search

@@ -275,6 +275,24 @@ namespace CloudBuilder.Master.Service
FamilyGroupPermissionEntity[] permissionEntities = repositoryFamilyGroupPermission.DetachedEntities.Where(x => x.UserName == service.UserId).ToArray();
FamilyFolderFavoriteEntity[] favorites = repositoryFamilyFolderFavorite.DetachedEntities.Where(x => x.UserName == service.UserId).ToArray();
// 管理员权限的唯一出口:本人任管理员的群,所有目录一律有权限(与 FamilyGroupService.FindByKey 管理员视角 IsSharePermission 全 Y 同口径)。
// 权限表只记普通成员的授权记录,管理员不逐目录补录——否则别的管理员建的新目录会漏锁(本接口是共享大厅/文件页/共享目标选择器共用的PermissionIndc判定点)
IRepository<FamilyGroupManagerEntity> repositoryFamilyGroupManager = repository.GetRepository<IRepository<FamilyGroupManagerEntity>>();
string[] managerFamilyNames = repositoryFamilyGroupManager.DetachedEntities
.Where(x => x.UserName == service.UserId && x.ManagerIndc == YesNoPolicy.YES && x.ValidIndc == YesNoPolicy.YES)
.Select(x => x.FamilyName).Distinct().ToArray();
// 群组开启「公开成员目录权限」(open_dir_indc=Y):群内所有目录对所有成员开放,与管理员放行同一出口
string[] memberFamilyNames = repositoryFamilyGroupManager.DetachedEntities
.Where(x => x.UserName == service.UserId && x.ValidIndc == YesNoPolicy.YES)
.Select(x => x.FamilyName).Distinct().ToArray();
IRepository<FamilyGroupEntity> repositoryFamilyGroup = repository.GetRepository<IRepository<FamilyGroupEntity>>();
string[] openDirFamilyNames = memberFamilyNames.Length > 0
? repositoryFamilyGroup.DetachedEntities
.Where(x => x.OpenDirIndc == YesNoPolicy.YES && memberFamilyNames.AsQueryable().Contains(x.FamilyName))
.Select(x => x.FamilyName).ToArray()
: new string[0];
string err = null;
try
{
@@ -293,7 +311,12 @@ namespace CloudBuilder.Master.Service
foreach (var item in list)
{
if (permissionEntities != null && permissionEntities.Length > 0)
if (managerFamilyNames.Contains(item.FamilyName) || openDirFamilyNames.Contains(item.FamilyName))
{
// 管理员 / 群开放全部目录:全目录放行
item.PermissionIndc = YesNoPolicy.YES;
}
else if (permissionEntities != null && permissionEntities.Length > 0)
{
foreach (var p in permissionEntities)
{
@@ -9,6 +9,8 @@ using CloudBuilder.Master.Data;
using CloudBuilder.Core.Service;
using CloudBuilder.Security.Utility;
using CloudBuilder.Security.Service;
using CloudBuilder.Security.Entity;
using CloudBuilder.Security.Policy;
using Microsoft.Extensions.DependencyInjection;
namespace CloudBuilder.Master.Service
{
@@ -33,6 +35,7 @@ namespace CloudBuilder.Master.Service
data.FamilyGroup = familyGroup;
data.IsAdd = familyGroup.AddIndc == YesNoPolicy.YES;
data.IsOpen = familyGroup.OpenIndc == YesNoPolicy.YES;
data.IsOpenDir = familyGroup.OpenDirIndc == YesNoPolicy.YES;
@@ -66,6 +69,13 @@ namespace CloudBuilder.Master.Service
if (users == null || users.Length == 0) return data;
// 成员视图只有用户名/中文名:手机号与头像在 security_user 上,按本群成员用户名集合一次取回
string[] memberUserNames = users.Select(x => x.UserName).Where(x => !string.IsNullOrEmpty(x)).Distinct().ToArray();
IRepository<SecurityUserEntity> repositorySecurityUser = repository.GetRepository<IRepository<SecurityUserEntity>>();
SecurityUserEntity[] memberUsers = memberUserNames.Length > 0
? repositorySecurityUser.DetachedEntities.Where(x => memberUserNames.AsQueryable().Contains(x.UserName)).ToArray()
: new SecurityUserEntity[0];
bool isManager = false;
bool isUser = false;
IRepository<FamilyGroupManagerEntity> repositoryFamilyGroupManager = repository.GetRepository<IRepository<FamilyGroupManagerEntity>>();
@@ -73,7 +83,11 @@ namespace CloudBuilder.Master.Service
if (fgms != null && fgms.Length > 0)
{
data.FamilyGroupManagers = fgms.Select(x => new FamilyGroupManagerDisplayData(x)
{ UserLocalName = users.Where(y => y.UserName == x.UserName).FirstOrDefault()!.UserLocalName }).ToArray();
{
UserLocalName = users.Where(y => y.UserName == x.UserName).FirstOrDefault()!.UserLocalName,
UserMobile = memberUsers.Where(y => y.UserName == x.UserName).FirstOrDefault()?.UserMobile ?? "",
AvatarUrl = FileTypePolicy.PackAvatarUrl(service, UploadFolderPolicy.USER_AVATAR, memberUsers.Where(y => y.UserName == x.UserName).FirstOrDefault()?.UserIconImgPath ?? "") ?? "",
}).ToArray();
//如果不是管理员,则只能看到有权限的目录
@@ -91,19 +105,33 @@ namespace CloudBuilder.Master.Service
IRepository<FamilyGroupPermissionEntity> repositoryFamilyGroupPermission = repository.GetRepository<IRepository<FamilyGroupPermissionEntity>>();
FamilyGroupPermissionEntity[] fgps = repositoryFamilyGroupPermission.DetachedEntities.Where(x => x.FamilyName == key).ToArray();
// 剔除孤儿权限行(目录已删/新建目录尚未拿到编号导致 FolderName 为空):
// 视图按 folder_name 关联不到就取不到目录名,前端也不应再把它提交回来
string[] currentFolderNames = folders.Select(x => x.FolderName).ToArray();
fgps = fgps.Where(x => !string.IsNullOrEmpty(x.FolderName) && currentFolderNames.Contains(x.FolderName)).ToArray();
if (fgps != null && fgps.Length > 0)
{
data.FamilyGroupPermissions = fgps.Select(x => new FamilyGroupPermissionDisplayData(x)
{
UserLocalName = users!.Where(y => y.UserName == x.UserName).FirstOrDefault()!.UserLocalName,
FolderLocalName = ufs!.Where(y => y.UserName == x.UserName && y.FolderName == x.FolderName).FirstOrDefault()!.FolderLocalName
// 人员/目录均可能是历史脏数据(成员已移除、目录已删):兜底回退用户名/目录编号,不再空引用
UserLocalName = users!.Where(y => y.UserName == x.UserName).FirstOrDefault()?.UserLocalName ?? x.UserName,
FolderLocalName = ufs!.Where(y => y.UserName == x.UserName && y.FolderName == x.FolderName).FirstOrDefault()?.FolderLocalName ?? x.FolderName
}).ToArray();
if (!isManager)
{
FamilyGroupPermissionDisplayData[] ps = data.FamilyGroupPermissions.Where(x => x.UserName == service.UserId).ToArray();
if (ps == null || ps.Length == 0)
if (familyGroup.OpenDirIndc == YesNoPolicy.YES)
{
// 公开成员目录权限:所有目录对全体成员开放(与管理员视角、DmsFileService 的 PermissionIndc 同一出口)
data.FamilyGroupFolders = folders!.Select(x => new FamilyGroupFolderDisplayData(x)
{
IsSharePermission = true,
}).ToArray();
}
else if (ps == null || ps.Length == 0)
{
data.FamilyGroupFolders = folders!.Select(x => new FamilyGroupFolderDisplayData(x)
{
@@ -144,7 +172,11 @@ namespace CloudBuilder.Master.Service
fgms = repositoryFamilyGroupManager.DetachedEntities.Where(x => x.FamilyName == key && x.ValidIndc == YesNoPolicy.NO).ToArray();
if (fgms != null && fgms.Length > 0)
data.FamilyGroupRequests = fgms.Select(x => new FamilyGroupManagerDisplayData(x)
{ UserLocalName = users!.Where(y => y.UserName == x.UserName).FirstOrDefault()!.UserLocalName }).ToArray();
{
UserLocalName = users!.Where(y => y.UserName == x.UserName).FirstOrDefault()?.UserLocalName ?? x.UserName,
UserMobile = memberUsers.Where(y => y.UserName == x.UserName).FirstOrDefault()?.UserMobile ?? "",
AvatarUrl = FileTypePolicy.PackAvatarUrl(service, UploadFolderPolicy.USER_AVATAR, memberUsers.Where(y => y.UserName == x.UserName).FirstOrDefault()?.UserIconImgPath ?? "") ?? "",
}).ToArray();
//管理员有分享权限
data.FamilyGroupFolders = folders!.Select(x => new FamilyGroupFolderDisplayData(x)
@@ -159,10 +191,10 @@ namespace CloudBuilder.Master.Service
if (fgms != null && fgms.Length > 0)
{
data.FamilyGroupManagers = fgms.Where(x => x.ValidIndc == YesNoPolicy.YES)!.Select(x => new FamilyGroupManagerDisplayData(x)
{ UserLocalName = users!.Where(y => y.UserName == x.UserName).FirstOrDefault()!.UserLocalName }).ToArray();
{ UserLocalName = users!.Where(y => y.UserName == x.UserName).FirstOrDefault()?.UserLocalName ?? x.UserName }).ToArray();
data.FamilyGroupRequests = fgms.Where(x => x.ValidIndc == YesNoPolicy.NO)!.Select(x => new FamilyGroupManagerDisplayData(x)
{ UserLocalName = users!.Where(y => y.UserName == x.UserName).FirstOrDefault()!.UserLocalName }).ToArray();
{ UserLocalName = users!.Where(y => y.UserName == x.UserName).FirstOrDefault()?.UserLocalName ?? x.UserName }).ToArray();
}
}
@@ -347,6 +379,7 @@ namespace CloudBuilder.Master.Service
familyGroup.AddIndc = data.IsAdd ? YesNoPolicy.YES : YesNoPolicy.NO;
familyGroup.OpenIndc = data.IsOpen ? YesNoPolicy.YES : YesNoPolicy.NO;
familyGroup.OpenDirIndc = data.IsOpenDir ? YesNoPolicy.YES : YesNoPolicy.NO;
repository.InsertNow(familyGroup);
@@ -485,11 +518,18 @@ namespace CloudBuilder.Master.Service
if (permissions == null || permissions.Length == 0) return;
// 本群当前有效目录编号:新建目录在 SaveFamilyGroupFolders 之前还没有编号(FolderName 为空),
// 这种权限行插进去就是查不到目录名的孤儿(旧目录被删后前端残留的同理),一律不落库
IRepository<FamilyGroupFolderEntity> repositoryFamilyGroupFolder = repository.GetRepository<IRepository<FamilyGroupFolderEntity>>();
string[] validFolderNames = repositoryFamilyGroupFolder.Entities.Where(x => x.FamilyName == familyName).Select(x => x.FolderName).ToArray();
foreach (FamilyGroupPermissionEntity dto in permissions)
{
//原来不存在的插入
if (!string.IsNullOrEmpty(dto.CreatedBy)) continue;
if (string.IsNullOrEmpty(dto.FolderName) || !validFolderNames.Contains(dto.FolderName)) continue;
ValidateHelper.Validate(service, dto, FamilyGroupPermissionEntity.DB_NAME_FAMILY_GROUP_PERMISSION);
repositoryFamilyGroupPermission.InsertNow(new FamilyGroupPermissionEntity()
@@ -566,6 +606,7 @@ namespace CloudBuilder.Master.Service
familyGroup.AddIndc = data.IsAdd ? YesNoPolicy.YES : YesNoPolicy.NO;
familyGroup.OpenIndc = data.IsOpen ? YesNoPolicy.YES : YesNoPolicy.NO;
familyGroup.OpenDirIndc = data.IsOpenDir ? YesNoPolicy.YES : YesNoPolicy.NO;
repository.UpdateNow(familyGroup);
@@ -17,6 +17,8 @@ namespace CloudBuilder.Master.Data
public bool IsManager { get; set; } = false;
public bool IsOpen { get; set; } = false;
public bool IsAdd { get; set; } = false;
// 公开成员目录权限:开群组后所有目录对全体成员开放(不再逐目录分配)
public bool IsOpenDir { get; set; } = false;
public FamilyGroupFolderDisplayData[]? FamilyGroupFolders { get; set; }
@@ -29,6 +29,16 @@ namespace CloudBuilder.Master.Data
public const string DB_USER_LOCAL_NAME = "user_local_name";
/// <summary>成员手机号(security_user.user_mobile;成员视图不带,FindByKey 回查用户档案填充)</summary>
public string? UserMobile { get; set; }
public const string USER_MOBILE = "UserMobile";
/// <summary>成员头像访问地址(security_user.user_icon_img_path 经 PackAvatarUrl 拼装;空=未上传,前端占位)</summary>
public string? AvatarUrl { get; set; }
public const string AVATAR_URL = "AvatarUrl";
public const string IS_MANAGER = "IsManager";
public bool IsManager { get; set; }
@@ -117,7 +117,8 @@ builder.Entity<FamilyTreePermissionUserViewEntity>(eb => { eb.HasNoKey(); });
builder.Entity<DmsFileUsageViewEntity>(eb => { eb.HasNoKey(); });
//***END***
//***END***
}
}
}
@@ -14,56 +14,60 @@ namespace CloudBuilder.Master.Entity
{
}
[Column("add_indc")]
public string AddIndc { get; set; }
[Column("created_by")]
public string CreatedBy { get; set; }
[Column("created_datetime")]
public DateTime CreatedDatetime { get; set; }
[Column("expire_datetime")]
public Nullable<DateTime> ExpireDatetime { get; set; }
[Column("family_local_name")]
public string? FamilyLocalName { get; set; }
[Column("created_by")]
public string CreatedBy { get; set; }
[Column("updated_datetime")]
public DateTime UpdatedDatetime { get; set; }
[Column("updated_by")]
public string UpdatedBy { get; set; }
[Key]
[Column("family_name")]
public string FamilyName { get; set; }
[Column("family_local_name")]
public string? FamilyLocalName { get; set; }
[Column("notice")]
public string? Notice { get; set; }
[Column("expire_datetime")]
public Nullable<DateTime> ExpireDatetime { get; set; }
[Column("open_indc")]
public string OpenIndc { get; set; }
[Column("updated_by")]
public string UpdatedBy { get; set; }
[Column("updated_datetime")]
public DateTime UpdatedDatetime { get; set; }
[Column("add_indc")]
public string AddIndc { get; set; }
[Column("valid_indc")]
public string ValidIndc { get; set; }
[Column("open_dir_indc")]
public string? OpenDirIndc { get; set; }
public const string ADD_INDC = "AddIndc";
public const string CREATED_BY = "CreatedBy";
public const string CREATED_DATETIME = "CreatedDatetime";
public const string EXPIRE_DATETIME = "ExpireDatetime";
public const string FAMILY_LOCAL_NAME = "FamilyLocalName";
public const string FAMILY_NAME = "FamilyName";
public const string NOTICE = "Notice";
public const string OPEN_INDC = "OpenIndc";
public const string UPDATED_BY = "UpdatedBy";
public const string CREATED_BY = "CreatedBy";
public const string UPDATED_DATETIME = "UpdatedDatetime";
public const string UPDATED_BY = "UpdatedBy";
public const string FAMILY_NAME = "FamilyName";
public const string FAMILY_LOCAL_NAME = "FamilyLocalName";
public const string NOTICE = "Notice";
public const string EXPIRE_DATETIME = "ExpireDatetime";
public const string OPEN_INDC = "OpenIndc";
public const string ADD_INDC = "AddIndc";
public const string VALID_INDC = "ValidIndc";
public const string OPEN_DIR_INDC = "OpenDirIndc";
public const string DB_NAME_FAMILY_GROUP = "family_group";
public const string DB_NAME_FIELDS="add_indc,created_by,created_datetime,expire_datetime,family_local_name,family_name,notice,open_indc,updated_by,updated_datetime,valid_indc";
public const string DB_NAME_FIELDS="created_datetime,created_by,updated_datetime,updated_by,family_name,family_local_name,notice,expire_datetime,open_indc,add_indc,valid_indc,open_dir_indc";
public const string DB_ADD_INDC = "add_indc";
public const string DB_CREATED_BY = "created_by";
public const string DB_CREATED_DATETIME = "created_datetime";
public const string DB_EXPIRE_DATETIME = "expire_datetime";
public const string DB_FAMILY_LOCAL_NAME = "family_local_name";
public const string DB_FAMILY_NAME = "family_name";
public const string DB_NOTICE = "notice";
public const string DB_OPEN_INDC = "open_indc";
public const string DB_UPDATED_BY = "updated_by";
public const string DB_CREATED_BY = "created_by";
public const string DB_UPDATED_DATETIME = "updated_datetime";
public const string DB_UPDATED_BY = "updated_by";
public const string DB_FAMILY_NAME = "family_name";
public const string DB_FAMILY_LOCAL_NAME = "family_local_name";
public const string DB_NOTICE = "notice";
public const string DB_EXPIRE_DATETIME = "expire_datetime";
public const string DB_OPEN_INDC = "open_indc";
public const string DB_ADD_INDC = "add_indc";
public const string DB_VALID_INDC = "valid_indc";
public const string DB_OPEN_DIR_INDC = "open_dir_indc";
private string ProviderName { get; set; }
@@ -84,24 +88,25 @@ namespace CloudBuilder.Master.Entity
throw new NullReferenceException("Source entity is null.");
}
this.AddIndc = source.AddIndc;
this.CreatedBy = source.CreatedBy;
this.CreatedDatetime = source.CreatedDatetime;
this.ExpireDatetime = source.ExpireDatetime;
this.FamilyLocalName = source.FamilyLocalName;
this.FamilyName = source.FamilyName;
this.Notice = source.Notice;
this.OpenIndc = source.OpenIndc;
this.UpdatedBy = source.UpdatedBy;
this.CreatedBy = source.CreatedBy;
this.UpdatedDatetime = source.UpdatedDatetime;
this.UpdatedBy = source.UpdatedBy;
this.FamilyName = source.FamilyName;
this.FamilyLocalName = source.FamilyLocalName;
this.Notice = source.Notice;
this.ExpireDatetime = source.ExpireDatetime;
this.OpenIndc = source.OpenIndc;
this.AddIndc = source.AddIndc;
this.ValidIndc = source.ValidIndc;
this.OpenDirIndc = source.OpenDirIndc;
if (includeSystemFields)
{
this.CreatedBy = source.CreatedBy;
this.CreatedDatetime = source.CreatedDatetime;
this.UpdatedBy = source.UpdatedBy;
this.CreatedBy = source.CreatedBy;
this.UpdatedDatetime = source.UpdatedDatetime;
this.UpdatedBy = source.UpdatedBy;
}
}