151 lines
6.2 KiB
PHP

<?php
namespace App\Http\Controllers\SystemSettings;
use App\Models\Auth\DingTalkAuthAudit;
use App\Models\Auth\DingTalkBindingRequest;
use App\Models\Auth\DingTalkIdentity;
use App\Models\Auth\User;
use App\Services\Auth\DingTalkClosedAccess;
use App\Utilities\SystemAccess;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;
class DingTalkBindings extends Controller
{
public function __construct()
{
$this->middleware(function ($request, $next) {
abort_unless(SystemAccess::canOpenSettings(), 403);
return $next($request);
});
}
public function index()
{
$eligibleUsers = $this->eligibleUsers()->with('roles')->orderBy('name')->get();
$eligibleUserIds = $eligibleUsers->pluck('id');
$bindingRequests = DingTalkBindingRequest::query()->with(['matchedUser', 'reviewer']);
$identities = DingTalkIdentity::query()->with('user');
$audits = DingTalkAuthAudit::query()->with(['user', 'actor']);
if (! SystemAccess::isSuperAdmin()) {
$bindingRequests->whereIn('matched_user_id', $eligibleUserIds);
$identities->whereIn('user_id', $eligibleUserIds);
$audits->whereIn('user_id', $eligibleUserIds);
}
return view('system_settings.dingtalk_bindings.index', [
'bindingRequests' => $bindingRequests->latest('last_attempted_at')->get(),
'identities' => $identities->latest('bound_at')->get(),
'eligibleUsers' => $eligibleUsers,
'audits' => $audits->latest('created_at')->limit(50)->get(),
]);
}
public function approve(DingTalkBindingRequest $bindingRequest, Request $request, DingTalkClosedAccess $access)
{
$data = $request->validate(['user_id' => ['required', 'integer']]);
$managedUser = $this->eligibleUsers()->findOrFail((int) $data['user_id']);
abort_unless(SystemAccess::canManageUser(user(), $managedUser) || $managedUser->id === user()->id, 403);
abort_unless(
SystemAccess::isSuperAdmin()
|| ((int) $bindingRequest->matched_user_id === (int) $managedUser->id),
403
);
if (DingTalkIdentity::query()->where('union_id', $bindingRequest->union_id)->exists()) {
throw ValidationException::withMessages(['binding' => '该钉钉账号已经完成绑定。']);
}
if (DingTalkIdentity::query()->where('user_id', $managedUser->id)->exists()) {
throw ValidationException::withMessages(['user_id' => '该财务账号已经绑定其他钉钉账号。']);
}
DB::transaction(function () use ($bindingRequest, $managedUser, $request, $access): void {
DingTalkIdentity::query()->create([
'user_id' => $managedUser->id,
'union_id' => $bindingRequest->union_id,
'open_id' => $bindingRequest->open_id,
'dingtalk_user_id' => $bindingRequest->dingtalk_user_id,
'nickname' => $bindingRequest->nickname,
'bound_by' => user()->id,
'bound_at' => now(),
]);
$bindingRequest->forceFill([
'status' => DingTalkBindingRequest::APPROVED,
'matched_user_id' => $managedUser->id,
'match_reason' => 'administrator_approved',
'reviewed_by' => user()->id,
'reviewed_at' => now(),
])->save();
$access->audit('binding_admin_approved', 'success', $managedUser->id, user()->id, $bindingRequest->union_id, $request);
});
flash('钉钉账号已绑定。')->success();
return redirect()->route('system-settings.dingtalk-bindings.index');
}
public function reject(DingTalkBindingRequest $bindingRequest, Request $request, DingTalkClosedAccess $access)
{
abort_unless(
SystemAccess::isSuperAdmin()
|| ($bindingRequest->matchedUser && SystemAccess::canManageUser(user(), $bindingRequest->matchedUser)),
403
);
abort_if(DingTalkIdentity::query()->where('union_id', $bindingRequest->union_id)->exists(), 422, '已绑定身份不能直接拒绝。');
$bindingRequest->forceFill([
'status' => DingTalkBindingRequest::REJECTED,
'matched_user_id' => null,
'match_reason' => 'administrator_rejected',
'reviewed_by' => user()->id,
'reviewed_at' => now(),
])->save();
$access->audit('binding_rejected', 'denied', null, user()->id, $bindingRequest->union_id, $request);
flash('钉钉绑定申请已拒绝。')->success();
return redirect()->route('system-settings.dingtalk-bindings.index');
}
public function destroy(DingTalkIdentity $identity, Request $request, DingTalkClosedAccess $access)
{
$managedUser = $identity->user()->firstOrFail();
abort_unless(SystemAccess::canManageUser(user(), $managedUser) || $managedUser->id === user()->id, 403);
DB::transaction(function () use ($identity, $managedUser, $request, $access): void {
$unionId = $identity->union_id;
$identity->delete();
DingTalkBindingRequest::query()->where('union_id', $unionId)->update([
'status' => DingTalkBindingRequest::REVOKED,
'match_reason' => 'administrator_revoked',
'reviewed_by' => user()->id,
'reviewed_at' => now(),
]);
$access->audit('binding_revoked', 'success', $managedUser->id, user()->id, $unionId, $request);
});
flash('钉钉账号绑定已解除。')->success();
return redirect()->route('system-settings.dingtalk-bindings.index');
}
private function eligibleUsers()
{
$query = User::query()
->where('enabled', true)
->whereHas('companies', fn ($company) => $company->where('companies.id', company_id())->where('companies.enabled', true));
if (! SystemAccess::isSuperAdmin()) {
$query->whereHas('roles', fn ($roles) => $roles->where('roles.name', SystemAccess::USER));
}
return $query;
}
}