浏览代码

Add VNet用户查询

兔姬桑 3 年之前
父节点
当前提交
23c23998b5

+ 80 - 78
app/Http/Controllers/Admin/UserController.php

@@ -7,6 +7,7 @@ use App\Components\IP;
 use App\Http\Controllers\Controller;
 use App\Http\Controllers\Controller;
 use App\Http\Requests\Admin\UserStoreRequest;
 use App\Http\Requests\Admin\UserStoreRequest;
 use App\Http\Requests\Admin\UserUpdateRequest;
 use App\Http\Requests\Admin\UserUpdateRequest;
+use App\Jobs\VNet\getUser;
 use App\Models\Level;
 use App\Models\Level;
 use App\Models\Node;
 use App\Models\Node;
 use App\Models\Order;
 use App\Models\Order;
@@ -27,7 +28,6 @@ use Str;
 
 
 class UserController extends Controller
 class UserController extends Controller
 {
 {
-    // 用户列表
     public function index(Request $request)
     public function index(Request $request)
     {
     {
         $query = User::with('subscribe');
         $query = User::with('subscribe');
@@ -82,23 +82,6 @@ class UserController extends Controller
         ]);
         ]);
     }
     }
 
 
-    // 添加账号页面
-    public function create()
-    {
-        if (Auth::getUser()->hasRole('Super Admin')) { // 超级管理员直接获取全部角色
-            $roles = Role::all()->pluck('description', 'name');
-        } elseif (Auth::getUser()->can('give roles')) { // 有权者只能获得已有角色,防止权限泛滥
-            $roles = Auth::getUser()->roles()->pluck('description', 'name');
-        }
-
-        return view('admin.user.info', [
-            'levels'     => Level::orderBy('level')->get(),
-            'userGroups' => UserGroup::orderBy('id')->get(),
-            'roles'      => $roles ?? null,
-        ]);
-    }
-
-    // 添加账号
     public function store(UserStoreRequest $request): JsonResponse
     public function store(UserStoreRequest $request): JsonResponse
     {
     {
         $data = $request->validated();
         $data = $request->validated();
@@ -139,8 +122,7 @@ class UserController extends Controller
         return Response::json(['status' => 'fail', 'message' => '添加失败']);
         return Response::json(['status' => 'fail', 'message' => '添加失败']);
     }
     }
 
 
-    // 编辑账号页面
-    public function edit(User $user)
+    public function create()
     {
     {
         if (Auth::getUser()->hasRole('Super Admin')) { // 超级管理员直接获取全部角色
         if (Auth::getUser()->hasRole('Super Admin')) { // 超级管理员直接获取全部角色
             $roles = Role::all()->pluck('description', 'name');
             $roles = Role::all()->pluck('description', 'name');
@@ -149,69 +131,28 @@ class UserController extends Controller
         }
         }
 
 
         return view('admin.user.info', [
         return view('admin.user.info', [
-            'user'       => $user->load('inviter:id,username'),
             'levels'     => Level::orderBy('level')->get(),
             'levels'     => Level::orderBy('level')->get(),
             'userGroups' => UserGroup::orderBy('id')->get(),
             'userGroups' => UserGroup::orderBy('id')->get(),
             'roles'      => $roles ?? null,
             'roles'      => $roles ?? null,
         ]);
         ]);
     }
     }
 
 
