From ac9e1e5e67d1dd53f162586391f92b9450898bcd Mon Sep 17 00:00:00 2001 From: kuaifan Date: Tue, 9 Dec 2025 10:30:23 +0000 Subject: [PATCH] feat: call appstore user lifecycle hooks from main app --- app/Http/Controllers/Api/UsersController.php | 10 +++++ app/Models/User.php | 11 ++++- app/Module/Apps.php | 42 ++++++++++++++++++++ 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/Api/UsersController.php b/app/Http/Controllers/Api/UsersController.php index 3f340816d..29e865422 100755 --- a/app/Http/Controllers/Api/UsersController.php +++ b/app/Http/Controllers/Api/UsersController.php @@ -37,6 +37,7 @@ use App\Models\UserRecentItem; use App\Models\UserTag; use App\Models\UserTagRecognition; use App\Models\UserAppSort; +use App\Module\Apps; use Illuminate\Support\Facades\DB; use App\Models\UserEmailVerification; use App\Module\AgoraIO\AgoraTokenGenerator; @@ -1098,6 +1099,8 @@ class UsersController extends AbstractController $upArray = []; $upLdap = []; $transferUser = null; + $hookAction = ''; + $hookEvent = ''; switch ($type) { case 'setadmin': $msg = '设置成功'; @@ -1179,12 +1182,16 @@ class UsersController extends AbstractController return Base::retError('交接人已离职,请选择另一个交接人'); } } + $hookAction = 'user_offboard'; + $hookEvent = 'offboard'; break; case 'cleardisable': $msg = '操作成功'; $upArray['identity'] = array_diff($userInfo->identity, ['disable']); $upArray['disable_at'] = null; + $hookAction = 'user_onboard'; + $hookEvent = 'restore'; break; case 'delete': @@ -1303,6 +1310,9 @@ class UsersController extends AbstractController } }); } + if ($hookAction) { + Apps::dispatchUserHook($userInfo, $hookAction, $hookEvent); + } // return Base::retSuccess($msg, $userInfo); } diff --git a/app/Models/User.php b/app/Models/User.php index 4c3463af3..6f4160dac 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -5,6 +5,7 @@ namespace App\Models; use App\Exceptions\ApiException; use App\Module\Base; use App\Module\Doo; +use App\Module\Apps; use App\Module\Table\OnlineData; use App\Services\RequestContext; use Cache; @@ -313,7 +314,7 @@ class User extends AbstractModel */ public function deleteUser($reason) { - return AbstractModel::transaction(function () use ($reason) { + $ret = AbstractModel::transaction(function () use ($reason) { // 删除原因 $userDelete = UserDelete::createInstance([ 'operator' => User::userid(), @@ -334,6 +335,10 @@ class User extends AbstractModel // return $this->delete(); }); + if ($ret) { + Apps::dispatchUserHook($this, 'user_offboard', 'delete'); + } + return $ret; } /** @@ -407,7 +412,9 @@ class User extends AbstractModel $dialog?->joinGroup($user->userid, 0); } } - return $user->find($user->userid); + $createdUser = $user->find($user->userid); + Apps::dispatchUserHook($createdUser, 'user_onboard', 'onboard'); + return $createdUser; } /** diff --git a/app/Module/Apps.php b/app/Module/Apps.php index 9ca9dff11..050474f91 100644 --- a/app/Module/Apps.php +++ b/app/Module/Apps.php @@ -3,8 +3,11 @@ namespace App\Module; use App\Exceptions\ApiException; +use App\Models\User; use App\Services\RequestContext; use Symfony\Component\Yaml\Yaml; +use App\Module\Base; +use App\Module\Ihttp; class Apps { @@ -57,4 +60,43 @@ class Apps throw new ApiException("应用「{$name}」未安装", [], 0, false); } } + + /** + * Dispatch user lifecycle hook to appstore (onboard/offboard/delete/restore). + */ + public static function dispatchUserHook(User $user, string $action, string $eventType = ''): void + { + $appKey = env('APP_KEY', ''); + if (empty($appKey)) { + info('[appstore_hook] APP_KEY is empty, skip dispatchUserHook'); + return; + } + + $url = sprintf('http://appstore/api/v1/internal/hooks/%s', $action); + $payload = [ + 'user' => [ + 'id' => (string) $user->userid, + 'email' => (string) $user->email, + 'name' => (string) $user->nickname, + 'role' => in_array('admin', $user->identity ?? []) ? 'admin' : 'normal', + ], + ]; + if ($eventType !== '') { + $payload['event_type'] = $eventType; + } + + $headers = [ + 'Content-Type' => 'application/json', + 'Authorization' => 'Bearer ' . md5($appKey), + ]; + + $resp = Ihttp::ihttp_request($url, json_encode($payload, JSON_UNESCAPED_UNICODE), $headers, 5); + if (Base::isError($resp)) { + info('[appstore_hook] dispatch fail', [ + 'url' => $url, + 'payload' => $payload, + 'error' => $resp, + ]); + } + } }