mirror of
https://github.com/kuaifan/dootask.git
synced 2026-03-17 19:23:26 +00:00
feat: 添加 user_update hook 事件并重构用户生命周期 hook
- 新增 user_update 事件,当用户基本信息变更时触发 - 扩展 dispatchUserHook payload 包含完整用户信息(tel、profession、birthday、address、introduction、departments) - 将 user_onboard/user_offboard/user_update hook 触发逻辑集中到 UserObserver - 区分 profile_update(用户自己修改)和 admin_update(管理员修改)事件类型 - 修复 User::reg() 中 Manticore 索引同步遗漏问题 - 排除机器人账号的 hook 触发
This commit is contained in:
parent
7f9c42d3d8
commit
1ac3a4cc96
@ -37,7 +37,6 @@ use App\Models\UserRecentItem;
|
|||||||
use App\Models\UserTag;
|
use App\Models\UserTag;
|
||||||
use App\Models\UserTagRecognition;
|
use App\Models\UserTagRecognition;
|
||||||
use App\Models\UserAppSort;
|
use App\Models\UserAppSort;
|
||||||
use App\Module\Apps;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use App\Models\UserEmailVerification;
|
use App\Models\UserEmailVerification;
|
||||||
use App\Module\AgoraIO\AgoraTokenGenerator;
|
use App\Module\AgoraIO\AgoraTokenGenerator;
|
||||||
@ -1104,8 +1103,6 @@ class UsersController extends AbstractController
|
|||||||
$upArray = [];
|
$upArray = [];
|
||||||
$upLdap = [];
|
$upLdap = [];
|
||||||
$transferUser = null;
|
$transferUser = null;
|
||||||
$hookAction = '';
|
|
||||||
$hookEvent = '';
|
|
||||||
switch ($type) {
|
switch ($type) {
|
||||||
case 'setadmin':
|
case 'setadmin':
|
||||||
$msg = '设置成功';
|
$msg = '设置成功';
|
||||||
@ -1187,16 +1184,12 @@ class UsersController extends AbstractController
|
|||||||
return Base::retError('交接人已离职,请选择另一个交接人');
|
return Base::retError('交接人已离职,请选择另一个交接人');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$hookAction = 'user_offboard';
|
|
||||||
$hookEvent = 'offboard';
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'cleardisable':
|
case 'cleardisable':
|
||||||
$msg = '操作成功';
|
$msg = '操作成功';
|
||||||
$upArray['identity'] = array_diff($userInfo->identity, ['disable']);
|
$upArray['identity'] = array_diff($userInfo->identity, ['disable']);
|
||||||
$upArray['disable_at'] = null;
|
$upArray['disable_at'] = null;
|
||||||
$hookAction = 'user_onboard';
|
|
||||||
$hookEvent = 'restore';
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'delete':
|
case 'delete':
|
||||||
@ -1315,9 +1308,6 @@ class UsersController extends AbstractController
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if ($hookAction) {
|
|
||||||
Apps::dispatchUserHook($userInfo, $hookAction, $hookEvent);
|
|
||||||
}
|
|
||||||
//
|
//
|
||||||
return Base::retSuccess($msg, $userInfo);
|
return Base::retSuccess($msg, $userInfo);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,9 @@ use App\Module\Base;
|
|||||||
use App\Module\Doo;
|
use App\Module\Doo;
|
||||||
use App\Module\Apps;
|
use App\Module\Apps;
|
||||||
use App\Module\Table\OnlineData;
|
use App\Module\Table\OnlineData;
|
||||||
|
use App\Observers\AbstractObserver;
|
||||||
use App\Services\RequestContext;
|
use App\Services\RequestContext;
|
||||||
|
use App\Tasks\ManticoreSyncTask;
|
||||||
use Cache;
|
use Cache;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
|
|
||||||
@ -335,9 +337,6 @@ class User extends AbstractModel
|
|||||||
//
|
//
|
||||||
return $this->delete();
|
return $this->delete();
|
||||||
});
|
});
|
||||||
if ($ret) {
|
|
||||||
Apps::dispatchUserHook($this, 'user_offboard', 'delete');
|
|
||||||
}
|
|
||||||
return $ret;
|
return $ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -413,7 +412,12 @@ class User extends AbstractModel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
$createdUser = $user->find($user->userid);
|
$createdUser = $user->find($user->userid);
|
||||||
|
if (!$createdUser->bot) {
|
||||||
|
// Manticore 索引同步
|
||||||
|
AbstractObserver::taskDeliver(new ManticoreSyncTask('user_sync', $createdUser->toArray()));
|
||||||
|
// 触发 user_onboard hook
|
||||||
Apps::dispatchUserHook($createdUser, 'user_onboard', 'onboard');
|
Apps::dispatchUserHook($createdUser, 'user_onboard', 'onboard');
|
||||||
|
}
|
||||||
return $createdUser;
|
return $createdUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@ namespace App\Module;
|
|||||||
|
|
||||||
use App\Exceptions\ApiException;
|
use App\Exceptions\ApiException;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use App\Models\UserDepartment;
|
||||||
use App\Services\RequestContext;
|
use App\Services\RequestContext;
|
||||||
use Symfony\Component\Yaml\Yaml;
|
use Symfony\Component\Yaml\Yaml;
|
||||||
use App\Module\Base;
|
use App\Module\Base;
|
||||||
@ -62,9 +63,14 @@ class Apps
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dispatch user lifecycle hook to appstore (onboard/offboard/delete/restore).
|
* Dispatch user lifecycle hook to appstore (user_onboard/user_offboard/user_update).
|
||||||
|
*
|
||||||
|
* @param User $user 用户对象
|
||||||
|
* @param string $action Hook 动作: user_onboard, user_offboard, user_update
|
||||||
|
* @param string $eventType 事件类型: onboard, restore, offboarded, delete, profile_update, admin_update
|
||||||
|
* @param array $changedFields 变更字段列表(仅 user_update 时有值)
|
||||||
*/
|
*/
|
||||||
public static function dispatchUserHook(User $user, string $action, string $eventType = ''): void
|
public static function dispatchUserHook(User $user, string $action, string $eventType = '', array $changedFields = []): void
|
||||||
{
|
{
|
||||||
$appKey = env('APP_KEY', '');
|
$appKey = env('APP_KEY', '');
|
||||||
if (empty($appKey)) {
|
if (empty($appKey)) {
|
||||||
@ -72,18 +78,40 @@ class Apps
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取用户部门信息
|
||||||
|
$departments = [];
|
||||||
|
if (!empty($user->department)) {
|
||||||
|
$deptIds = is_array($user->department)
|
||||||
|
? $user->department
|
||||||
|
: array_filter(explode(',', $user->department));
|
||||||
|
if (!empty($deptIds)) {
|
||||||
|
$deptList = UserDepartment::whereIn('id', $deptIds)->get(['id', 'name']);
|
||||||
|
foreach ($deptList as $dept) {
|
||||||
|
$departments[] = [
|
||||||
|
'id' => (string) $dept->id,
|
||||||
|
'name' => (string) $dept->name,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$url = sprintf('http://appstore/api/v1/internal/hooks/%s', $action);
|
$url = sprintf('http://appstore/api/v1/internal/hooks/%s', $action);
|
||||||
$payload = [
|
$payload = [
|
||||||
'user' => [
|
'user' => [
|
||||||
'id' => (string) $user->userid,
|
'id' => (string) $user->userid,
|
||||||
'email' => (string) $user->email,
|
'email' => (string) $user->email,
|
||||||
'name' => (string) $user->nickname,
|
'name' => (string) $user->nickname,
|
||||||
'role' => in_array('admin', $user->identity ?? []) ? 'admin' : 'normal',
|
'role' => $user->isAdmin() ? 'admin' : 'normal',
|
||||||
|
'tel' => (string) ($user->tel ?? ''),
|
||||||
|
'profession' => (string) ($user->profession ?? ''),
|
||||||
|
'birthday' => $user->birthday ? (string) $user->birthday : '',
|
||||||
|
'address' => (string) ($user->address ?? ''),
|
||||||
|
'introduction' => (string) ($user->introduction ?? ''),
|
||||||
|
'departments' => $departments,
|
||||||
],
|
],
|
||||||
|
'event_type' => $eventType,
|
||||||
|
'changed_fields' => $changedFields,
|
||||||
];
|
];
|
||||||
if ($eventType !== '') {
|
|
||||||
$payload['event_type'] = $eventType;
|
|
||||||
}
|
|
||||||
|
|
||||||
$headers = [
|
$headers = [
|
||||||
'Content-Type' => 'application/json',
|
'Content-Type' => 'application/json',
|
||||||
|
|||||||
@ -3,10 +3,26 @@
|
|||||||
namespace App\Observers;
|
namespace App\Observers;
|
||||||
|
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use App\Module\Apps;
|
||||||
use App\Tasks\ManticoreSyncTask;
|
use App\Tasks\ManticoreSyncTask;
|
||||||
|
|
||||||
class UserObserver extends AbstractObserver
|
class UserObserver extends AbstractObserver
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* 搜索相关字段(Manticore 同步)
|
||||||
|
*/
|
||||||
|
private static array $searchableFields = [
|
||||||
|
'nickname', 'email', 'profession', 'introduction', 'disable_at'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 需要监控并触发 user_update hook 的字段
|
||||||
|
*/
|
||||||
|
private static array $hookMonitoredFields = [
|
||||||
|
'email', 'tel', 'nickname', 'profession',
|
||||||
|
'birthday', 'address', 'introduction', 'department'
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle the User "created" event.
|
* Handle the User "created" event.
|
||||||
*
|
*
|
||||||
@ -30,15 +46,14 @@ class UserObserver extends AbstractObserver
|
|||||||
*/
|
*/
|
||||||
public function updated(User $user)
|
public function updated(User $user)
|
||||||
{
|
{
|
||||||
// 机器人账号不同步
|
// 机器人账号不处理
|
||||||
if ($user->bot) {
|
if ($user->bot) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否有搜索相关字段变化
|
// 检查是否有搜索相关字段变化(Manticore 同步)
|
||||||
$searchableFields = ['nickname', 'email', 'profession', 'introduction', 'disable_at'];
|
|
||||||
$isDirty = false;
|
$isDirty = false;
|
||||||
foreach ($searchableFields as $field) {
|
foreach (self::$searchableFields as $field) {
|
||||||
if ($user->isDirty($field)) {
|
if ($user->isDirty($field)) {
|
||||||
$isDirty = true;
|
$isDirty = true;
|
||||||
break;
|
break;
|
||||||
@ -53,6 +68,43 @@ class UserObserver extends AbstractObserver
|
|||||||
self::taskDeliver(new ManticoreSyncTask('user_sync', $user->toArray()));
|
self::taskDeliver(new ManticoreSyncTask('user_sync', $user->toArray()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检测 onboard/offboard 场景(disable_at 变化)
|
||||||
|
if ($user->isDirty('disable_at')) {
|
||||||
|
$originalDisableAt = $user->getOriginal('disable_at');
|
||||||
|
$currentDisableAt = $user->disable_at;
|
||||||
|
|
||||||
|
if ($originalDisableAt && !$currentDisableAt) {
|
||||||
|
// disable_at 从有值变为 null → 取消离职 (restore)
|
||||||
|
Apps::dispatchUserHook($user, 'user_onboard', 'restore');
|
||||||
|
} elseif (!$originalDisableAt && $currentDisableAt) {
|
||||||
|
// disable_at 从 null 变为有值 → 离职 (offboarded)
|
||||||
|
Apps::dispatchUserHook($user, 'user_offboard', 'offboarded');
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 排除仅 identity 变化的场景
|
||||||
|
if ($user->isDirty('identity')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检测监控字段变更,触发 user_update hook
|
||||||
|
$changedFields = [];
|
||||||
|
foreach (self::$hookMonitoredFields as $field) {
|
||||||
|
if ($user->isDirty($field)) {
|
||||||
|
$changedFields[] = $field;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($changedFields)) {
|
||||||
|
// 判断是用户自己修改还是管理员修改
|
||||||
|
$currentUser = User::authInfo();
|
||||||
|
$eventType = ($currentUser && $currentUser->userid === $user->userid)
|
||||||
|
? 'profile_update'
|
||||||
|
: 'admin_update';
|
||||||
|
Apps::dispatchUserHook($user, 'user_update', $eventType, $changedFields);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -63,7 +115,13 @@ class UserObserver extends AbstractObserver
|
|||||||
*/
|
*/
|
||||||
public function deleted(User $user)
|
public function deleted(User $user)
|
||||||
{
|
{
|
||||||
|
// Manticore 索引删除
|
||||||
self::taskDeliver(new ManticoreSyncTask('user_delete', ['userid' => $user->userid]));
|
self::taskDeliver(new ManticoreSyncTask('user_delete', ['userid' => $user->userid]));
|
||||||
|
|
||||||
|
// 触发 user_offboard (delete) hook
|
||||||
|
if (!$user->bot) {
|
||||||
|
Apps::dispatchUserHook($user, 'user_offboard', 'delete');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user