mirror of
https://github.com/kuaifan/dootask.git
synced 2026-03-06 09:27:05 +00:00
feat: 迁移至 MVA 权限方案
- 表结构:为 file/project/task_vectors 添加 allowed_users MULTI 字段 - 删除关系表:file_users, project_users, task_users - 搜索:使用 allowed_users = userid 进行权限过滤 - 同步:sync 时自动计算并写入 allowed_users - 级联:项目成员变更异步级联 v=1 任务,任务成员变更递归更新子任务 - 覆盖场景:visibility/parent_id/project_id 变更、子任务升级主任务等
This commit is contained in:
parent
fdf5ceeaab
commit
c08323e1ea
@ -12,17 +12,16 @@ use Illuminate\Console\Command;
|
||||
class SyncFileToManticore extends Command
|
||||
{
|
||||
/**
|
||||
* 更新数据
|
||||
* 更新数据(MVA 方案:allowed_users 在同步时自动写入)
|
||||
* --f: 全量更新 (默认)
|
||||
* --i: 增量更新(从上次更新的最后一个ID接上)
|
||||
* --u: 仅同步文件用户关系(不同步文件内容)
|
||||
*
|
||||
* 清理数据
|
||||
* --c: 清除索引
|
||||
*/
|
||||
|
||||
protected $signature = 'manticore:sync-files {--f} {--i} {--c} {--u} {--batch=100}';
|
||||
protected $description = '同步文件内容到 Manticore Search';
|
||||
protected $signature = 'manticore:sync-files {--f} {--i} {--c} {--batch=100}';
|
||||
protected $description = '同步文件内容到 Manticore Search(MVA 权限方案)';
|
||||
|
||||
/**
|
||||
* @return int
|
||||
@ -61,47 +60,11 @@ class SyncFileToManticore extends Command
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 仅同步文件用户关系
|
||||
if ($this->option('u')) {
|
||||
$this->info('开始同步文件用户关系...');
|
||||
$count = ManticoreFile::syncAllFileUsers(function ($count) {
|
||||
if ($count % 1000 === 0) {
|
||||
$this->info(" 已同步 {$count} 条关系...");
|
||||
}
|
||||
});
|
||||
$this->info("文件用户关系同步完成,共 {$count} 条");
|
||||
$this->releaseLock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
$this->info('开始同步文件数据...');
|
||||
$this->info('开始同步文件数据(MVA 方案:allowed_users 自动内联)...');
|
||||
|
||||
// 同步文件数据
|
||||
$this->syncFiles();
|
||||
|
||||
// 同步文件用户关系
|
||||
if ($this->option('f') || (!$this->option('i') && !$this->option('u'))) {
|
||||
// 全量同步:清空后重建
|
||||
$this->info("\n全量同步文件用户关系...");
|
||||
$count = ManticoreFile::syncAllFileUsers(function ($count) {
|
||||
if ($count % 1000 === 0) {
|
||||
$this->info(" 已同步 {$count} 条关系...");
|
||||
}
|
||||
});
|
||||
$this->info("文件用户关系同步完成,共 {$count} 条");
|
||||
} elseif ($this->option('i')) {
|
||||
// 增量同步:只同步新增的
|
||||
$this->info("\n增量同步文件用户关系...");
|
||||
$count = ManticoreFile::syncFileUsersIncremental(function ($count) {
|
||||
if ($count % 1000 === 0) {
|
||||
$this->info(" 已同步 {$count} 条关系...");
|
||||
}
|
||||
});
|
||||
if ($count > 0) {
|
||||
$this->info("新增文件用户关系 {$count} 条");
|
||||
}
|
||||
}
|
||||
|
||||
// 完成
|
||||
$this->info("\n同步完成");
|
||||
$this->releaseLock();
|
||||
@ -220,4 +183,3 @@ class SyncFileToManticore extends Command
|
||||
$this->info("已索引文件数量: " . ManticoreFile::getIndexedCount());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -12,17 +12,16 @@ use Illuminate\Console\Command;
|
||||
class SyncProjectToManticore extends Command
|
||||
{
|
||||
/**
|
||||
* 更新数据
|
||||
* 更新数据(MVA 方案:allowed_users 在同步时自动写入)
|
||||
* --f: 全量更新 (默认)
|
||||
* --i: 增量更新(从上次更新的最后一个ID接上)
|
||||
* --u: 仅同步项目成员关系(不同步项目内容)
|
||||
*
|
||||
* 清理数据
|
||||
* --c: 清除索引
|
||||
*/
|
||||
|
||||
protected $signature = 'manticore:sync-projects {--f} {--i} {--c} {--u} {--batch=100}';
|
||||
protected $description = '同步项目数据到 Manticore Search';
|
||||
protected $signature = 'manticore:sync-projects {--f} {--i} {--c} {--batch=100}';
|
||||
protected $description = '同步项目数据到 Manticore Search(MVA 权限方案)';
|
||||
|
||||
/**
|
||||
* @return int
|
||||
@ -59,43 +58,9 @@ class SyncProjectToManticore extends Command
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 仅同步项目成员关系
|
||||
if ($this->option('u')) {
|
||||
$this->info('开始同步项目成员关系...');
|
||||
$count = ManticoreProject::syncAllProjectUsers(function ($count) {
|
||||
if ($count % 1000 === 0) {
|
||||
$this->info(" 已同步 {$count} 条关系...");
|
||||
}
|
||||
});
|
||||
$this->info("项目成员关系同步完成,共 {$count} 条");
|
||||
$this->releaseLock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
$this->info('开始同步项目数据...');
|
||||
$this->info('开始同步项目数据(MVA 方案:allowed_users 自动内联)...');
|
||||
$this->syncProjects();
|
||||
|
||||
// 同步项目成员关系
|
||||
if ($this->option('f') || (!$this->option('i') && !$this->option('u'))) {
|
||||
$this->info("\n全量同步项目成员关系...");
|
||||
$count = ManticoreProject::syncAllProjectUsers(function ($count) {
|
||||
if ($count % 1000 === 0) {
|
||||
$this->info(" 已同步 {$count} 条关系...");
|
||||
}
|
||||
});
|
||||
$this->info("项目成员关系同步完成,共 {$count} 条");
|
||||
} elseif ($this->option('i')) {
|
||||
$this->info("\n增量同步项目成员关系...");
|
||||
$count = ManticoreProject::syncProjectUsersIncremental(function ($count) {
|
||||
if ($count % 1000 === 0) {
|
||||
$this->info(" 已同步 {$count} 条关系...");
|
||||
}
|
||||
});
|
||||
if ($count > 0) {
|
||||
$this->info("新增项目成员关系 {$count} 条");
|
||||
}
|
||||
}
|
||||
|
||||
$this->info("\n同步完成");
|
||||
$this->releaseLock();
|
||||
return 0;
|
||||
@ -178,4 +143,3 @@ class SyncProjectToManticore extends Command
|
||||
$this->info("已索引项目数量: " . ManticoreProject::getIndexedCount());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -12,17 +12,16 @@ use Illuminate\Console\Command;
|
||||
class SyncTaskToManticore extends Command
|
||||
{
|
||||
/**
|
||||
* 更新数据
|
||||
* 更新数据(MVA 方案:allowed_users 在同步时自动写入)
|
||||
* --f: 全量更新 (默认)
|
||||
* --i: 增量更新(从上次更新的最后一个ID接上)
|
||||
* --u: 仅同步任务成员关系(不同步任务内容)
|
||||
*
|
||||
* 清理数据
|
||||
* --c: 清除索引
|
||||
*/
|
||||
|
||||
protected $signature = 'manticore:sync-tasks {--f} {--i} {--c} {--u} {--batch=100}';
|
||||
protected $description = '同步任务数据到 Manticore Search';
|
||||
protected $signature = 'manticore:sync-tasks {--f} {--i} {--c} {--batch=100}';
|
||||
protected $description = '同步任务数据到 Manticore Search(MVA 权限方案)';
|
||||
|
||||
/**
|
||||
* @return int
|
||||
@ -59,43 +58,9 @@ class SyncTaskToManticore extends Command
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 仅同步任务成员关系
|
||||
if ($this->option('u')) {
|
||||
$this->info('开始同步任务成员关系...');
|
||||
$count = ManticoreTask::syncAllTaskUsers(function ($count) {
|
||||
if ($count % 1000 === 0) {
|
||||
$this->info(" 已同步 {$count} 条关系...");
|
||||
}
|
||||
});
|
||||
$this->info("任务成员关系同步完成,共 {$count} 条");
|
||||
$this->releaseLock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
$this->info('开始同步任务数据...');
|
||||
$this->info('开始同步任务数据(MVA 方案:allowed_users 自动内联)...');
|
||||
$this->syncTasks();
|
||||
|
||||
// 同步任务成员关系
|
||||
if ($this->option('f') || (!$this->option('i') && !$this->option('u'))) {
|
||||
$this->info("\n全量同步任务成员关系...");
|
||||
$count = ManticoreTask::syncAllTaskUsers(function ($count) {
|
||||
if ($count % 1000 === 0) {
|
||||
$this->info(" 已同步 {$count} 条关系...");
|
||||
}
|
||||
});
|
||||
$this->info("任务成员关系同步完成,共 {$count} 条");
|
||||
} elseif ($this->option('i')) {
|
||||
$this->info("\n增量同步任务成员关系...");
|
||||
$count = ManticoreTask::syncTaskUsersIncremental(function ($count) {
|
||||
if ($count % 1000 === 0) {
|
||||
$this->info(" 已同步 {$count} 条关系...");
|
||||
}
|
||||
});
|
||||
if ($count > 0) {
|
||||
$this->info("新增任务成员关系 {$count} 条");
|
||||
}
|
||||
}
|
||||
|
||||
$this->info("\n同步完成");
|
||||
$this->releaseLock();
|
||||
return 0;
|
||||
@ -180,4 +145,3 @@ class SyncTaskToManticore extends Command
|
||||
$this->info("已索引任务数量: " . ManticoreTask::getIndexedCount());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -13,7 +13,7 @@ use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* Manticore Search 文件搜索类
|
||||
* Manticore Search 文件搜索类(MVA 权限方案)
|
||||
*
|
||||
* 使用方法:
|
||||
*
|
||||
@ -25,7 +25,10 @@ use Illuminate\Support\Facades\DB;
|
||||
* - 批量同步: batchSync($files);
|
||||
* - 删除索引: delete($fileId);
|
||||
*
|
||||
* 3. 工具方法
|
||||
* 3. 权限更新方法
|
||||
* - 更新权限: updateAllowedUsers($fileId);
|
||||
*
|
||||
* 4. 工具方法
|
||||
* - 清空索引: clear();
|
||||
*/
|
||||
class ManticoreFile
|
||||
@ -204,12 +207,39 @@ class ManticoreFile
|
||||
})->toArray();
|
||||
}
|
||||
|
||||
// ==============================
|
||||
// 权限计算方法(MVA 方案核心)
|
||||
// ==============================
|
||||
|
||||
/**
|
||||
* 获取文件的 allowed_users 列表
|
||||
*
|
||||
* 有权限查看此文件的用户列表:
|
||||
* - 文件所有者 (userid)
|
||||
* - 共享用户(FileUser 表中的 userid)
|
||||
* - userid=0 表示公开共享
|
||||
*
|
||||
* @param File $file 文件模型
|
||||
* @return array 有权限的用户ID数组
|
||||
*/
|
||||
public static function getAllowedUsers(File $file): array
|
||||
{
|
||||
$userids = [$file->userid]; // 所有者
|
||||
|
||||
// 获取共享用户(包括 userid=0 表示公开)
|
||||
$shareUsers = FileUser::where('file_id', $file->id)
|
||||
->pluck('userid')
|
||||
->toArray();
|
||||
|
||||
return array_unique(array_merge($userids, $shareUsers));
|
||||
}
|
||||
|
||||
// ==============================
|
||||
// 同步方法
|
||||
// ==============================
|
||||
|
||||
/**
|
||||
* 同步单个文件到 Manticore
|
||||
* 同步单个文件到 Manticore(含 allowed_users)
|
||||
*
|
||||
* @param File $file 文件模型
|
||||
* @return bool 是否成功
|
||||
@ -248,7 +278,10 @@ class ManticoreFile
|
||||
}
|
||||
}
|
||||
|
||||
// 写入 Manticore
|
||||
// 获取文件的 allowed_users
|
||||
$allowedUsers = self::getAllowedUsers($file);
|
||||
|
||||
// 写入 Manticore(含 allowed_users)
|
||||
$result = ManticoreBase::upsertFileVector([
|
||||
'file_id' => $file->id,
|
||||
'userid' => $file->userid,
|
||||
@ -258,6 +291,7 @@ class ManticoreFile
|
||||
'file_ext' => $file->ext,
|
||||
'content' => $content,
|
||||
'content_vector' => $embedding,
|
||||
'allowed_users' => $allowedUsers,
|
||||
]);
|
||||
|
||||
return $result;
|
||||
@ -414,166 +448,33 @@ class ManticoreFile
|
||||
}
|
||||
|
||||
// ==============================
|
||||
// 文件用户关系同步方法
|
||||
// 权限更新方法(MVA 方案)
|
||||
// ==============================
|
||||
|
||||
/**
|
||||
* 同步单个文件的用户关系到 Manticore
|
||||
* 更新文件的 allowed_users 权限列表
|
||||
* 从 MySQL 获取最新的共享用户并更新到 Manticore
|
||||
*
|
||||
* @param int $fileId 文件ID
|
||||
* @return bool 是否成功
|
||||
*/
|
||||
public static function syncFileUsers(int $fileId): bool
|
||||
public static function updateAllowedUsers(int $fileId): bool
|
||||
{
|
||||
if (!Apps::isInstalled("manticore") || $fileId <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
// 从 MySQL 获取文件的用户关系
|
||||
$users = FileUser::where('file_id', $fileId)
|
||||
->select(['userid', 'permission'])
|
||||
->get()
|
||||
->map(function ($item) {
|
||||
return [
|
||||
'userid' => $item->userid,
|
||||
'permission' => $item->permission,
|
||||
];
|
||||
})
|
||||
->toArray();
|
||||
$file = File::find($fileId);
|
||||
if (!$file) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 同步到 Manticore
|
||||
return ManticoreBase::syncFileUsers($fileId, $users);
|
||||
$userids = self::getAllowedUsers($file);
|
||||
return ManticoreBase::updateFileAllowedUsers($fileId, $userids);
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Manticore syncFileUsers error: ' . $e->getMessage(), ['file_id' => $fileId]);
|
||||
Log::error('Manticore updateAllowedUsers error: ' . $e->getMessage(), ['file_id' => $fileId]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加文件用户关系到 Manticore
|
||||
*
|
||||
* @param int $fileId 文件ID
|
||||
* @param int $userid 用户ID
|
||||
* @param int $permission 权限
|
||||
* @return bool 是否成功
|
||||
*/
|
||||
public static function addFileUser(int $fileId, int $userid, int $permission = 0): bool
|
||||
{
|
||||
if (!Apps::isInstalled("manticore") || $fileId <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ManticoreBase::upsertFileUser($fileId, $userid, $permission);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文件用户关系
|
||||
*
|
||||
* @param int $fileId 文件ID
|
||||
* @param int|null $userid 用户ID,null 表示删除所有
|
||||
* @return bool 是否成功
|
||||
*/
|
||||
public static function removeFileUser(int $fileId, ?int $userid = null): bool
|
||||
{
|
||||
if (!Apps::isInstalled("manticore") || $fileId <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($userid === null) {
|
||||
return ManticoreBase::deleteFileUsers($fileId);
|
||||
}
|
||||
|
||||
return ManticoreBase::deleteFileUser($fileId, $userid);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量同步所有文件用户关系(全量同步)
|
||||
*
|
||||
* @param callable|null $progressCallback 进度回调
|
||||
* @return int 同步数量
|
||||
*/
|
||||
public static function syncAllFileUsers(?callable $progressCallback = null): int
|
||||
{
|
||||
if (!Apps::isInstalled("manticore")) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$count = 0;
|
||||
$lastId = 0;
|
||||
$batchSize = 1000;
|
||||
|
||||
// 先清空 Manticore 中的 file_users 表
|
||||
ManticoreBase::clearAllFileUsers();
|
||||
|
||||
// 分批同步
|
||||
while (true) {
|
||||
$records = FileUser::where('id', '>', $lastId)
|
||||
->orderBy('id')
|
||||
->limit($batchSize)
|
||||
->get();
|
||||
|
||||
if ($records->isEmpty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
foreach ($records as $record) {
|
||||
ManticoreBase::upsertFileUser($record->file_id, $record->userid, $record->permission);
|
||||
$count++;
|
||||
$lastId = $record->id;
|
||||
}
|
||||
|
||||
if ($progressCallback) {
|
||||
$progressCallback($count);
|
||||
}
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 增量同步文件用户关系(只同步新增的)
|
||||
*
|
||||
* @param callable|null $progressCallback 进度回调
|
||||
* @return int 同步数量
|
||||
*/
|
||||
public static function syncFileUsersIncremental(?callable $progressCallback = null): int
|
||||
{
|
||||
if (!Apps::isInstalled("manticore")) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$count = 0;
|
||||
$batchSize = 1000;
|
||||
$lastKey = "sync:manticoreFileUserLastId";
|
||||
$lastId = intval(ManticoreKeyValue::get($lastKey, 0));
|
||||
|
||||
// 分批同步新增的记录
|
||||
while (true) {
|
||||
$records = FileUser::where('id', '>', $lastId)
|
||||
->orderBy('id')
|
||||
->limit($batchSize)
|
||||
->get();
|
||||
|
||||
if ($records->isEmpty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
foreach ($records as $record) {
|
||||
ManticoreBase::upsertFileUser($record->file_id, $record->userid, $record->permission);
|
||||
$count++;
|
||||
$lastId = $record->id;
|
||||
}
|
||||
|
||||
// 保存进度
|
||||
ManticoreKeyValue::set($lastKey, $lastId);
|
||||
|
||||
if ($progressCallback) {
|
||||
$progressCallback($count);
|
||||
}
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ use App\Module\AI;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Manticore Search 项目搜索类
|
||||
* Manticore Search 项目搜索类(MVA 权限方案)
|
||||
*
|
||||
* 使用方法:
|
||||
*
|
||||
@ -22,10 +22,8 @@ use Illuminate\Support\Facades\Log;
|
||||
* - 批量同步: batchSync($projects);
|
||||
* - 删除索引: delete($projectId);
|
||||
*
|
||||
* 3. 成员关系方法
|
||||
* - 添加成员: addProjectUser($projectId, $userid);
|
||||
* - 删除成员: removeProjectUser($projectId, $userid);
|
||||
* - 同步所有成员: syncProjectUsers($projectId);
|
||||
* 3. 权限更新方法
|
||||
* - 更新权限: updateAllowedUsers($projectId);
|
||||
*
|
||||
* 4. 工具方法
|
||||
* - 清空索引: clear();
|
||||
@ -134,7 +132,20 @@ class ManticoreProject
|
||||
// ==============================
|
||||
|
||||
/**
|
||||
* 同步单个项目到 Manticore
|
||||
* 获取项目的 allowed_users 列表
|
||||
*
|
||||
* @param int $projectId 项目ID
|
||||
* @return array 有权限的用户ID数组
|
||||
*/
|
||||
public static function getAllowedUsers(int $projectId): array
|
||||
{
|
||||
return ProjectUser::where('project_id', $projectId)
|
||||
->pluck('userid')
|
||||
->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步单个项目到 Manticore(含 allowed_users)
|
||||
*
|
||||
* @param Project $project 项目模型
|
||||
* @return bool 是否成功
|
||||
@ -163,7 +174,10 @@ class ManticoreProject
|
||||
}
|
||||
}
|
||||
|
||||
// 写入 Manticore
|
||||
// 获取项目成员列表(作为 allowed_users)
|
||||
$allowedUsers = self::getAllowedUsers($project->id);
|
||||
|
||||
// 写入 Manticore(含 allowed_users)
|
||||
$result = ManticoreBase::upsertProjectVector([
|
||||
'project_id' => $project->id,
|
||||
'userid' => $project->userid ?? 0,
|
||||
@ -171,6 +185,7 @@ class ManticoreProject
|
||||
'project_name' => $project->name ?? '',
|
||||
'project_desc' => $project->desc ?? '',
|
||||
'content_vector' => $embedding,
|
||||
'allowed_users' => $allowedUsers,
|
||||
]);
|
||||
|
||||
return $result;
|
||||
@ -236,12 +251,7 @@ class ManticoreProject
|
||||
return false;
|
||||
}
|
||||
|
||||
// 删除项目索引
|
||||
ManticoreBase::deleteProjectVector($projectId);
|
||||
// 删除项目成员关系
|
||||
ManticoreBase::deleteAllProjectUsers($projectId);
|
||||
|
||||
return true;
|
||||
return ManticoreBase::deleteProjectVector($projectId);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -255,10 +265,7 @@ class ManticoreProject
|
||||
return false;
|
||||
}
|
||||
|
||||
ManticoreBase::clearAllProjectVectors();
|
||||
ManticoreBase::clearAllProjectUsers();
|
||||
|
||||
return true;
|
||||
return ManticoreBase::clearAllProjectVectors();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -276,154 +283,28 @@ class ManticoreProject
|
||||
}
|
||||
|
||||
// ==============================
|
||||
// 成员关系方法
|
||||
// 权限更新方法(MVA 方案)
|
||||
// ==============================
|
||||
|
||||
/**
|
||||
* 添加项目成员到 Manticore
|
||||
*
|
||||
* @param int $projectId 项目ID
|
||||
* @param int $userid 用户ID
|
||||
* @return bool 是否成功
|
||||
*/
|
||||
public static function addProjectUser(int $projectId, int $userid): bool
|
||||
{
|
||||
if (!Apps::isInstalled("manticore") || $projectId <= 0 || $userid <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ManticoreBase::upsertProjectUser($projectId, $userid);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除项目成员
|
||||
*
|
||||
* @param int $projectId 项目ID
|
||||
* @param int $userid 用户ID
|
||||
* @return bool 是否成功
|
||||
*/
|
||||
public static function removeProjectUser(int $projectId, int $userid): bool
|
||||
{
|
||||
if (!Apps::isInstalled("manticore") || $projectId <= 0 || $userid <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ManticoreBase::deleteProjectUser($projectId, $userid);
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步项目的所有成员到 Manticore
|
||||
* 更新项目的 allowed_users 权限列表
|
||||
* 从 MySQL 获取最新的项目成员并更新到 Manticore
|
||||
*
|
||||
* @param int $projectId 项目ID
|
||||
* @return bool 是否成功
|
||||
*/
|
||||
public static function syncProjectUsers(int $projectId): bool
|
||||
public static function updateAllowedUsers(int $projectId): bool
|
||||
{
|
||||
if (!Apps::isInstalled("manticore") || $projectId <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
// 从 MySQL 获取项目成员
|
||||
$userids = ProjectUser::where('project_id', $projectId)
|
||||
->pluck('userid')
|
||||
->toArray();
|
||||
|
||||
// 同步到 Manticore
|
||||
return ManticoreBase::syncProjectUsers($projectId, $userids);
|
||||
$userids = self::getAllowedUsers($projectId);
|
||||
return ManticoreBase::updateProjectAllowedUsers($projectId, $userids);
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Manticore syncProjectUsers error: ' . $e->getMessage(), ['project_id' => $projectId]);
|
||||
Log::error('Manticore updateAllowedUsers error: ' . $e->getMessage(), ['project_id' => $projectId]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量同步所有项目成员关系(全量同步)
|
||||
*
|
||||
* @param callable|null $progressCallback 进度回调
|
||||
* @return int 同步数量
|
||||
*/
|
||||
public static function syncAllProjectUsers(?callable $progressCallback = null): int
|
||||
{
|
||||
if (!Apps::isInstalled("manticore")) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$count = 0;
|
||||
$lastId = 0;
|
||||
$batchSize = 1000;
|
||||
|
||||
// 先清空 Manticore 中的 project_users 表
|
||||
ManticoreBase::clearAllProjectUsers();
|
||||
|
||||
// 分批同步
|
||||
while (true) {
|
||||
$records = ProjectUser::where('id', '>', $lastId)
|
||||
->orderBy('id')
|
||||
->limit($batchSize)
|
||||
->get();
|
||||
|
||||
if ($records->isEmpty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
foreach ($records as $record) {
|
||||
ManticoreBase::upsertProjectUser($record->project_id, $record->userid);
|
||||
$count++;
|
||||
$lastId = $record->id;
|
||||
}
|
||||
|
||||
if ($progressCallback) {
|
||||
$progressCallback($count);
|
||||
}
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 增量同步项目成员关系(只同步新增的)
|
||||
*
|
||||
* @param callable|null $progressCallback 进度回调
|
||||
* @return int 同步数量
|
||||
*/
|
||||
public static function syncProjectUsersIncremental(?callable $progressCallback = null): int
|
||||
{
|
||||
if (!Apps::isInstalled("manticore")) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$count = 0;
|
||||
$batchSize = 1000;
|
||||
$lastKey = "sync:manticoreProjectUserLastId";
|
||||
$lastId = intval(ManticoreKeyValue::get($lastKey, 0));
|
||||
|
||||
// 分批同步新增的记录
|
||||
while (true) {
|
||||
$records = ProjectUser::where('id', '>', $lastId)
|
||||
->orderBy('id')
|
||||
->limit($batchSize)
|
||||
->get();
|
||||
|
||||
if ($records->isEmpty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
foreach ($records as $record) {
|
||||
ManticoreBase::upsertProjectUser($record->project_id, $record->userid);
|
||||
$count++;
|
||||
$lastId = $record->id;
|
||||
}
|
||||
|
||||
// 保存进度
|
||||
ManticoreKeyValue::set($lastKey, $lastId);
|
||||
|
||||
if ($progressCallback) {
|
||||
$progressCallback($count);
|
||||
}
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -6,18 +6,20 @@ use App\Models\ProjectTask;
|
||||
use App\Models\ProjectTaskContent;
|
||||
use App\Models\ProjectTaskUser;
|
||||
use App\Models\ProjectTaskVisibilityUser;
|
||||
use App\Models\ProjectUser;
|
||||
use App\Module\Apps;
|
||||
use App\Module\Base;
|
||||
use App\Module\AI;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Manticore Search 任务搜索类
|
||||
* Manticore Search 任务搜索类(MVA 权限方案)
|
||||
*
|
||||
* 权限逻辑说明:
|
||||
* - visibility = 1: 项目人员可见,通过 project_users 表过滤
|
||||
* - visibility = 2: 任务人员可见,通过 task_users 表过滤(ProjectTaskUser)
|
||||
* - visibility = 3: 指定成员可见,通过 task_users 表过滤(ProjectTaskUser + ProjectTaskVisibilityUser)
|
||||
* - visibility = 1: 项目人员可见,通过项目成员计算 allowed_users
|
||||
* - visibility = 2: 任务人员可见,通过任务成员计算 allowed_users
|
||||
* - visibility = 3: 指定成员可见,通过任务成员 + 可见性成员计算 allowed_users
|
||||
* - 子任务继承父任务的 allowed_users
|
||||
*
|
||||
* 使用方法:
|
||||
*
|
||||
@ -29,10 +31,10 @@ use Illuminate\Support\Facades\Log;
|
||||
* - 批量同步: batchSync($tasks);
|
||||
* - 删除索引: delete($taskId);
|
||||
*
|
||||
* 3. 成员关系方法
|
||||
* - 添加成员: addTaskUser($taskId, $userid);
|
||||
* - 删除成员: removeTaskUser($taskId, $userid);
|
||||
* - 同步所有成员: syncTaskUsers($taskId);
|
||||
* 3. 权限更新方法
|
||||
* - 更新权限: updateAllowedUsers($taskId);
|
||||
* - 项目成员变更级联更新: cascadeUpdateByProject($projectId);
|
||||
* - 父任务变更级联到子任务: cascadeToChildren($taskId);
|
||||
*
|
||||
* 4. 工具方法
|
||||
* - 清空索引: clear();
|
||||
@ -143,12 +145,66 @@ class ManticoreTask
|
||||
return $formatted;
|
||||
}
|
||||
|
||||
// ==============================
|
||||
// 权限计算方法(MVA 方案核心)
|
||||
// ==============================
|
||||
|
||||
/**
|
||||
* 获取任务的 allowed_users 列表
|
||||
*
|
||||
* 根据 visibility 计算有权限查看此任务的用户列表:
|
||||
* - visibility=1: 项目成员
|
||||
* - visibility=2: 任务成员(负责人/协作人)
|
||||
* - visibility=3: 任务成员 + 可见性指定成员
|
||||
* - 子任务: 还需要继承父任务的成员
|
||||
*
|
||||
* @param ProjectTask $task 任务模型
|
||||
* @return array 有权限的用户ID数组
|
||||
*/
|
||||
public static function getAllowedUsers(ProjectTask $task): array
|
||||
{
|
||||
$userids = [];
|
||||
|
||||
// 1. 根据 visibility 获取基础成员
|
||||
if ($task->visibility == 1) {
|
||||
// visibility=1: 项目成员
|
||||
$userids = ProjectUser::where('project_id', $task->project_id)
|
||||
->pluck('userid')
|
||||
->toArray();
|
||||
} else {
|
||||
// visibility=2,3: 任务成员(负责人/协作人)
|
||||
$userids = ProjectTaskUser::where('task_id', $task->id)
|
||||
->orWhere('task_pid', $task->id)
|
||||
->pluck('userid')
|
||||
->toArray();
|
||||
|
||||
// visibility=3: 加上可见性指定成员
|
||||
if ($task->visibility == 3) {
|
||||
$visUsers = ProjectTaskVisibilityUser::where('task_id', $task->id)
|
||||
->pluck('userid')
|
||||
->toArray();
|
||||
$userids = array_merge($userids, $visUsers);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 如果是子任务,继承父任务成员
|
||||
if ($task->parent_id > 0) {
|
||||
$parentTask = ProjectTask::find($task->parent_id);
|
||||
if ($parentTask) {
|
||||
$parentUsers = self::getAllowedUsers($parentTask);
|
||||
$userids = array_merge($userids, $parentUsers);
|
||||
}
|
||||
}
|
||||
|
||||
return array_unique($userids);
|
||||
}
|
||||
|
||||
// ==============================
|
||||
// 同步方法
|
||||
// ==============================
|
||||
|
||||
/**
|
||||
* 同步单个任务到 Manticore
|
||||
* 同步单个任务到 Manticore(含 allowed_users)
|
||||
*
|
||||
* @param ProjectTask $task 任务模型
|
||||
* @return bool 是否成功
|
||||
@ -180,7 +236,10 @@ class ManticoreTask
|
||||
}
|
||||
}
|
||||
|
||||
// 写入 Manticore
|
||||
// 获取任务的 allowed_users
|
||||
$allowedUsers = self::getAllowedUsers($task);
|
||||
|
||||
// 写入 Manticore(含 allowed_users)
|
||||
$result = ManticoreBase::upsertTaskVector([
|
||||
'task_id' => $task->id,
|
||||
'project_id' => $task->project_id ?? 0,
|
||||
@ -190,6 +249,7 @@ class ManticoreTask
|
||||
'task_desc' => $task->desc ?? '',
|
||||
'task_content' => $taskContent,
|
||||
'content_vector' => $embedding,
|
||||
'allowed_users' => $allowedUsers,
|
||||
]);
|
||||
|
||||
return $result;
|
||||
@ -322,28 +382,7 @@ class ManticoreTask
|
||||
return false;
|
||||
}
|
||||
|
||||
// 删除任务索引
|
||||
ManticoreBase::deleteTaskVector($taskId);
|
||||
// 删除任务成员关系
|
||||
ManticoreBase::deleteAllTaskUsers($taskId);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新任务可见性
|
||||
*
|
||||
* @param int $taskId 任务ID
|
||||
* @param int $visibility 可见性
|
||||
* @return bool 是否成功
|
||||
*/
|
||||
public static function updateVisibility(int $taskId, int $visibility): bool
|
||||
{
|
||||
if (!Apps::isInstalled("manticore") || $taskId <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ManticoreBase::updateTaskVisibility($taskId, $visibility);
|
||||
return ManticoreBase::deleteTaskVector($taskId);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -357,10 +396,7 @@ class ManticoreTask
|
||||
return false;
|
||||
}
|
||||
|
||||
ManticoreBase::clearAllTaskVectors();
|
||||
ManticoreBase::clearAllTaskUsers();
|
||||
|
||||
return true;
|
||||
return ManticoreBase::clearAllTaskVectors();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -378,269 +414,110 @@ class ManticoreTask
|
||||
}
|
||||
|
||||
// ==============================
|
||||
// 成员关系方法
|
||||
// 权限更新方法(MVA 方案)
|
||||
// ==============================
|
||||
|
||||
/**
|
||||
* 添加任务成员到 Manticore
|
||||
*
|
||||
* @param int $taskId 任务ID
|
||||
* @param int $userid 用户ID
|
||||
* @return bool 是否成功
|
||||
*/
|
||||
public static function addTaskUser(int $taskId, int $userid): bool
|
||||
{
|
||||
if (!Apps::isInstalled("manticore") || $taskId <= 0 || $userid <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ManticoreBase::upsertTaskUser($taskId, $userid);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除任务成员
|
||||
*
|
||||
* @param int $taskId 任务ID
|
||||
* @param int $userid 用户ID
|
||||
* @return bool 是否成功
|
||||
*/
|
||||
public static function removeTaskUser(int $taskId, int $userid): bool
|
||||
{
|
||||
if (!Apps::isInstalled("manticore") || $taskId <= 0 || $userid <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ManticoreBase::deleteTaskUser($taskId, $userid);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除指定可见成员(visibility=3 场景)
|
||||
*
|
||||
* 特殊处理:需要检查该用户是否仍是任务的负责人/协作人
|
||||
* 如果是,则不应该从 task_users 中删除
|
||||
*
|
||||
* @param int $taskId 任务ID
|
||||
* @param int $userid 用户ID
|
||||
* @return bool 是否成功
|
||||
*/
|
||||
public static function removeVisibilityUser(int $taskId, int $userid): bool
|
||||
{
|
||||
if (!Apps::isInstalled("manticore") || $taskId <= 0 || $userid <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
// 检查用户是否仍是任务的负责人/协作人
|
||||
$isTaskMember = ProjectTaskUser::where('task_id', $taskId)
|
||||
->where('userid', $userid)
|
||||
->exists();
|
||||
|
||||
// 检查是否是父任务的成员(子任务场景)
|
||||
$task = \App\Models\ProjectTask::find($taskId);
|
||||
$isParentTaskMember = false;
|
||||
if ($task && $task->parent_id > 0) {
|
||||
$isParentTaskMember = ProjectTaskUser::where('task_id', $task->parent_id)
|
||||
->where('userid', $userid)
|
||||
->exists();
|
||||
}
|
||||
|
||||
// 如果仍是任务成员,不删除
|
||||
if ($isTaskMember || $isParentTaskMember) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 从 Manticore 删除
|
||||
return ManticoreBase::deleteTaskUser($taskId, $userid);
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Manticore removeVisibilityUser error: ' . $e->getMessage(), [
|
||||
'task_id' => $taskId,
|
||||
'userid' => $userid,
|
||||
]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步任务的所有成员到 Manticore
|
||||
*
|
||||
* 包括:ProjectTaskUser 和 ProjectTaskVisibilityUser
|
||||
* 更新任务的 allowed_users 权限列表
|
||||
* 重新计算并更新 Manticore 中的权限
|
||||
*
|
||||
* @param int $taskId 任务ID
|
||||
* @return bool 是否成功
|
||||
*/
|
||||
public static function syncTaskUsers(int $taskId): bool
|
||||
public static function updateAllowedUsers(int $taskId): bool
|
||||
{
|
||||
if (!Apps::isInstalled("manticore") || $taskId <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
// 获取任务成员(负责人/协作人)
|
||||
$taskUserIds = ProjectTaskUser::where('task_id', $taskId)
|
||||
->orWhere('task_pid', $taskId)
|
||||
->pluck('userid')
|
||||
->toArray();
|
||||
$task = ProjectTask::find($taskId);
|
||||
if (!$task) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取可见性指定成员
|
||||
$visibilityUserIds = ProjectTaskVisibilityUser::where('task_id', $taskId)
|
||||
->pluck('userid')
|
||||
->toArray();
|
||||
|
||||
// 合并去重
|
||||
$allUserIds = array_unique(array_merge($taskUserIds, $visibilityUserIds));
|
||||
|
||||
// 同步到 Manticore
|
||||
return ManticoreBase::syncTaskUsers($taskId, $allUserIds);
|
||||
$userids = self::getAllowedUsers($task);
|
||||
return ManticoreBase::updateTaskAllowedUsers($taskId, $userids);
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Manticore syncTaskUsers error: ' . $e->getMessage(), ['task_id' => $taskId]);
|
||||
Log::error('Manticore updateAllowedUsers error: ' . $e->getMessage(), ['task_id' => $taskId]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量同步所有任务成员关系(全量同步)
|
||||
* 级联更新项目下所有 visibility=1 任务的 allowed_users
|
||||
* 当项目成员变更时调用(异步执行)
|
||||
*
|
||||
* @param callable|null $progressCallback 进度回调
|
||||
* @return int 同步数量
|
||||
* @param int $projectId 项目ID
|
||||
* @return int 更新的任务数量
|
||||
*/
|
||||
public static function syncAllTaskUsers(?callable $progressCallback = null): int
|
||||
public static function cascadeUpdateByProject(int $projectId): int
|
||||
{
|
||||
if (!Apps::isInstalled("manticore")) {
|
||||
if (!Apps::isInstalled("manticore") || $projectId <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$count = 0;
|
||||
$lastId = 0;
|
||||
$batchSize = 1000;
|
||||
try {
|
||||
// 获取项目成员
|
||||
$projectUsers = ProjectUser::where('project_id', $projectId)
|
||||
->pluck('userid')
|
||||
->toArray();
|
||||
|
||||
// 先清空 Manticore 中的 task_users 表
|
||||
ManticoreBase::clearAllTaskUsers();
|
||||
// 分批更新该项目下所有 visibility=1 的任务
|
||||
$count = 0;
|
||||
ProjectTask::where('project_id', $projectId)
|
||||
->where('visibility', 1)
|
||||
->whereNull('deleted_at')
|
||||
->whereNull('archived_at')
|
||||
->chunk(100, function ($tasks) use ($projectUsers, &$count) {
|
||||
foreach ($tasks as $task) {
|
||||
// 对于子任务,需要合并父任务成员
|
||||
$allowedUsers = $projectUsers;
|
||||
if ($task->parent_id > 0) {
|
||||
$parentTask = ProjectTask::find($task->parent_id);
|
||||
if ($parentTask) {
|
||||
$parentUsers = self::getAllowedUsers($parentTask);
|
||||
$allowedUsers = array_unique(array_merge($allowedUsers, $parentUsers));
|
||||
}
|
||||
}
|
||||
|
||||
ManticoreBase::updateTaskAllowedUsers($task->id, $allowedUsers);
|
||||
$count++;
|
||||
}
|
||||
});
|
||||
|
||||
// 同步 ProjectTaskUser
|
||||
while (true) {
|
||||
$records = ProjectTaskUser::where('id', '>', $lastId)
|
||||
->orderBy('id')
|
||||
->limit($batchSize)
|
||||
->get();
|
||||
|
||||
if ($records->isEmpty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
foreach ($records as $record) {
|
||||
ManticoreBase::upsertTaskUser($record->task_id, $record->userid);
|
||||
// 如果有父任务,也添加到父任务
|
||||
if ($record->task_pid) {
|
||||
ManticoreBase::upsertTaskUser($record->task_pid, $record->userid);
|
||||
}
|
||||
$count++;
|
||||
$lastId = $record->id;
|
||||
}
|
||||
|
||||
if ($progressCallback) {
|
||||
$progressCallback($count);
|
||||
}
|
||||
return $count;
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Manticore cascadeUpdateByProject error: ' . $e->getMessage(), ['project_id' => $projectId]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 同步 ProjectTaskVisibilityUser
|
||||
$lastId = 0;
|
||||
while (true) {
|
||||
$records = ProjectTaskVisibilityUser::where('id', '>', $lastId)
|
||||
->orderBy('id')
|
||||
->limit($batchSize)
|
||||
->get();
|
||||
|
||||
if ($records->isEmpty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
foreach ($records as $record) {
|
||||
ManticoreBase::upsertTaskUser($record->task_id, $record->userid);
|
||||
$count++;
|
||||
$lastId = $record->id;
|
||||
}
|
||||
|
||||
if ($progressCallback) {
|
||||
$progressCallback($count);
|
||||
}
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 增量同步任务成员关系(只同步新增的)
|
||||
* 级联更新所有子任务的 allowed_users
|
||||
* 当父任务的成员变更时调用
|
||||
*
|
||||
* @param callable|null $progressCallback 进度回调
|
||||
* @return int 同步数量
|
||||
* @param int $taskId 父任务ID
|
||||
* @return void
|
||||
*/
|
||||
public static function syncTaskUsersIncremental(?callable $progressCallback = null): int
|
||||
public static function cascadeToChildren(int $taskId): void
|
||||
{
|
||||
if (!Apps::isInstalled("manticore")) {
|
||||
return 0;
|
||||
if (!Apps::isInstalled("manticore") || $taskId <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$count = 0;
|
||||
$batchSize = 1000;
|
||||
|
||||
// 同步 ProjectTaskUser 新增
|
||||
$lastKey1 = "sync:manticoreTaskUserLastId";
|
||||
$lastId1 = intval(ManticoreKeyValue::get($lastKey1, 0));
|
||||
|
||||
while (true) {
|
||||
$records = ProjectTaskUser::where('id', '>', $lastId1)
|
||||
->orderBy('id')
|
||||
->limit($batchSize)
|
||||
->get();
|
||||
|
||||
if ($records->isEmpty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
foreach ($records as $record) {
|
||||
ManticoreBase::upsertTaskUser($record->task_id, $record->userid);
|
||||
if ($record->task_pid) {
|
||||
ManticoreBase::upsertTaskUser($record->task_pid, $record->userid);
|
||||
}
|
||||
$count++;
|
||||
$lastId1 = $record->id;
|
||||
}
|
||||
|
||||
ManticoreKeyValue::set($lastKey1, $lastId1);
|
||||
|
||||
if ($progressCallback) {
|
||||
$progressCallback($count);
|
||||
}
|
||||
try {
|
||||
ProjectTask::where('parent_id', $taskId)
|
||||
->whereNull('deleted_at')
|
||||
->whereNull('archived_at')
|
||||
->each(function ($child) {
|
||||
$allowedUsers = self::getAllowedUsers($child);
|
||||
ManticoreBase::updateTaskAllowedUsers($child->id, $allowedUsers);
|
||||
// 递归处理子任务的子任务
|
||||
self::cascadeToChildren($child->id);
|
||||
});
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Manticore cascadeToChildren error: ' . $e->getMessage(), ['task_id' => $taskId]);
|
||||
}
|
||||
|
||||
// 同步 ProjectTaskVisibilityUser 新增
|
||||
$lastKey2 = "sync:manticoreTaskVisibilityUserLastId";
|
||||
$lastId2 = intval(ManticoreKeyValue::get($lastKey2, 0));
|
||||
|
||||
while (true) {
|
||||
$records = ProjectTaskVisibilityUser::where('id', '>', $lastId2)
|
||||
->orderBy('id')
|
||||
->limit($batchSize)
|
||||
->get();
|
||||
|
||||
if ($records->isEmpty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
foreach ($records as $record) {
|
||||
ManticoreBase::upsertTaskUser($record->task_id, $record->userid);
|
||||
$count++;
|
||||
$lastId2 = $record->id;
|
||||
}
|
||||
|
||||
ManticoreKeyValue::set($lastKey2, $lastId2);
|
||||
|
||||
if ($progressCallback) {
|
||||
$progressCallback($count);
|
||||
}
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -5,6 +5,9 @@ namespace App\Observers;
|
||||
use App\Models\FileUser;
|
||||
use App\Tasks\ManticoreSyncTask;
|
||||
|
||||
/**
|
||||
* FileUser 观察者(MVA 权限方案)
|
||||
*/
|
||||
class FileUserObserver extends AbstractObserver
|
||||
{
|
||||
/**
|
||||
@ -15,10 +18,9 @@ class FileUserObserver extends AbstractObserver
|
||||
*/
|
||||
public function created(FileUser $fileUser)
|
||||
{
|
||||
self::taskDeliver(new ManticoreSyncTask('file_user_add', [
|
||||
// MVA 方案:更新文件的 allowed_users
|
||||
self::taskDeliver(new ManticoreSyncTask('update_file_allowed_users', [
|
||||
'file_id' => $fileUser->file_id,
|
||||
'userid' => $fileUser->userid,
|
||||
'permission' => $fileUser->permission,
|
||||
]));
|
||||
}
|
||||
|
||||
@ -30,10 +32,9 @@ class FileUserObserver extends AbstractObserver
|
||||
*/
|
||||
public function updated(FileUser $fileUser)
|
||||
{
|
||||
self::taskDeliver(new ManticoreSyncTask('file_user_add', [
|
||||
// MVA 方案:更新文件的 allowed_users
|
||||
self::taskDeliver(new ManticoreSyncTask('update_file_allowed_users', [
|
||||
'file_id' => $fileUser->file_id,
|
||||
'userid' => $fileUser->userid,
|
||||
'permission' => $fileUser->permission,
|
||||
]));
|
||||
}
|
||||
|
||||
@ -45,10 +46,9 @@ class FileUserObserver extends AbstractObserver
|
||||
*/
|
||||
public function deleted(FileUser $fileUser)
|
||||
{
|
||||
self::taskDeliver(new ManticoreSyncTask('file_user_remove', [
|
||||
// MVA 方案:更新文件的 allowed_users
|
||||
self::taskDeliver(new ManticoreSyncTask('update_file_allowed_users', [
|
||||
'file_id' => $fileUser->file_id,
|
||||
'userid' => $fileUser->userid,
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -32,11 +32,6 @@ class ProjectTaskObserver extends AbstractObserver
|
||||
{
|
||||
if ($projectTask->isDirty('visibility')) {
|
||||
self::visibilityUpdate($projectTask);
|
||||
// 同步 visibility 变化到 Manticore
|
||||
self::taskDeliver(new ManticoreSyncTask('task_visibility_update', [
|
||||
'task_id' => $projectTask->id,
|
||||
'visibility' => $projectTask->visibility,
|
||||
]));
|
||||
}
|
||||
if ($projectTask->isDirty('archived_at')) {
|
||||
if ($projectTask->archived_at) {
|
||||
@ -46,9 +41,11 @@ class ProjectTaskObserver extends AbstractObserver
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否有搜索相关字段变化
|
||||
// project_id 变化时也需要同步(任务移动到其他项目)
|
||||
$searchableFields = ['name', 'desc', 'archived_at', 'project_id'];
|
||||
// MVA 方案:检查是否有搜索相关字段变化或权限相关字段变化
|
||||
// visibility 变化会影响 allowed_users 来源
|
||||
// parent_id 变化会影响子任务继承
|
||||
// project_id 变化会影响 visibility=1 的任务权限
|
||||
$searchableFields = ['name', 'desc', 'archived_at', 'project_id', 'visibility', 'parent_id'];
|
||||
$isDirty = false;
|
||||
foreach ($searchableFields as $field) {
|
||||
if ($projectTask->isDirty($field)) {
|
||||
@ -61,6 +58,7 @@ class ProjectTaskObserver extends AbstractObserver
|
||||
if ($projectTask->archived_at) {
|
||||
self::taskDeliver(new ManticoreSyncTask('task_delete', ['task_id' => $projectTask->id]));
|
||||
} else {
|
||||
// 重新同步任务(会重新计算 allowed_users)
|
||||
self::taskDeliver(new ManticoreSyncTask('task_sync', $projectTask->toArray()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,16 +22,14 @@ class ProjectTaskUserObserver extends AbstractObserver
|
||||
Deleted::forget('projectTask', $projectTaskUser->task_pid, $projectTaskUser->userid);
|
||||
}
|
||||
|
||||
// 同步任务成员到 Manticore
|
||||
self::taskDeliver(new ManticoreSyncTask('task_user_add', [
|
||||
// MVA 方案:更新任务的 allowed_users(会自动 cascadeToChildren)
|
||||
self::taskDeliver(new ManticoreSyncTask('update_task_allowed_users', [
|
||||
'task_id' => $projectTaskUser->task_id,
|
||||
'userid' => $projectTaskUser->userid,
|
||||
]));
|
||||
// 如果是子任务,同时添加到父任务
|
||||
// 如果是子任务,也更新父任务
|
||||
if ($projectTaskUser->task_pid) {
|
||||
self::taskDeliver(new ManticoreSyncTask('task_user_add', [
|
||||
self::taskDeliver(new ManticoreSyncTask('update_task_allowed_users', [
|
||||
'task_id' => $projectTaskUser->task_pid,
|
||||
'userid' => $projectTaskUser->userid,
|
||||
]));
|
||||
}
|
||||
}
|
||||
@ -59,10 +57,9 @@ class ProjectTaskUserObserver extends AbstractObserver
|
||||
Deleted::record('projectTask', $projectTaskUser->task_id, $projectTaskUser->userid);
|
||||
}
|
||||
|
||||
// 从 Manticore 删除任务成员关系
|
||||
self::taskDeliver(new ManticoreSyncTask('task_user_remove', [
|
||||
// MVA 方案:更新任务的 allowed_users(会自动 cascadeToChildren)
|
||||
self::taskDeliver(new ManticoreSyncTask('update_task_allowed_users', [
|
||||
'task_id' => $projectTaskUser->task_id,
|
||||
'userid' => $projectTaskUser->userid,
|
||||
]));
|
||||
}
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ use App\Models\ProjectTaskVisibilityUser;
|
||||
use App\Tasks\ManticoreSyncTask;
|
||||
|
||||
/**
|
||||
* ProjectTaskVisibilityUser 观察者
|
||||
* ProjectTaskVisibilityUser 观察者(MVA 权限方案)
|
||||
*
|
||||
* 用于处理任务 visibility=3(指定成员可见)时的成员变更同步
|
||||
*/
|
||||
@ -20,10 +20,9 @@ class ProjectTaskVisibilityUserObserver extends AbstractObserver
|
||||
*/
|
||||
public function created(ProjectTaskVisibilityUser $visibilityUser)
|
||||
{
|
||||
// 将指定成员添加到 Manticore 的 task_users 表
|
||||
self::taskDeliver(new ManticoreSyncTask('task_user_add', [
|
||||
// MVA 方案:更新任务的 allowed_users(会自动 cascadeToChildren)
|
||||
self::taskDeliver(new ManticoreSyncTask('update_task_allowed_users', [
|
||||
'task_id' => $visibilityUser->task_id,
|
||||
'userid' => $visibilityUser->userid,
|
||||
]));
|
||||
}
|
||||
|
||||
@ -35,10 +34,9 @@ class ProjectTaskVisibilityUserObserver extends AbstractObserver
|
||||
*/
|
||||
public function updated(ProjectTaskVisibilityUser $visibilityUser)
|
||||
{
|
||||
// 通常不会更新,但如果更新了也同步
|
||||
self::taskDeliver(new ManticoreSyncTask('task_user_add', [
|
||||
// MVA 方案:更新任务的 allowed_users(会自动 cascadeToChildren)
|
||||
self::taskDeliver(new ManticoreSyncTask('update_task_allowed_users', [
|
||||
'task_id' => $visibilityUser->task_id,
|
||||
'userid' => $visibilityUser->userid,
|
||||
]));
|
||||
}
|
||||
|
||||
@ -50,12 +48,9 @@ class ProjectTaskVisibilityUserObserver extends AbstractObserver
|
||||
*/
|
||||
public function deleted(ProjectTaskVisibilityUser $visibilityUser)
|
||||
{
|
||||
// 从 Manticore 的 task_users 表删除该成员
|
||||
// 注意:需要检查该用户是否仍是任务的负责人/协作人
|
||||
// 如果是,则不应该删除(因为 ProjectTaskUser 仍存在)
|
||||
self::taskDeliver(new ManticoreSyncTask('task_visibility_user_remove', [
|
||||
// MVA 方案:更新任务的 allowed_users(会自动 cascadeToChildren)
|
||||
self::taskDeliver(new ManticoreSyncTask('update_task_allowed_users', [
|
||||
'task_id' => $visibilityUser->task_id,
|
||||
'userid' => $visibilityUser->userid,
|
||||
]));
|
||||
}
|
||||
|
||||
@ -81,4 +76,3 @@ class ProjectTaskVisibilityUserObserver extends AbstractObserver
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -17,9 +17,14 @@ class ProjectUserObserver extends AbstractObserver
|
||||
public function created(ProjectUser $projectUser)
|
||||
{
|
||||
Deleted::forget('project', $projectUser->project_id, $projectUser->userid);
|
||||
self::taskDeliver(new ManticoreSyncTask('project_user_add', [
|
||||
|
||||
// MVA 方案:更新项目的 allowed_users
|
||||
self::taskDeliver(new ManticoreSyncTask('update_project_allowed_users', [
|
||||
'project_id' => $projectUser->project_id,
|
||||
]));
|
||||
// 异步级联更新该项目下所有 visibility=1 的任务
|
||||
self::taskDeliver(new ManticoreSyncTask('cascade_project_users', [
|
||||
'project_id' => $projectUser->project_id,
|
||||
'userid' => $projectUser->userid,
|
||||
]));
|
||||
}
|
||||
|
||||
@ -43,9 +48,14 @@ class ProjectUserObserver extends AbstractObserver
|
||||
public function deleted(ProjectUser $projectUser)
|
||||
{
|
||||
Deleted::record('project', $projectUser->project_id, $projectUser->userid);
|
||||
self::taskDeliver(new ManticoreSyncTask('project_user_remove', [
|
||||
|
||||
// MVA 方案:更新项目的 allowed_users
|
||||
self::taskDeliver(new ManticoreSyncTask('update_project_allowed_users', [
|
||||
'project_id' => $projectUser->project_id,
|
||||
]));
|
||||
// 异步级联更新该项目下所有 visibility=1 的任务
|
||||
self::taskDeliver(new ManticoreSyncTask('cascade_project_users', [
|
||||
'project_id' => $projectUser->project_id,
|
||||
'userid' => $projectUser->userid,
|
||||
]));
|
||||
}
|
||||
|
||||
|
||||
@ -16,9 +16,10 @@ use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
/**
|
||||
* 通用 Manticore Search 同步任务
|
||||
* 通用 Manticore Search 同步任务(MVA 权限方案)
|
||||
*
|
||||
* 支持文件、用户、项目、任务的同步操作
|
||||
* 使用 MVA (Multi-Value Attribute) 内联权限过滤
|
||||
*/
|
||||
class ManticoreSyncTask extends AbstractTask
|
||||
{
|
||||
@ -57,30 +58,6 @@ class ManticoreSyncTask extends AbstractTask
|
||||
}
|
||||
break;
|
||||
|
||||
case 'file_user_sync':
|
||||
$fileId = $this->data['file_id'] ?? 0;
|
||||
if ($fileId > 0) {
|
||||
ManticoreFile::syncFileUsers($fileId);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'file_user_add':
|
||||
$fileId = $this->data['file_id'] ?? 0;
|
||||
$userid = $this->data['userid'] ?? 0;
|
||||
$permission = $this->data['permission'] ?? 0;
|
||||
if ($fileId > 0) {
|
||||
ManticoreFile::addFileUser($fileId, $userid, $permission);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'file_user_remove':
|
||||
$fileId = $this->data['file_id'] ?? 0;
|
||||
$userid = $this->data['userid'] ?? null;
|
||||
if ($fileId > 0) {
|
||||
ManticoreFile::removeFileUser($fileId, $userid);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'file_pshare_update':
|
||||
$fileIds = $this->data['file_ids'] ?? [];
|
||||
$pshare = $this->data['pshare'] ?? 0;
|
||||
@ -89,6 +66,14 @@ class ManticoreSyncTask extends AbstractTask
|
||||
}
|
||||
break;
|
||||
|
||||
case 'update_file_allowed_users':
|
||||
// 更新文件的 allowed_users(共享变更时调用)
|
||||
$fileId = $this->data['file_id'] ?? 0;
|
||||
if ($fileId > 0) {
|
||||
ManticoreFile::updateAllowedUsers($fileId);
|
||||
}
|
||||
break;
|
||||
|
||||
// ==============================
|
||||
// 用户同步动作
|
||||
// ==============================
|
||||
@ -123,26 +108,20 @@ class ManticoreSyncTask extends AbstractTask
|
||||
}
|
||||
break;
|
||||
|
||||
case 'project_user_add':
|
||||
$projectId = $this->data['project_id'] ?? 0;
|
||||
$userid = $this->data['userid'] ?? 0;
|
||||
if ($projectId > 0 && $userid > 0) {
|
||||
ManticoreProject::addProjectUser($projectId, $userid);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'project_user_remove':
|
||||
$projectId = $this->data['project_id'] ?? 0;
|
||||
$userid = $this->data['userid'] ?? 0;
|
||||
if ($projectId > 0 && $userid > 0) {
|
||||
ManticoreProject::removeProjectUser($projectId, $userid);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'project_users_sync':
|
||||
case 'update_project_allowed_users':
|
||||
// 更新项目的 allowed_users(成员变更时调用)
|
||||
$projectId = $this->data['project_id'] ?? 0;
|
||||
if ($projectId > 0) {
|
||||
ManticoreProject::syncProjectUsers($projectId);
|
||||
ManticoreProject::updateAllowedUsers($projectId);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'cascade_project_users':
|
||||
// 项目成员变更时,级联更新该项目下所有 visibility=1 的任务
|
||||
// 异步执行,避免阻塞
|
||||
$projectId = $this->data['project_id'] ?? 0;
|
||||
if ($projectId > 0) {
|
||||
ManticoreTask::cascadeUpdateByProject($projectId);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -163,43 +142,13 @@ class ManticoreSyncTask extends AbstractTask
|
||||
}
|
||||
break;
|
||||
|
||||
case 'task_visibility_update':
|
||||
$taskId = $this->data['task_id'] ?? 0;
|
||||
$visibility = $this->data['visibility'] ?? 1;
|
||||
if ($taskId > 0) {
|
||||
ManticoreTask::updateVisibility($taskId, $visibility);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'task_user_add':
|
||||
$taskId = $this->data['task_id'] ?? 0;
|
||||
$userid = $this->data['userid'] ?? 0;
|
||||
if ($taskId > 0 && $userid > 0) {
|
||||
ManticoreTask::addTaskUser($taskId, $userid);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'task_user_remove':
|
||||
$taskId = $this->data['task_id'] ?? 0;
|
||||
$userid = $this->data['userid'] ?? 0;
|
||||
if ($taskId > 0 && $userid > 0) {
|
||||
ManticoreTask::removeTaskUser($taskId, $userid);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'task_visibility_user_remove':
|
||||
// 特殊处理:删除 visibility user 时需要检查是否仍是任务成员
|
||||
$taskId = $this->data['task_id'] ?? 0;
|
||||
$userid = $this->data['userid'] ?? 0;
|
||||
if ($taskId > 0 && $userid > 0) {
|
||||
ManticoreTask::removeVisibilityUser($taskId, $userid);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'task_users_sync':
|
||||
case 'update_task_allowed_users':
|
||||
// 更新任务的 allowed_users(成员变更时调用)
|
||||
$taskId = $this->data['task_id'] ?? 0;
|
||||
if ($taskId > 0) {
|
||||
ManticoreTask::syncTaskUsers($taskId);
|
||||
ManticoreTask::updateAllowedUsers($taskId);
|
||||
// 级联更新子任务
|
||||
ManticoreTask::cascadeToChildren($taskId);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -212,7 +161,7 @@ class ManticoreSyncTask extends AbstractTask
|
||||
|
||||
/**
|
||||
* 增量更新(定时执行)
|
||||
* 使用 --i 参数执行增量同步,会同步新增的向量数据和用户关系数据
|
||||
* 使用 --i 参数执行增量同步,会同步新增的向量数据
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@ -227,7 +176,7 @@ class ManticoreSyncTask extends AbstractTask
|
||||
// 执行开始
|
||||
Cache::put("ManticoreSyncTask:Time", time(), Carbon::now()->addMinutes(60));
|
||||
|
||||
// 执行增量同步(同时同步向量表和用户关系表的新增数据)
|
||||
// 执行增量同步(MVA 方案不需要单独同步关系表)
|
||||
@shell_exec("php /var/www/artisan manticore:sync-files --i 2>&1 &");
|
||||
@shell_exec("php /var/www/artisan manticore:sync-users --i 2>&1 &");
|
||||
@shell_exec("php /var/www/artisan manticore:sync-projects --i 2>&1 &");
|
||||
@ -241,4 +190,3 @@ class ManticoreSyncTask extends AbstractTask
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user