-    // 编辑账号
-    public function update(UserUpdateRequest $request, User $user)
+    public function edit(User $user)
     {
     {
-        $data = $request->validated();
-        $data['passwd'] = $request->input('passwd') ?? Str::random();
-        $data['vmess_id'] = $data['uuid'] ?? Str::uuid();
-        Arr::forget($data, ['roles', 'uuid', 'password']);
-        $data['transfer_enable'] *= GB;
-        $data['enable'] = $data['status'] < 0 ? 0 : $data['enable'];
-        $data['expired_at'] = $data['expired_at'] ?? date('Y-m-d', strtotime('365 days'));
-        $data['remark'] = str_replace(['atob', 'eval'], '', $data['remark']);
-
-        // 只有超级管理员才能赋予超级管理员
-        $roles = $request->input('roles');
-        try {
-            if (isset($roles)) {
-                $adminUser = Auth::getUser();
-                if ($adminUser->can('give roles') || $adminUser->hasRole('Super Admin')
-                    || (in_array('Super Admin', $roles, true) && Auth::getUser()->hasRole('Super Admin'))) {
-                    $user->syncRoles($roles);
-                }
-            } else {
-                $user->roles()->detach();
-            }
-
-            // Input checking for dummy
-            if ($data['enable'] === '1') {
-                if ($data['status'] === '-1' || $data['transfer_enable'] === 0 || $data['expired_at'] < date('Y-m-d')) {
-                    $data['enable'] = 0;
-                }
-            }
-
-            // 非演示环境才可以修改管理员密码
-            $password = $request->input('password');
-            if (! empty($password) && ! (config('app.demo') && $user->id === 1)) {
-                $data['password'] = $password;
-            }
-
-            // 写入用户流量变动记录
-            if ($user->transfer_enable !== $data['transfer_enable']) {
-                Helpers::addUserTrafficModifyLog($user->id, null, $user->transfer_enable, $data['transfer_enable'], '后台手动编辑用户');
-            }
-
-            if ($user->update($data)) {
-                return Response::json(['status' => 'success', 'message' => '编辑成功']);
-            }
-        } catch (Exception $e) {
-            Log::error('编辑用户信息异常:'.$e->getMessage());
-
-            return Response::json(['status' => 'fail', 'message' => '编辑用户信息错误:'.$e->getMessage()]);
+        if (Auth::getUser()->hasRole('Super Admin')) { // 超级管理员直接获取全部角色
+            $roles = Role::all()->pluck('description', 'name');
+        } elseif (Auth::getUser()->can('give roles')) { // 有权者只能获得已有角色,防止权限泛滥
+            $roles = Auth::getUser()->roles()->pluck('description', 'name');
         }
         }
 
 
-        return Response::json(['status' => 'fail', 'message' => '编辑失败']);
+        return view('admin.user.info', [
+            'user'       => $user->load('inviter:id,username'),
+            'levels'     => Level::orderBy('level')->get(),
+            'userGroups' => UserGroup::orderBy('id')->get(),
+            'roles'      => $roles ?? null,
+        ]);
     }
     }
 
 
-    // 删除用户
     public function destroy(User $user)
     public function destroy(User $user)
     {
     {
         if ($user->id === 1) {
         if ($user->id === 1) {
@@ -231,7 +172,6 @@ class UserController extends Controller
         return Response::json(['status' => 'fail', 'message' => '删除失败']);
         return Response::json(['status' => 'fail', 'message' => '删除失败']);
     }
     }
 
 
-    // 批量生成账号
     public function batchAddUsers()
     public function batchAddUsers()
     {
     {
         try {
         try {
@@ -247,7 +187,6 @@ class UserController extends Controller
         }
         }
     }
     }
 
 
-    // 转换成某个用户的身份
     public function switchToUser(User $user): JsonResponse
     public function switchToUser(User $user): JsonResponse
     {
     {
         // 存储当前管理员ID,并将当前登录信息改成要切换的用户的身份信息
         // 存储当前管理员ID,并将当前登录信息改成要切换的用户的身份信息
@@ -257,7 +196,6 @@ class UserController extends Controller
         return Response::json(['status' => 'success', 'message' => '身份切换成功']);
         return Response::json(['status' => 'success', 'message' => '身份切换成功']);
     }
     }
 
 
-    // 重置用户流量
     public function resetTraffic(User $user): JsonResponse
     public function resetTraffic(User $user): JsonResponse
     {
     {
         try {
         try {
@@ -271,7 +209,60 @@ class UserController extends Controller
         return Response::json(['status' => 'success', 'message' => '流量重置成功']);
         return Response::json(['status' => 'success', 'message' => '流量重置成功']);
     }
     }
 
 
-    // 操作用户余额
+    public function update(UserUpdateRequest $request, User $user)
+    {
+        $data = $request->validated();
+        $data['passwd'] = $request->input('passwd') ?? Str::random();
+        $data['vmess_id'] = $data['uuid'] ?? Str::uuid();
+        Arr::forget($data, ['roles', 'uuid', 'password']);
+        $data['transfer_enable'] *= GB;
+        $data['enable'] = $data['status'] < 0 ? 0 : $data['enable'];
+        $data['expired_at'] = $data['expired_at'] ?? date('Y-m-d', strtotime('365 days'));
+        $data['remark'] = str_replace(['atob', 'eval'], '', $data['remark']);
+
+        // 只有超级管理员才能赋予超级管理员
+        $roles = $request->input('roles');
+        try {
+            if (isset($roles)) {
+                $adminUser = Auth::getUser();
+                if ($adminUser->can('give roles') || $adminUser->hasRole('Super Admin')
+                    || (in_array('Super Admin', $roles, true) && Auth::getUser()->hasRole('Super Admin'))) {
+                    $user->syncRoles($roles);
+                }
+            } else {
+                $user->roles()->detach();
+            }
+
+            // Input checking for dummy
+            if ($data['enable'] === '1') {
+                if ($data['status'] === '-1' || $data['transfer_enable'] === 0 || $data['expired_at'] < date('Y-m-d')) {
+                    $data['enable'] = 0;
+                }
+            }
+
+            // 非演示环境才可以修改管理员密码
+            $password = $request->input('password');
+            if (! empty($password) && ! (config('app.demo') && $user->id === 1)) {
+                $data['password'] = $password;
+            }
+
+            // 写入用户流量变动记录
+            if ($user->transfer_enable !== $data['transfer_enable']) {
+                Helpers::addUserTrafficModifyLog($user->id, null, $user->transfer_enable, $data['transfer_enable'], '后台手动编辑用户');
+            }
+
+            if ($user->update($data)) {
+                return Response::json(['status' => 'success', 'message' => '编辑成功']);
+            }
+        } catch (Exception $e) {
+            Log::error('编辑用户信息异常:'.$e->getMessage());
+
+            return Response::json(['status' => 'fail', 'message' => '编辑用户信息错误:'.$e->getMessage()]);
+        }
+
+        return Response::json(['status' => 'fail', 'message' => '编辑失败']);
+    }
+
     public function handleUserCredit(Request $request, User $user): JsonResponse
     public function handleUserCredit(Request $request, User $user): JsonResponse
     {
     {
         $amount = $request->input('amount');
         $amount = $request->input('amount');
@@ -282,7 +273,7 @@ class UserController extends Controller
 
 
         // 加减余额
         // 加减余额
         if ($user->updateCredit($amount)) {
         if ($user->updateCredit($amount)) {
-            Helpers::addUserCreditLog($user->id, null, $user->credit - $amount, $user->credit, $amount, '后台手动充值');  // 写入余额变动日志
+            Helpers::addUserCreditLog($user->id, null, $user->credit - $amount, $user->credit, $amount, $request->input('description') ?? '后台手动充值');  // 写入余额变动日志
 
 
             return Response::json(['status' => 'success', 'message' => '充值成功']);
             return Response::json(['status' => 'success', 'message' => '充值成功']);
         }
         }
@@ -290,7 +281,6 @@ class UserController extends Controller
         return Response::json(['status' => 'fail', 'message' => '充值失败']);
         return Response::json(['status' => 'fail', 'message' => '充值失败']);
     }
     }
 
 
-    // 导出配置信息
     public function export(User $user)
     public function export(User $user)
     {
     {
         return view('admin.user.export', [
         return view('admin.user.export', [
@@ -312,4 +302,16 @@ class UserController extends Controller
 
 
         return view('admin.user.oauth', compact('list'));
         return view('admin.user.oauth', compact('list'));
     }
     }
+
+    public function VNetInfo(User $user)
+    {
+        $nodes = $user->nodes()->whereType(4)->get(['node.id', 'node.name']);
+        $nodeList = (new getUser())->existsinVNet($user);
+
+        foreach ($nodes as $node) {
+            $node->avaliable = in_array($node->id, $nodeList, true) ? '✔️' : '❌';
+        }
+
+        return Response::json(['status' => 'success', 'data' => $nodes]);
+    }
 }
 }

+ 1 - 14
app/Jobs/VNet/editUser.php

@@ -39,7 +39,7 @@ class editUser implements ShouldQueue
     public function handle(): void
     public function handle(): void
     {
     {
         foreach ($this->nodes as $node) {
         foreach ($this->nodes as $node) {
-            $list = $this->list(($node->server ?: $node->ips()[0]).':'.$node->push_port, $node->auth->secret);
+            $list = (new getUser())->list($node);
             if ($list && in_array($this->data['uid'], $list, true)) { // 如果用户已存在节点内,则执行修改;否则为添加
             if ($list && in_array($this->data['uid'], $list, true)) { // 如果用户已存在节点内,则执行修改;否则为添加
                 if ($node->is_ddns) {
                 if ($node->is_ddns) {
                     $this->send($node->server.':'.$node->push_port, $node->auth->secret);
                     $this->send($node->server.':'.$node->push_port, $node->auth->secret);
@@ -54,19 +54,6 @@ class editUser implements ShouldQueue
         }
         }
     }
     }
 
 
-    private function list(string $host, string $secret)
-    {
-        $response = Http::baseUrl($host)->timeout(20)->withHeaders(['secret' => $secret])->get('api/user/list');
-        $message = $response->json();
-        if ($message && $response->ok()) {
-            return Arr::pluck($message, 'uid');
-        }
-
-        Log::warning('【用户列表】获取失败(推送地址:'.$host.')');
-
-        return false;
-    }
-
     private function send(string $host, string $secret): void
     private function send(string $host, string $secret): void
     {
     {
         try {
         try {

+ 62 - 0
app/Jobs/VNet/getUser.php

@@ -0,0 +1,62 @@
+<?php
+
+namespace App\Jobs\VNet;
+
+use App\Models\Node;
+use App\Models\User;
+use Arr;
+use Exception;
+use Http;
+use Log;
+
+class getUser
+{
+    public function existsinVNet(User $user)
+    {
+        $nodeList = [];
+        foreach ($user->nodes()->whereType(4)->get() as $node) {
+            $list = $this->list($node);
+            if ($list && in_array($user->id, $list, true)) {
+                $nodeList[] = $node->id;
+            }
+        }
+
+        return $nodeList;
+    }
+
+    public function list(Node $node, string $mode = 'uid')
+    {
+        $list = $this->send(($node->server ?: $node->ips()[0]).':'.$node->push_port, $node->auth->secret);
+
+        if (is_array($list)) {
+            if ($mode === 'uid') {
+                return Arr::pluck($list, 'uid');
+            }
+
+            if ($mode === 'port') {
+                return Arr::pluck($list, 'port');
+            }
+
+            return $list;
+        }
+
+        return false;
+    }
+
+    private function send(string $host, string $secret)
+    {
+        try {
+            $response = Http::baseUrl($host)->timeout(20)->withHeaders(['secret' => $secret])->get('api/user/list');
+            $message = $response->json();
+            if ($message && $response->ok()) {
+                return $message;
+            }
+
+            Log::warning('【用户列表】获取失败(推送地址:'.$host.')');
+        } catch (Exception $exception) {
+            Log::alert('【用户列表】获取异常:'.$exception->getMessage());
+        }
+
+        return false;
+    }
+}

+ 42 - 0
resources/views/admin/user/index.blade.php

@@ -3,6 +3,10 @@
     <link href="/assets/global/vendor/bootstrap-table/bootstrap-table.min.css" rel="stylesheet">
     <link href="/assets/global/vendor/bootstrap-table/bootstrap-table.min.css" rel="stylesheet">
     <link href="/assets/custom/range.min.css" rel="stylesheet">
     <link href="/assets/custom/range.min.css" rel="stylesheet">
     <style>
     <style>
+        #swal2-content {
+            display: grid !important;
+        }
+
         .table a {
         .table a {
             color: #76838f;
             color: #76838f;
             text-decoration: none;
             text-decoration: none;
@@ -185,6 +189,11 @@
                                                 <i class="icon wb-user" aria-hidden="true"></i> 用户视角
                                                 <i class="icon wb-user" aria-hidden="true"></i> 用户视角
                                             </a>
                                             </a>
                                         @endcan
                                         @endcan
+                                        @can('admin.user.VNetInfo')
+                                            <a class="dropdown-item" href="javascript:VNetInfo('{{$user->id}}')" role="menuitem">
+                                                <i id="vent_{{$user->id}}" class="icon wb-link-broken" aria-hidden="true"></i> 联网测试
+                                            </a>
+                                        @endcan
                                     </div>
                                     </div>
                                 @endcanany
                                 @endcanany
                             </td>
                             </td>
@@ -314,6 +323,39 @@
         }
         }
         @endcan
         @endcan
 
 
+        @can('admin.user.VNetInfo')
+        // 节点连通性测试
+        function VNetInfo(id) {
+            $.ajax({
+                method: 'POST',
+                url: '{{route('admin.user.VNetInfo', '')}}/' + id,
+                data: {_token: '{{csrf_token()}}'},
+                beforeSend: function() {
+                    $('#vent_' + id).removeClass('wb-link-broken').addClass('wb-loop icon-spin');
+                },
+                success: function(ret) {
+                    if (ret.status === 'success') {
+                        let str = '';
+                        for (let i in ret.data) {
+                            str += '<tr><td>' + ret.data[i]['id'] + '</td><td>' + ret.data[i]['name'] + '</td><td>' + ret.data[i]['avaliable'] + '</td></tr>';
+                        }
+                        swal.fire({
+                            title: ret.title,
+                            icon: 'info',
+                            html: '<table class="my-20"><thead class="thead-default"><tr><th> ID </th><th> 节点 </th> <th> 状态 </th></thead><tbody>' + str + '</tbody></table>',
+                            showConfirmButton: false,
+                        });
+                    } else {
+                        swal.fire({title: ret.title, text: ret.data, icon: 'error'});
+                    }
+                },
+                complete: function() {
+                    $('#vent_' + id).removeClass('wb-loop icon-spin').addClass('wb-link-broken');
+                },
+            });
+        }
+        @endcan
+
         const clipboard = new ClipboardJS('.copySubscribeLink');
         const clipboard = new ClipboardJS('.copySubscribeLink');
         clipboard.on('success', function() {
         clipboard.on('success', function() {
             swal.fire({
             swal.fire({

+ 1 - 0
routes/admin.php

@@ -21,6 +21,7 @@ Route::prefix('admin')->name('admin.')->group(function () {
             Route::post('reset/{user}', 'UserController@resetTraffic')->name('reset'); // 重置用户流量
             Route::post('reset/{user}', 'UserController@resetTraffic')->name('reset'); // 重置用户流量
             Route::get('export/{user}', 'UserController@export')->name('export'); // 查看配置信息
             Route::get('export/{user}', 'UserController@export')->name('export'); // 查看配置信息
             Route::post('export/{user}', 'UserController@exportProxyConfig')->name('exportProxy'); // 读取配置信息
             Route::post('export/{user}', 'UserController@exportProxyConfig')->name('exportProxy'); // 读取配置信息
+            Route::post('vnet/{user}', 'UserController@VNetInfo')->name('VNetInfo'); // VNet用户开通检测
         });
         });
 
 
         Route::prefix('subscribe')->name('subscribe.')->group(function () {
         Route::prefix('subscribe')->name('subscribe.')->group(function () {