瀏覽代碼

Add 全新第三方登录模块

兔姬桑 4 年之前
父節點
當前提交
1c56a36690
共有 71 個文件被更改,包括 1037 次插入245 次删除
  1. 5 5
      app/Components/Helpers.php
  2. 2 2
      app/Console/Commands/DailyJob.php
  3. 1 1
      app/Console/Commands/UserExpireWarning.php
  4. 1 1
      app/Console/Commands/UserHourlyTrafficMonitoring.php
  5. 13 13
      app/Http/Controllers/Admin/AffiliateController.php
  6. 27 27
      app/Http/Controllers/Admin/LogsController.php
  7. 3 3
      app/Http/Controllers/Admin/RuleController.php
  8. 5 5
      app/Http/Controllers/Admin/SubscribeController.php
  9. 5 1
      app/Http/Controllers/Admin/SystemController.php
  10. 4 4
      app/Http/Controllers/Admin/TicketController.php
  11. 1 1
      app/Http/Controllers/Admin/ToolsController.php
  12. 10 2
      app/Http/Controllers/Admin/UserController.php
  13. 1 1
      app/Http/Controllers/AdminController.php
  14. 21 20
      app/Http/Controllers/AuthController.php
  15. 5 3
      app/Http/Controllers/Gateway/BitpayX.php
  16. 143 0
      app/Http/Controllers/OAuth/BaseController.php
  17. 2 2
      app/Http/Controllers/User/AffiliateController.php
  18. 3 3
      app/Http/Controllers/UserController.php
  19. 2 2
      app/Http/Requests/Admin/TicketRequest.php
  20. 2 2
      app/Http/Requests/Admin/UserStoreRequest.php
  21. 2 2
      app/Http/Requests/Admin/UserUpdateRequest.php
  22. 2 2
      app/Http/Requests/Auth/RegisterRequest.php
  23. 25 20
      app/Models/User.php
  24. 17 0
      app/Models/UserOauth.php
  25. 10 1
      app/Notifications/Custom.php
  26. 6 9
      app/Services/TelegramService.php
  27. 10 0
      config/common.php
  28. 2 2
      database/factories/UserFactory.php
  29. 53 0
      database/migrations/2021_06_16_115448_oauth.php
  30. 1 1
      database/migrations/2021_06_27_174304_append_v2_sni_to_node_table.php
  31. 195 0
      public/assets/global/fonts/brand-icons/brand-icons.css
  32. 二進制
      public/assets/global/fonts/brand-icons/brand-icons.eot
  33. 0 0
      public/assets/global/fonts/brand-icons/brand-icons.min.css
  34. 237 0
      public/assets/global/fonts/brand-icons/brand-icons.svg
  35. 二進制
      public/assets/global/fonts/brand-icons/brand-icons.ttf
  36. 二進制
      public/assets/global/fonts/brand-icons/brand-icons.woff
  37. 二進制
      public/assets/global/fonts/brand-icons/brand-icons.woff2
  38. 2 0
      resources/lang/en/auth.php
  39. 2 0
      resources/lang/zh_CN/auth.php
  40. 3 3
      resources/views/admin/aff/index.blade.php
  41. 4 4
      resources/views/admin/aff/rebate.blade.php
  42. 36 34
      resources/views/admin/config/system.blade.php
  43. 2 2
      resources/views/admin/inviteList.blade.php
  44. 7 0
      resources/views/admin/layouts.blade.php
  45. 1 1
      resources/views/admin/logs/notification.blade.php
  46. 2 2
      resources/views/admin/logs/onlineIPMonitor.blade.php
  47. 3 3
      resources/views/admin/logs/order.blade.php
  48. 3 3
      resources/views/admin/logs/traffic.blade.php
  49. 3 3
      resources/views/admin/logs/userBanHistory.blade.php
  50. 2 2
      resources/views/admin/logs/userCreditHistory.blade.php
  51. 1 1
      resources/views/admin/logs/userMonitor.blade.php
  52. 2 2
      resources/views/admin/logs/userOnlineIP.blade.php
  53. 2 2
      resources/views/admin/logs/userTraffic.blade.php
  54. 2 2
      resources/views/admin/rule/log.blade.php
  55. 3 3
      resources/views/admin/subscribe/index.blade.php
  56. 1 1
      resources/views/admin/subscribe/log.blade.php
  57. 7 7
      resources/views/admin/ticket/index.blade.php
  58. 1 1
      resources/views/admin/user/export.blade.php
  59. 8 8
      resources/views/admin/user/index.blade.php
  60. 7 7
      resources/views/admin/user/info.blade.php
  61. 54 0
      resources/views/admin/user/oauth.blade.php
  62. 1 1
      resources/views/auth/activeUser.blade.php
  63. 9 2
      resources/views/auth/login.blade.php
  64. 16 5
      resources/views/auth/register.blade.php
  65. 1 1
      resources/views/auth/resetPassword.blade.php
  66. 2 2
      resources/views/components/avatar.blade.php
  67. 1 1
      resources/views/components/chat-unit.blade.php
  68. 22 5
      resources/views/user/profile.blade.php
  69. 2 2
      resources/views/user/referral.blade.php
  70. 1 0
      routes/admin.php
  71. 8 0
      routes/web.php

+ 5 - 5
app/Components/Helpers.php

@@ -52,19 +52,19 @@ class Helpers
     /**
      * 添加用户.
      *
-     * @param  string  $email  用户邮箱
+     * @param  string  $username  用户
      * @param  string  $password  用户密码
      * @param  int  $transfer_enable  可用流量
      * @param  int|null  $date  可使用天数
      * @param  int|null  $inviter_id  邀请人
-     * @param  string|null  $username  昵称
+     * @param  string|null  $nickname  昵称
      * @return User
      */
-    public static function addUser(string $email, string $password, int $transfer_enable, int $date = null, int $inviter_id = null, string $username = null): User
+    public static function addUser(string $username, string $password, int $transfer_enable, int $date = null, int $inviter_id = null, string $nickname = null): User
     {
         return User::create([
-            'username'        => $username ?? $email,
-            'email'           => $email,
+            'nickname'        => $nickname ?? $username,
+            'username'        => $username,
             'password'        => $password,
             'port'            => self::getPort(), // 生成一个可用端口
             'passwd'          => Str::random(),

+ 2 - 2
app/Console/Commands/DailyJob.php

@@ -116,9 +116,9 @@ class DailyJob extends Command
                     if ($user->update((new OrderService($order))->resetTimeAndData($user->expired_at))) {
                         // 可用流量变动日志
                         Helpers::addUserTrafficModifyLog($order->user_id, $order->id, $oldData, $user->transfer_enable, '【流量重置】重置可用流量');
-                        Log::info('用户[ID:'.$user->id.'  昵称: '.$user->username.'  邮箱: '.$user->email.'] 流量重置为 '.flowAutoShow($user->transfer_enable).'. 重置日期为 '.($user->reset_time ?: '【无】'));
+                        Log::info('用户[ID:'.$user->id.'  昵称: '.$user->nickname.'  邮箱: '.$user->username.'] 流量重置为 '.flowAutoShow($user->transfer_enable).'. 重置日期为 '.($user->reset_time ?: '【无】'));
                     } else {
-                        Log::warning('用户[ID:'.$user->id.'  昵称: '.$user->username.'  邮箱: '.$user->email.'] 流量重置失败');
+                        Log::warning('用户[ID:'.$user->id.'  昵称: '.$user->nickname.'  邮箱: '.$user->username.'] 流量重置失败');
                     }
                 }
             });

+ 1 - 1
app/Console/Commands/UserExpireWarning.php

@@ -33,7 +33,7 @@ class UserExpireWarning extends Command
             ->where('expired_at', '<', date('Y-m-d', strtotime(sysConfig('expire_days').' days')))
             ->chunk(config('tasks.chunk'), function ($users) {
                 foreach ($users as $user) {
-                    if (filter_var($user->email, FILTER_VALIDATE_EMAIL) === false) { // 用户账号不是邮箱的跳过
+                    if (filter_var($user->username, FILTER_VALIDATE_EMAIL) === false) { // 用户账号不是邮箱的跳过
                         continue;
                     }
                     $user->notify(new AccountExpire($user->expired_at));

+ 1 - 1
app/Console/Commands/UserHourlyTrafficMonitoring.php

@@ -59,7 +59,7 @@ class UserHourlyTrafficMonitoring extends Command
             if ($this->data_anomaly_notification) { // 用户流量异常警告
                 $traffic = $user->hourlyDataFlows()->whereNodeId(null)->latest()->first();
                 if ($traffic->total >= $this->traffic_ban_value) {
-                    Notification::send(User::find(1), new DataAnomaly($user->email, flowAutoShow($traffic->u), flowAutoShow($traffic->d), flowAutoShow($traffic->traffic)));
+                    Notification::send(User::find(1), new DataAnomaly($user->username, flowAutoShow($traffic->u), flowAutoShow($traffic->d), flowAutoShow($traffic->traffic)));
                 }
             }
         }

+ 13 - 13
app/Http/Controllers/Admin/AffiliateController.php

@@ -12,10 +12,10 @@ class AffiliateController extends Controller
     // 提现申请列表
     public function index(Request $request)
     {
-        $query = ReferralApply::with('user:id,email');
-        $request->whenFilled('email', function ($email) use ($query) {
-            $query->whereHas('user', function ($query) use ($email) {
-                $query->where('email', 'like', "%{$email}%");
+        $query = ReferralApply::with('user:id,username');
+        $request->whenFilled('username', function ($username) use ($query) {
+            $query->whereHas('user', function ($query) use ($username) {
+                $query->where('username', 'like', "%{$username}%");
             });
         });
 
@@ -30,8 +30,8 @@ class AffiliateController extends Controller
     public function detail(Request $request, ReferralApply $aff)
     {
         return view('admin.aff.detail', [
-            'referral'    => $aff->load('user:id,email'),
-            'commissions' => $aff->referral_logs()->with(['invitee:id,email', 'order.goods:id,name'])->paginate()->appends($request->except('page')),
+            'referral'    => $aff->load('user:id,username'),
+            'commissions' => $aff->referral_logs()->with(['invitee:id,username', 'order.goods:id,name'])->paginate()->appends($request->except('page')),
         ]);
     }
 
@@ -57,17 +57,17 @@ class AffiliateController extends Controller
     // 用户返利流水记录
     public function rebate(Request $request)
     {
-        $query = ReferralLog::with(['invitee:id,email', 'inviter:id,email'])->orderBy('status')->latest();
+        $query = ReferralLog::with(['invitee:id,username', 'inviter:id,username'])->orderBy('status')->latest();
 
-        $request->whenFilled('invitee_email', function ($email) use ($query) {
-            $query->whereHas('invitee', function ($query) use ($email) {
-                $query->where('email', 'like', "%{$email}%");
+        $request->whenFilled('invitee_username', function ($username) use ($query) {
+            $query->whereHas('invitee', function ($query) use ($username) {
+                $query->where('username', 'like', "%{$username}%");
             });
         });
 
-        $request->whenFilled('inviter_email', function ($email) use ($query) {
-            $query->whereHas('inviter', function ($query) use ($email) {
-                $query->where('email', 'like', "%{$email}%");
+        $request->whenFilled('inviter_username', function ($username) use ($query) {
+            $query->whereHas('inviter', function ($query) use ($username) {
+                $query->where('username', 'like', "%{$username}%");
             });
         });
 

+ 27 - 27
app/Http/Controllers/Admin/LogsController.php

@@ -21,11 +21,11 @@ class LogsController extends Controller
     // 订单列表
     public function orderList(Request $request)
     {
-        $query = Order::with(['user:id,email', 'goods:id,name', 'coupon:id,name,sn']);
+        $query = Order::with(['user:id,username', 'goods:id,name', 'coupon:id,name,sn']);
 
-        $request->whenFilled('email', function ($email) use ($query) {
-            $query->whereHas('user', function ($query) use ($email) {
-                $query->where('email', 'like', "%{$email}%");
+        $request->whenFilled('username', function ($username) use ($query) {
+            $query->whereHas('user', function ($query) use ($username) {
+                $query->where('username', 'like', "%{$username}%");
             });
         });
 
@@ -82,9 +82,9 @@ class LogsController extends Controller
             });
         }
 
-        $request->whenFilled('email', function ($email) use ($query) {
-            $query->whereHas('user', function ($query) use ($email) {
-                $query->where('email', 'like', "%{$email}%");
+        $request->whenFilled('username', function ($username) use ($query) {
+            $query->whereHas('user', function ($query) use ($username) {
+                $query->where('username', 'like', "%{$username}%");
             });
         });
 
@@ -113,8 +113,8 @@ class LogsController extends Controller
     {
         $query = NotificationLog::query();
 
-        $request->whenFilled('email', function ($email) use ($query) {
-            $query->where('address', 'like', "%{$email}%");
+        $request->whenFilled('username', function ($username) use ($query) {
+            $query->where('address', 'like', "%{$username}%");
         });
 
         $request->whenFilled('type', function ($type) use ($query) {
@@ -127,7 +127,7 @@ class LogsController extends Controller
     // 在线IP监控(实时)
     public function onlineIPMonitor(Request $request, $id = null)
     {
-        $query = NodeOnlineIp::with(['node:id,name', 'user:id,email'])->where('created_at', '>=', strtotime('-2 minutes'));
+        $query = NodeOnlineIp::with(['node:id,name', 'user:id,username'])->where('created_at', '>=', strtotime('-2 minutes'));
 
         if ($id !== null) {
             $query->whereHas('user', static function ($query) use ($id) {
@@ -139,9 +139,9 @@ class LogsController extends Controller
             $query->whereIp($ip);
         });
 
-        $request->whenFilled('email', function ($email) use ($query) {
-            $query->whereHas('user', function ($query) use ($email) {
-                $query->where('email', 'like', "%{$email}%");
+        $request->whenFilled('username', function ($username) use ($query) {
+            $query->whereHas('user', function ($query) use ($username) {
+                $query->where('username', 'like', "%{$username}%");
             });
         });
 
@@ -177,11 +177,11 @@ class LogsController extends Controller
     // 用户余额变动记录
     public function userCreditLogList(Request $request)
     {
-        $query = UserCreditLog::with('user:id,email')->latest();
+        $query = UserCreditLog::with('user:id,username')->latest();
 
-        $request->whenFilled('email', function ($value) use ($query) {
-            $query->whereHas('user', function ($query) use ($value) {
-                $query->where('email', 'like', "%{$value}%");
+        $request->whenFilled('username', function ($username) use ($query) {
+            $query->whereHas('user', function ($query) use ($username) {
+                $query->where('username', 'like', "%{$username}%");
             });
         });
 
@@ -191,11 +191,11 @@ class LogsController extends Controller
     // 用户封禁记录
     public function userBanLogList(Request $request)
     {
-        $query = UserBanedLog::with('user:id,email,t');
+        $query = UserBanedLog::with('user:id,username,t');
 
-        $request->whenFilled('email', function ($value) use ($query) {
-            $query->whereHas('user', function ($query) use ($value) {
-                $query->where('email', 'like', "%{$value}%");
+        $request->whenFilled('username', function ($username) use ($query) {
+            $query->whereHas('user', function ($query) use ($username) {
+                $query->where('username', 'like', "%{$username}%");
             });
         });
 
@@ -205,11 +205,11 @@ class LogsController extends Controller
     // 用户流量变动记录
     public function userTrafficLogList(Request $request)
     {
-        $query = UserDataModifyLog::with(['user:id,email', 'order.goods:id,name']);
+        $query = UserDataModifyLog::with(['user:id,username', 'order.goods:id,name']);
 
-        $request->whenFilled('email', function ($value) use ($query) {
-            $query->whereHas('user', function ($query) use ($value) {
-                $query->where('email', 'like', "%{$value}%");
+        $request->whenFilled('username', function ($username) use ($query) {
+            $query->whereHas('user', function ($query) use ($username) {
+                $query->where('username', 'like', "%{$username}%");
             });
         });
 
@@ -221,7 +221,7 @@ class LogsController extends Controller
     {
         $query = User::activeUser();
 
-        foreach (['email', 'wechat', 'qq'] as $field) {
+        foreach (['username', 'wechat', 'qq'] as $field) {
             $request->whenFilled($field, function ($value) use ($query, $field) {
                 $query->where($field, 'like', "%{$value}%");
             });
@@ -248,7 +248,7 @@ class LogsController extends Controller
     // 用户流量监控
     public function userTrafficMonitor(User $user)
     {
-        return view('admin.logs.userMonitor', array_merge(['email' => $user->email], $this->dataFlowChart($user->id)));
+        return view('admin.logs.userMonitor', array_merge(['username' => $user->username], $this->dataFlowChart($user->id)));
     }
 
     // 回调日志

+ 3 - 3
app/Http/Controllers/Admin/RuleController.php

@@ -69,9 +69,9 @@ class RuleController extends Controller
             });
         }
 
-        $request->whenFilled('email', function ($email) use ($query) {
-            $query->whereHas('user', function ($query) use ($email) {
-                $query->where('email', 'like', "%{$email}%");
+        $request->whenFilled('username', function ($username) use ($query) {
+            $query->whereHas('user', function ($query) use ($username) {
+                $query->where('username', 'like', "%{$username}%");
             });
         });
 

+ 5 - 5
app/Http/Controllers/Admin/SubscribeController.php

@@ -19,11 +19,11 @@ class SubscribeController extends Controller
     // 订阅码列表
     public function index(Request $request)
     {
-        $query = UserSubscribe::with(['user:id,email']);
+        $query = UserSubscribe::with(['user:id,username']);
 
-        $request->whenFilled('email', function ($value) use ($query) {
-            $query->whereHas('user', function ($query) use ($value) {
-                $query->where('email', 'like', "%{$value}%");
+        $request->whenFilled('username', function ($username) use ($query) {
+            $query->whereHas('user', function ($query) use ($username) {
+                $query->where('username', 'like', "%{$username}%");
             });
         });
 
@@ -39,7 +39,7 @@ class SubscribeController extends Controller
     //订阅记录
     public function subscribeLog($id)
     {
-        $query = UserSubscribeLog::with('user:email');
+        $query = UserSubscribeLog::with('user:username');
 
         if (isset($id)) {
             $query->whereUserSubscribeId($id);

+ 5 - 1
app/Http/Controllers/Admin/SystemController.php

@@ -11,8 +11,9 @@ use App\Notifications\Custom;
 use App\Services\TelegramService;
 use Illuminate\Http\JsonResponse;
 use Illuminate\Http\RedirectResponse;
+use Illuminate\Http\Request;
 use Notification;
-use Request;
+use NotificationChannels\Telegram\TelegramChannel;
 use Response;
 
 class SystemController extends Controller
@@ -158,6 +159,9 @@ class SystemController extends Controller
             case 'bark':
                 Notification::sendNow(BarkChannel::class, new Custom('这是测试的标题', 'ProxyPanel测试内容'));
                 break;
+            case 'telegram':
+                Notification::sendNow(TelegramChannel::class, new Custom('这是测试的标题', 'ProxyPanel测试内容'));
+                break;
             default:
                 return Response::json(['status' => 'fail', 'message' => '未知渠道']);
         }

+ 4 - 4
app/Http/Controllers/Admin/TicketController.php

@@ -22,9 +22,9 @@ class TicketController extends Controller
             $query->whereAdminId(Auth::id())->orwhere('admin_id');
         });
 
-        $request->whenFilled('email', function ($email) use ($query) {
-            $query->whereHas('user', function ($query) use ($email) {
-                $query->where('email', 'like', "%{$email}%");
+        $request->whenFilled('username', function ($username) use ($query) {
+            $query->whereHas('user', function ($query) use ($username) {
+                $query->where('username', 'like', "%{$username}%");
             });
         });
 
@@ -35,7 +35,7 @@ class TicketController extends Controller
     public function store(TicketRequest $request)
     {
         $data = $request->validated();
-        $user = User::find($data['id']) ?: User::whereEmail($data['email'])->first();
+        $user = User::find($data['uid']) ?: User::whereUsername($data['username'])->first();
 
         if ($user === Auth::user()) {
             return Response::json(['status' => 'fail', 'message' => '不能对自己发起工单']);

+ 1 - 1
app/Http/Controllers/Admin/ToolsController.php

@@ -156,8 +156,8 @@ class ToolsController extends Controller
                 DB::beginTransaction();
                 foreach ($data as $user) {
                     $obj = new User();
+                    $obj->nickname = $user->user;
                     $obj->username = $user->user;
-                    $obj->email = $user->user;
                     $obj->password = '123456';
                     $obj->port = $user->port;
                     $obj->passwd = $user->passwd;

+ 10 - 2
app/Http/Controllers/Admin/UserController.php

@@ -13,6 +13,7 @@ use App\Models\Order;
 use App\Models\User;
 use App\Models\UserGroup;
 use App\Models\UserHourlyDataFlow;
+use App\Models\UserOauth;
 use Arr;
 use Auth;
 use Exception;
@@ -37,7 +38,7 @@ class UserController extends Controller
             });
         }
 
-        foreach (['email', 'wechat', 'qq'] as $field) {
+        foreach (['username', 'wechat', 'qq'] as $field) {
             $request->whenFilled($field, function ($value) use ($query, $field) {
                 $query->where($field, 'like', "%{$value}%");
             });
@@ -147,7 +148,7 @@ class UserController extends Controller
         }
 
         return view('admin.user.info', [
-            'user'       => $user->load('inviter:id,email'),
+            'user'       => $user->load('inviter:id,username'),
             'levels'     => Level::orderBy('level')->get(),
             'userGroups' => UserGroup::orderBy('id')->get(),
             'roles'      => $roles ?? null,
@@ -302,4 +303,11 @@ class UserController extends Controller
 
         return Response::json(['status' => 'success', 'data' => $this->getUserNodeInfo($server, $request->input('type') !== 'text'), 'title' => $server['type']]);
     }
+
+    public function oauth()
+    {
+        $list = UserOauth::paginate(15)->appends(\request('page'));
+
+        return view('admin.user.oauth', compact('list'));
+    }
 }

+ 1 - 1
app/Http/Controllers/AdminController.php

@@ -62,7 +62,7 @@ class AdminController extends Controller
     public function inviteList()
     {
         return view('admin.inviteList', [
-            'inviteList' => Invite::with(['invitee:id,email', 'inviter:id,email'])->orderBy('status')->orderByDesc('id')->paginate(15)->appends(request('page')),
+            'inviteList' => Invite::with(['invitee:id,username', 'inviter:id,username'])->orderBy('status')->orderByDesc('id')->paginate(15)->appends(request('page')),
         ]);
     }
 

+ 21 - 20
app/Http/Controllers/AuthController.php

@@ -49,7 +49,7 @@ class AuthController extends Controller
 
     public function login(Request $request)
     {
-        $validator = Validator::make($request->all(), ['email' => 'required|email', 'password' => 'required']);
+        $validator = Validator::make($request->all(), ['username' => 'required', 'password' => 'required']);
 
         if ($validator->fails()) {
             return Redirect::back()->withInput()->withErrors($validator->errors());
@@ -89,7 +89,7 @@ class AuthController extends Controller
         if ($user->status === 0 && sysConfig('is_activate_account')) {
             Auth::logout(); // 强制销毁会话,因为Auth::attempt的时候会产生会话
 
-            return Redirect::back()->withInput()->withErrors(trans('auth.active.promotion.0').'<a href="'.route('active').'?email='.$user->email.
+            return Redirect::back()->withInput()->withErrors(trans('auth.active.promotion.0').'<a href="'.route('active').'?username='.$user->username.
                 '" target="_blank">👉【'.trans('common.active_item', ['attribute' => trans('common.account')]).'】👈</span></a><br>'.trans('auth.active.promotion.1'));
         }
 
@@ -192,8 +192,9 @@ class AuthController extends Controller
         $cacheKey = 'register_times_'.md5(IP::getClientIp()); // 注册限制缓存key
 
         $validator = Validator::make($request->all(), [
-            'username' => 'required',
-            'email'    => 'required|email|unique:user',
+            'nickname' => 'required',
+            // todo: 需要修改
+            'username'    => 'required|unique:user',
             'password' => 'required|min:6|confirmed',
             'term'     => 'accepted',
         ]);
@@ -245,7 +246,7 @@ class AuthController extends Controller
                 return Redirect::back()->withInput($request->except('verify_code'))->withErrors(trans('auth.captcha.required'));
             }
 
-            $verifyCode = VerifyCode::whereAddress($data['email'])->whereCode($verify_code)->whereStatus(0)->first();
+            $verifyCode = VerifyCode::whereAddress($data['username'])->whereCode($verify_code)->whereStatus(0)->first();
             if (! $verifyCode) {
                 return Redirect::back()->withInput($request->except('verify_code'))->withErrors(trans('auth.captcha.error.timeout'));
             }
@@ -281,7 +282,7 @@ class AuthController extends Controller
         $transfer_enable = MB * ((int) sysConfig('default_traffic') + ($inviter_id ? (int) sysConfig('referral_traffic') : 0));
 
         // 创建新用户
-        $user = Helpers::addUser($data['email'], $data['password'], $transfer_enable, sysConfig('default_days'), $inviter_id, $data['username']);
+        $user = Helpers::addUser($data['username'], $data['password'], $transfer_enable, sysConfig('default_days'), $inviter_id, $data['nickname']);
 
         // 注册失败,抛出异常
         if (! $user) {
@@ -309,7 +310,7 @@ class AuthController extends Controller
         // 注册后发送激活码
         if ((int) sysConfig('is_activate_account') === 2) {
             // 生成激活账号的地址
-            $token = $this->addVerifyUrl($user->id, $user->email);
+            $token = $this->addVerifyUrl($user->id, $user->username);
             $activeUserUrl = route('activeAccount', $token);
 
             $user->notifyNow(new AccountActivation($activeUserUrl));
@@ -451,7 +452,7 @@ class AuthController extends Controller
                 return Redirect::back()->withInput()->withErrors($validator->errors());
             }
 
-            $email = $request->input('email');
+            $username = $request->input('username');
 
             // 是否开启重设密码
             if (! sysConfig('password_reset_notification')) {
@@ -459,25 +460,25 @@ class AuthController extends Controller
             }
 
             // 查找账号
-            $user = User::whereEmail($email)->firstOrFail();
+            $user = User::whereUsername($username)->firstOrFail();
 
             // 24小时内重设密码次数限制
             $resetTimes = 0;
-            if (Cache::has('resetPassword_'.md5($email))) {
-                $resetTimes = Cache::get('resetPassword_'.md5($email));
+            if (Cache::has('resetPassword_'.md5($username))) {
+                $resetTimes = Cache::get('resetPassword_'.md5($username));
                 if ($resetTimes >= sysConfig('reset_password_times')) {
                     return Redirect::back()->withErrors(trans('auth.password.reset.error.throttle', ['time' => sysConfig('reset_password_times')]));
                 }
             }
 
             // 生成取回密码的地址
-            $token = $this->addVerifyUrl($user->id, $email);
+            $token = $this->addVerifyUrl($user->id, $username);
 
             // 发送邮件
             $resetUrl = route('resettingPasswd', $token);
             $user->notifyNow(new PasswordReset($resetUrl));
 
-            Cache::put('resetPassword_'.md5($email), $resetTimes + 1, Day);
+            Cache::put('resetPassword_'.md5($username), $resetTimes + 1, Day);
 
             return Redirect::back()->with('successMsg', trans('auth.password.reset.sent'));
         }
@@ -557,7 +558,7 @@ class AuthController extends Controller
                 return Redirect::back()->withInput()->withErrors($validator->errors());
             }
 
-            $email = $request->input('email');
+            $username = $request->input('username');
 
             // 是否开启账号激活
             if (! sysConfig('is_activate_account')) {
@@ -565,7 +566,7 @@ class AuthController extends Controller
             }
 
             // 查找账号
-            $user = User::whereEmail($email)->firstOrFail();
+            $user = User::whereUsername($username)->firstOrFail();
             if ($user->status === -1) {
                 return Redirect::back()->withErrors(trans('auth.error.account_baned'));
             }
@@ -576,22 +577,22 @@ class AuthController extends Controller
 
             // 24小时内激活次数限制
             $activeTimes = 0;
-            if (Cache::has('activeUser_'.md5($email))) {
-                $activeTimes = Cache::get('activeUser_'.md5($email));
+            if (Cache::has('activeUser_'.md5($username))) {
+                $activeTimes = Cache::get('activeUser_'.md5($username));
                 if ($activeTimes >= sysConfig('active_times')) {
                     return Redirect::back()->withErrors(trans('auth.active.error.throttle', ['email' => sysConfig('webmaster_email')]));
                 }
             }
 
             // 生成激活账号的地址
-            $token = $this->addVerifyUrl($user->id, $email);
+            $token = $this->addVerifyUrl($user->id, $username);
 
             // 发送邮件
             $activeUserUrl = route('activeAccount', $token);
 
-            Notification::route('mail', $email)->notifyNow(new AccountActivation($activeUserUrl));
+            Notification::route('mail', $username)->notifyNow(new AccountActivation($activeUserUrl));
 
-            Cache::put('activeUser_'.md5($email), $activeTimes + 1, Day);
+            Cache::put('activeUser_'.md5($username), $activeTimes + 1, Day);
 
             return Redirect::back()->with('successMsg', trans('auth.active.sent'));
         }

+ 5 - 3
app/Http/Controllers/Gateway/BitpayX.php

@@ -12,6 +12,7 @@ class BitpayX extends AbstractPayment
     public function purchase($request): JsonResponse
     {
         $payment = $this->creatNewPayment(Auth::id(), $request->input('id'), $request->input('amount'));
+
         $data = [
             'merchant_order_id'  => $payment->trade_no,
             'price_amount'       => (float) $payment->amount,
@@ -29,12 +30,14 @@ class BitpayX extends AbstractPayment
             $data['pay_currency'] = 'WECHAT';
         }
         $result = $this->sendRequest($data);
+
         if ($result['status'] === 200 || $result['status'] === 201) {
             $result['payment_url'] .= '&lang=zh';
             $payment->update(['url' => $result['payment_url']]);
 
             return Response::json(['status' => 'success', 'url' => $result['payment_url'], 'message' => '创建订单成功!']);
         }
+
         Log::warning('创建订单错误:'.var_export($result, true));
 
         return Response::json(['status' => 'fail', 'message' => '创建订单失败!'.$result['error']]);
@@ -44,8 +47,8 @@ class BitpayX extends AbstractPayment
     {
         $data = [
             'merchant_order_id' => $tradeNo,
-            'secret' => sysConfig('bitpay_secret'),
-            'type' => 'FIAT',
+            'secret'            => sysConfig('bitpay_secret'),
+            'type'              => 'FIAT',
         ];
         ksort($data);
 
@@ -90,7 +93,6 @@ class BitpayX extends AbstractPayment
         return $mySign === $signature;
     }
 
-    //Todo: Postman虚拟测试通过,需要真实数据参考验证
     public function notify($request): void
     {
         $tradeNo = $request->input(['merchant_order_id']);

+ 143 - 0
app/Http/Controllers/OAuth/BaseController.php

@@ -0,0 +1,143 @@
+<?php
+
+namespace App\Http\Controllers\OAuth;
+
+use App\Components\Helpers;
+use App\Components\IP;
+use App\Http\Controllers\Controller;
+use App\Models\User;
+use App\Models\UserLoginLog;
+use App\Models\UserOauth;
+use Auth;
+use Illuminate\Http\Request;
+use Laravel\Socialite\Facades\Socialite;
+use Log;
+use Redirect;
+use Str;
+
+class BaseController extends Controller
+{
+    private $type;
+
+    public function route($type, $action = null)
+    {
+        $this->type = $type;
+        if ($action === 'binding') {
+            return Socialite::driver($this->type)->with(['redirect_uri' => route('oauth.bind', ['type' => $type])])->redirect();
+        }
+
+        if ($action === 'register') {
+            return Socialite::driver($this->type)->with(['redirect_uri' => route('oauth.register', ['type' => $type])])->redirect();
+        }
+
+        return Socialite::driver($this->type)->with(['redirect_uri' => route('oauth.redirect', ['type' => $type])])->redirect();
+    }
+
+    public function redirect()
+    {
+        $info = Socialite::driver($this->type)->user();
+        if ($info) {
+            $user = User::whereUsername($info->getEmail())->first();
+            if (! $user) {
+                $user = UserOauth::whereIdentifier($info->getId())->first();
+                if ($user) {
+                    $user = $user->user;
+                }
+            }
+        }
+
+        if (isset($user)) {
+            Auth::login($user);
+            // 写入登录日志
+            $this->addUserLoginLog($user->id, IP::getClientIp());
+
+            // 更新登录信息
+            $user->update(['last_login' => time()]);
+
+            return Redirect::route('login');
+        }
+
+        return Redirect::route('login')->withErrors(trans('auth.error.not_found_user'));
+    }
+
+    /**
+     * 添加用户登录日志.
+     *
+     * @param  int  $userId  用户ID
+     * @param  string  $ip  IP地址
+     */
+    private function addUserLoginLog(int $userId, string $ip): void
+    {
+        $ipLocation = IP::getIPInfo($ip);
+
+        if (empty($ipLocation) || empty($ipLocation['country'])) {
+            Log::warning(trans('error.get_ip').':'.$ip);
+        }
+
+        $log = new UserLoginLog();
+        $log->user_id = $userId;
+        $log->ip = $ip;
+        $log->country = $ipLocation['country'] ?? '';
+        $log->province = $ipLocation['province'] ?? '';
+        $log->city = $ipLocation['city'] ?? '';
+        $log->county = $ipLocation['county'] ?? '';
+        $log->isp = $ipLocation['isp'] ?? ($ipLocation['organization'] ?? '');
+        $log->area = $ipLocation['area'] ?? '';
+        $log->save();
+    }
+
+    public function bbind()
+    {
+        $user = Auth::getUser();
+        $info = Socialite::driver($this->type)->stateless()->user();
+        if ($user) {
+            if ($info) {
+                $user->userAuths()->create([
+                    'type'       => $this->type,
+                    'identifier' => $info->getId(),
+                    'credential' => $info->token,
+                ]);
+
+                return redirect()->route('profile')->with('successMsg', '绑定成功');
+            }
+
+            return redirect()->route('profile')->withErrors('绑定失败');
+        }
+
+        return redirect()->route('profile')->withErrors('无用户');
+    }
+
+    public function register()
+    {
+        $info = Socialite::driver($this->type)->stateless()->user();
+
+        // 排除重复用户注册
+        if ($info) {
+            $user = User::whereUsername($info->getEmail())->first();
+            if (! $user) {
+                $user = UserOauth::whereIdentifier($info->getId())->first();
+                if (! $user) {
+                    $user = Helpers::addUser($info->getEmail(), Str::random(), MB * ((int) sysConfig('default_traffic')), null, $user->getNickname());
+
+                    if ($user) {
+                        $user->userAuths()->create([
+                            'type'       => $this->type,
+                            'identifier' => $info->getId(),
+                            'credential' => $info->token,
+                        ]);
+
+                        Auth::login($user);
+
+                        return redirect()->route('login');
+                    }
+
+                    return redirect()->route('register')->withErrors('注册失败');
+                }
+            }
+
+            return redirect()->route('login')->withErrors('已注册,请直接登录');
+        }
+
+        return redirect()->route('register')->withErrors('绑定失败');
+    }
+}

+ 2 - 2
app/Http/Controllers/User/AffiliateController.php

@@ -34,9 +34,9 @@ class AffiliateController extends Controller
             'totalAmount'       => ReferralLog::uid()->sum('commission') / 100,
             'canAmount'         => ReferralLog::uid()->whereStatus(0)->sum('commission') / 100,
             'aff_link'          => $aff_link,
-            'referralLogList'   => ReferralLog::uid()->with('invitee:id,email')->latest()->paginate(10, ['*'], 'log_page'),
+            'referralLogList'   => ReferralLog::uid()->with('invitee:id,username')->latest()->paginate(10, ['*'], 'log_page'),
             'referralApplyList' => ReferralApply::uid()->latest()->paginate(10, ['*'], 'apply_page'),
-            'referralUserList'  => Auth::getUser()->invitees()->select(['email', 'created_at'])->latest()->paginate(10, ['*'], 'user_page'),
+            'referralUserList'  => Auth::getUser()->invitees()->select(['username', 'created_at'])->latest()->paginate(10, ['*'], 'user_page'),
         ]);
     }
 

+ 3 - 3
app/Http/Controllers/UserController.php

@@ -173,9 +173,9 @@ class UserController extends Controller
             }
 
             // 修改联系方式
-            if ($request->has(['username', 'wechat', 'qq'])) {
-                $data = $request->only(['username', 'wechat', 'qq']);
-                if (empty($data['username'])) {
+            if ($request->has(['nickname', 'wechat', 'qq'])) {
+                $data = $request->only(['nickname', 'wechat', 'qq']);
+                if (empty($data['nickname'])) {
                     return Redirect::back()->withErrors(trans('validation.required', ['attribute' => trans('validation.attributes.username')]));
                 }
 

+ 2 - 2
app/Http/Requests/Admin/TicketRequest.php

@@ -9,8 +9,8 @@ class TicketRequest extends FormRequest
     public function rules()
     {
         return [
-            'id' => 'required_without:email|exists:user,id|numeric|nullable',
-            'email' => 'required_without:id|exists:user,email||nullable',
+            'uid' => 'required_without:username|exists:user,id|numeric|nullable',
+            'username' => 'required_without:uid|exists:user,username||nullable',
             'title' => 'required|string',
             'content' => 'required|string',
         ];

+ 2 - 2
app/Http/Requests/Admin/UserStoreRequest.php

@@ -9,8 +9,8 @@ class UserStoreRequest extends FormRequest
     public function rules(): array
     {
         return [
-            'username' => 'required',
-            'email' => 'required|unique:user,email,'.$this->user,
+            'nickname' => 'required',
+            'username' => 'required|unique:user,username,'.$this->user,
             'password' => 'nullable|string|nullable',
             'port' => 'nullable|numeric',
             'passwd' => 'nullable|string',

+ 2 - 2
app/Http/Requests/Admin/UserUpdateRequest.php

@@ -9,8 +9,8 @@ class UserUpdateRequest extends FormRequest
     public function rules(): array
     {
         return [
-            'username' => 'required',
-            'email' => 'required|unique:user,email,'.$this->user->id,
+            'nickname' => 'required',
+            'username' => 'required|unique:user,username,'.$this->user->id,
             'password' => 'nullable|string',
             'port' => 'required|numeric|exclude_if:port,0|gt:0|unique:user,port,'.$this->user->id,
             'passwd' => 'required|string',

+ 2 - 2
app/Http/Requests/Auth/RegisterRequest.php

@@ -9,8 +9,8 @@ class RegisterRequest extends FormRequest
     public function rules()
     {
         return [
-            'username' => 'required',
-            'email' => 'required|email|unique:user',
+            'nickname' => 'required',
+            'username' => 'required|unique:user',
             'password' => 'required|min:6|confirmed',
             'term' => 'accepted',
         ];

+ 25 - 20
app/Models/User.php

@@ -37,30 +37,35 @@ class User extends Authenticatable implements JWTSubject
     public function profile()
     {
         return [
-            'id' => $this->id,
-            'nickname' => $this->username,
-            'account' => $this->email,
-            'port' => $this->port,
-            'passwd' => $this->passwd,
-            'uuid' => $this->vmess_id,
+            'id'              => $this->id,
+            'nickname'        => $this->nickname,
+            'account'         => $this->username,
+            'port'            => $this->port,
+            'passwd'          => $this->passwd,
+            'uuid'            => $this->vmess_id,
             'transfer_enable' => $this->transfer_enable,
-            'u' => $this->u,
-            'd' => $this->d,
-            't' => $this->t,
-            'enable' => $this->enable,
-            'speed_limit' => $this->speed_limit,
-            'credit' => $this->credit,
-            'expired_at' => $this->expired_at,
-            'ban_time' => $this->ban_time,
-            'level' => $this->level_name,
-            'group' => $this->userGroup->name ?? null,
-            'last_login' => $this->last_login,
-            'reset_time' => $this->reset_time,
-            'invite_num' => $this->invite_num,
-            'status' => $this->status,
+            'u'               => $this->u,
+            'd'               => $this->d,
+            't'               => $this->t,
+            'enable'          => $this->enable,
+            'speed_limit'     => $this->speed_limit,
+            'credit'          => $this->credit,
+            'expired_at'      => $this->expired_at,
+            'ban_time'        => $this->ban_time,
+            'level'           => $this->level_name,
+            'group'           => $this->userGroup->name ?? null,
+            'last_login'      => $this->last_login,
+            'reset_time'      => $this->reset_time,
+            'invite_num'      => $this->invite_num,
+            'status'          => $this->status,
         ];
     }
 
+    public function userAuths(): HasMany
+    {
+        return $this->hasMany(UserOauth::class);
+    }
+
     public function onlineIpLogs(): HasMany
     {
         return $this->hasMany(NodeOnlineIp::class);

+ 17 - 0
app/Models/UserOauth.php

@@ -0,0 +1,17 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+
+class UserOauth extends Model
+{
+    protected $table = 'user_oauth';
+    protected $guarded = [];
+
+    public function user(): BelongsTo
+    {
+        return $this->belongsTo(User::class);
+    }
+}

+ 10 - 1
app/Notifications/Custom.php

@@ -7,6 +7,8 @@ use Illuminate\Bus\Queueable;
 use Illuminate\Contracts\Queue\ShouldQueue;
 use Illuminate\Notifications\Messages\MailMessage;
 use Illuminate\Notifications\Notification;
+use NotificationChannels\Telegram\TelegramChannel;
+use NotificationChannels\Telegram\TelegramMessage;
 
 class Custom extends Notification implements ShouldQueue
 {
@@ -23,7 +25,7 @@ class Custom extends Notification implements ShouldQueue
 
     public function via($notifiable)
     {
-        return $notifiable ?? ['mail', BarkChannel::class];
+        return $notifiable ?? ['mail', BarkChannel::class, TelegramChannel::class];
     }
 
     public function toMail($notifiable)
@@ -40,4 +42,11 @@ class Custom extends Notification implements ShouldQueue
             'content' => $this->content,
         ];
     }
+
+    public function toTelegram($notifiable)
+    {
+        return TelegramMessage::create()
+            ->token(sysConfig('telegram_token'))
+            ->content($this->content);
+    }
 }

+ 6 - 9
app/Services/TelegramService.php

@@ -6,18 +6,18 @@ use Illuminate\Support\Facades\Http;
 
 class TelegramService
 {
-    protected $api;
+    private $api;
 
-    public function __construct($token = '')
+    public function __construct(string $token = null)
     {
-        $this->api = 'https://api.telegram.org/bot'.($token ? $token : sysConfig('telegram_token')).'/';
+        $this->api = 'https://api.telegram.org/bot'.($token ?? sysConfig('telegram_token')).'/';
     }
 
     public function sendMessage(int $chatId, string $text, string $parseMode = '')
     {
         $this->request('sendMessage', [
-            'chat_id' => $chatId,
-            'text' => $text,
+            'chat_id'    => $chatId,
+            'text'       => $text,
             'parse_mode' => $parseMode,
         ]);
     }
@@ -29,14 +29,11 @@ class TelegramService
 
     public function setWebhook(string $url)
     {
-        return $this->request('setWebhook', [
-            'url' => $url,
-        ]);
+        return $this->request('setWebhook', ['url' => $url]);
     }
 
     private function request(string $method, array $params = [])
     {
-        $curl = new Http();
         $response = Http::get($this->api.$method.'?'.http_build_query($params));
         if (! $response->ok()) {
             abort(500, '来自TG的错误:'.$response->json());

+ 10 - 0
config/common.php

@@ -25,4 +25,14 @@ return [
             6 => 'stripe.png',
         ],
     ],
+
+    'oauth' => [
+        'facebook'  => 'FaceBook',
+        'twitter'   => 'Twitter',
+        'linkedin'  => 'Linkedin',
+        'google'    => 'Google',
+        'github'    => 'GitHub',
+        'gitlab'    => 'GitLab',
+        'bitbucket' => 'Bitbucket',
+    ],
 ];

+ 2 - 2
database/factories/UserFactory.php

@@ -8,8 +8,8 @@ use Illuminate\Database\Eloquent\Factory;
 
 $factory->define(User::class, function (Faker $faker) {
     return [
-        'username' => $faker->name,
-        'email' => $faker->unique()->safeEmail,
+        'nickname' => $faker->name,
+        'username' => $faker->unique()->safeEmail,
         'password' => Hash::make(Str::random()),
         'port' => Helpers::getPort(),
         'passwd' => Str::random(),

+ 53 - 0
database/migrations/2021_06_16_115448_oauth.php

@@ -0,0 +1,53 @@
+<?php
+
+use App\Models\Config;
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class Oauth extends Migration
+{
+    protected $configs = [
+        'oauth_path',
+        'username_type',
+    ];
+
+    public function up()
+    {
+        Schema::create('user_oauth', function (Blueprint $table) {
+            $table->increments('id');
+            $table->unsignedInteger('user_id')->unique()->comment('用户ID');
+            $table->string('type', 10)->comment('登录类型');
+            $table->string('identifier', 128)->unique()->comment('手机号/邮箱/第三方的唯一标识');
+            $table->string('credential', 128)->comment('密码/Token凭证');
+            $table->dateTime('created_at')->comment('创建时间');
+            $table->dateTime('updated_at')->comment('最后更新时间');
+            $table->foreign('user_id')->references('id')->on('user')->cascadeOnDelete();
+        });
+
+        foreach ($this->configs as $config) {
+            Config::insert(['name' => $config]);
+        }
+
+        Schema::table('user', function (Blueprint $table) {
+            $table->renameColumn('username', 'nickname');
+            $table->renameColumn('email', 'username');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('user', function (Blueprint $table) {
+            $table->renameColumn('username', 'email');
+            $table->renameColumn('nickname', 'username');
+        });
+        Config::destroy($this->configs);
+
+        Schema::dropIfExists('user_oauth');
+    }
+}

+ 1 - 1
database/migrations/2021_06_27_174304_append_v2_sni_to_node_table.php

@@ -14,7 +14,7 @@ class AppendV2SniToNodeTable extends Migration
     public function up()
     {
         Schema::table('node', function (Blueprint $table) {
-            $table->string('v2_sni', 191)->nullable()->comment('V2Ray的SNI配置');
+            $table->string('v2_sni', 191)->nullable()->comment('V2Ray的SNI配置')->after('v2_tls');
         });
     }
 

+ 195 - 0
public/assets/global/fonts/brand-icons/brand-icons.css

@@ -0,0 +1,195 @@
+@charset "UTF-8";
+@font-face {
+  font-family: "Brand Icons";
+  src: url("./brand-icons.eot?v=0.3.2");
+  src: url("./brand-icons.eot?#iefix&v=0.3.2") format("embedded-opentype"), url("./brand-icons.woff2?v=0.3.2") format("woff2"), url("./brand-icons.woff?v=0.3.2") format("woff"), url("./brand-icons.ttf?v=0.3.2") format("truetype"), url("./brand-icons.svg?v=0.3.2#brand-icons") format("svg");
+  font-weight: normal;
+  font-style: normal; }
+
+[class^="bd-"],
+[class*="bd-"] {
+  font-family: "Brand Icons";
+  position: relative;
+  display: inline-block;
+  font-style: normal;
+  font-weight: normal;
+  -webkit-transform: translate(0, 0);
+          transform: translate(0, 0);
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  speak: none;
+  text-rendering: auto; }
+
+.bd-behance:before {
+  content: ""; }
+
+.bd-blogger:before {
+  content: ""; }
+
+.bd-delicious:before {
+  content: ""; }
+
+.bd-deviantart:before {
+  content: ""; }
+
+.bd-dribbble:before {
+  content: ""; }
+
+.bd-facebook:before {
+  content: ""; }
+
+.bd-flickr:before {
+  content: ""; }
+
+.bd-foursquare:before {
+  content: ""; }
+
+.bd-github:before {
+  content: ""; }
+
+.bd-google-plus:before {
+  content: ""; }
+
+.bd-instagram:before {
+  content: ""; }
+
+.bd-lastfm:before {
+  content: ""; }
+
+.bd-linkedin:before {
+  content: ""; }
+
+.bd-pinterest:before {
+  content: ""; }
+
+.bd-quora:before {
+  content: ""; }
+
+.bd-stackoverflow:before {
+  content: ""; }
+
+.bd-rdio:before {
+  content: ""; }
+
+.bd-reddit:before {
+  content: ""; }
+
+.bd-soundcloud:before {
+  content: ""; }
+
+.bd-spotify:before {
+  content: ""; }
+
+.bd-stumbleupon:before {
+  content: ""; }
+
+.bd-tumblr:before {
+  content: ""; }
+
+.bd-twitter:before {
+  content: ""; }
+
+.bd-viadeo:before {
+  content: ""; }
+
+.bd-vimeo:before {
+  content: ""; }
+
+.bd-vine:before {
+  content: ""; }
+
+.bd-yelp:before {
+  content: ""; }
+
+.bd-openid:before {
+  content: ""; }
+
+.bd-vk:before {
+  content: ""; }
+
+.bd-yahoo:before {
+  content: ""; }
+
+.bd-xing:before {
+  content: ""; }
+
+.bd-youtube:before {
+  content: ""; }
+
+.bd-android:before {
+  content: ""; }
+
+.bd-apple:before {
+  content: ""; }
+
+.bd-windows:before {
+  content: ""; }
+
+.bd-linux:before {
+  content: ""; }
+
+.bd-wordpress:before {
+  content: ""; }
+
+.bd-drupal:before {
+  content: ""; }
+
+.bd-joomla:before {
+  content: ""; }
+
+.bd-squarespace:before {
+  content: ""; }
+
+.bd-medium:before {
+  content: ""; }
+
+.bd-dropbox:before {
+  content: ""; }
+
+.bd-codepen:before {
+  content: ""; }
+
+.bd-jsfiddle:before {
+  content: ""; }
+
+.bd-evernote:before {
+  content: ""; }
+
+.bd-envato:before {
+  content: ""; }
+
+.bd-skype:before {
+  content: ""; }
+
+.bd-paypal:before {
+  content: ""; }
+
+.bd-feed:before {
+  content: ""; }
+
+.bd-html5:before {
+  content: ""; }
+
+.bd-css3:before {
+  content: ""; }
+
+.bd-angular:before {
+  content: ""; }
+
+.bd-webchat:before {
+  content: ""; }
+
+.bd-qq:before {
+  content: ""; }
+
+.bd-zhihu:before {
+  content: ""; }
+
+.bd-weibo:before {
+  content: ""; }
+
+.bd-douban:before {
+  content: ""; }
+
+.bd-baidu:before {
+  content: ""; }

二進制
public/assets/global/fonts/brand-icons/brand-icons.eot


File diff suppressed because it is too large
+ 0 - 0
public/assets/global/fonts/brand-icons/brand-icons.min.css


+ 237 - 0
public/assets/global/fonts/brand-icons/brand-icons.svg

@@ -0,0 +1,237 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata>
+Created by FontForge 20120731 at Fri Mar 31 22:30:15 2017
+ By kaptinlin,,,
+</metadata>
+<defs>
+<font id="brand-icons" horiz-adv-x="512" >
+  <font-face 
+    font-family="brand-icons"
+    font-weight="500"
+    font-stretch="normal"
+    units-per-em="512"
+    panose-1="2 0 6 3 0 0 0 0 0 0"
+    ascent="448"
+    descent="-64"
+    bbox="-0.625 -64.5714 1033 1385"
+    underline-thickness="25"
+    underline-position="-52"
+    unicode-range="U+F101-F13A"
+  />
+<missing-glyph horiz-adv-x="187" 
+d="M17 0v341h136v-341h-136zM34 17h102v307h-102v-307z" />
+    <glyph glyph-name=".notdef" horiz-adv-x="187" 
+d="M17 0v341h136v-341h-136zM34 17h102v307h-102v-307z" />
+    <glyph glyph-name=".null" horiz-adv-x="0" 
+ />
+    <glyph glyph-name="nonmarkingreturn" horiz-adv-x="170" 
+ />
+    <glyph glyph-name="behance" unicode="&#xf101;" 
+d="M148 352q23 0 41.5 -3.5t31.5 -13.5q14 -9 21 -23.5t7 -37.5t-11 -39t-32 -26q29 -9 43.5 -29.5t14.5 -50.5q0 -24 -9.5 -41.5t-24.5 -28.5q-16 -11 -36 -16q-20 -6 -41 -6h-153v315h148zM140 225q18 0 30 9t12 29q0 11 -4 18t-11 11q-6 4 -15 5q-8 2 -18 2h-65v-74h71z
+M143 91q11 0 20 2t16 7q7 4 11.5 12t4.5 21q0 24 -14 34.5t-36 10.5h-76v-87h74zM363 92q14 -14 40 -14q19 0 33 10q13 9 17 20h55q-14 -41 -41 -58.5t-66 -17.5q-27 0 -49 8q-21 9 -36 25t-23.5 38t-8.5 48t9 48q8 23 23 38q16 16 37.5 25.5t47.5 9.5q29 0 50.5 -11
+t35.5 -31q14 -18 20 -43q6 -24 5 -51h-165q0 -29 16 -44zM435 212q-12 13 -36 13q-15 0 -25 -5.5t-16 -12.5t-8 -16q-3 -8 -3 -15h102q-2 22 -14 36zM334 331h128v-31h-128v31z" />
+    <glyph glyph-name="blogger" unicode="&#xf102;" 
+d="M510 240l2 -7l-1 -133q0 -67 -48 -115.5t-115 -48.5h-188q-67 0 -113.5 49t-46.5 117v190q0 66 46 111t114 45h114q33 0 71.5 -25.5t54.5 -60.5q1 -2 3.5 -6.5t3.5 -6.5t2.5 -7.5t3 -13.5t2.5 -19q5 -36 13 -44q7 -6 37 -6.5t34 -3.5l7 -6zM162 317q-13 0 -22 -10t-9 -23
+t9 -23t22 -10h91q12 0 21.5 10t9.5 23t-9 23t-22 10h-91zM346 67q13 0 22 10t9 23t-9 23t-22 10h-184q-13 0 -22 -10t-9 -23t9 -23t22 -10h184z" />
+    <glyph glyph-name="delicious" unicode="&#xf103;" 
+d="M512 432v-480q0 -7 -4.5 -11.5t-11.5 -4.5h-480q-7 0 -11.5 4.5t-4.5 11.5v480q0 7 4.5 11.5t11.5 4.5h480q7 0 11.5 -4.5t4.5 -11.5zM480 -32v224h-224v224h-224v-224h224v-224h224z" />
+    <glyph glyph-name="deviantart" unicode="&#xf104;" 
+d="M281 245h1l26 -56q82 17 83 22q2 8 -19.5 21.5t-64 23t-108.5 -3.5q-4 -1 -7 -1l61 -125l-234 -64q-8 12 -12 26q-24 67 29 127q30 33 79 53l-23 54l67 -1l17 -37h2.5h2.5q103 16 183 -3q44 -9 81 -26.5t56 -39.5q7 -8 11 -18l-246 -66l-53 109q37 7 68 5zM91 138
+q2 -1 10.5 0.5t19.5 4t22 5.5t19 5l7 2l-36 76q-16 -7 -26.5 -19t-15 -23.5t-6 -23t0.5 -19t5 -8.5z" />
+    <glyph glyph-name="dribbble" unicode="&#xf105;" 
+d="M256 448q106 0 181 -75t75 -181t-75 -181t-181 -75t-181 75t-75 181t75 181t181 75zM425 330q-6 -8 -15.5 -18.5t-40 -31.5t-66.5 -36q8 -16 15 -32q2 -5 4 -11q75 9 153 -7q-1 76 -50 136zM256 410q-26 0 -51 -6q44 -59 81 -128q35 13 63.5 33t37.5 29.5t14 16.5
+q-62 55 -145 55zM163 390q-46 -22 -78 -62.5t-43 -91.5q97 -1 202 27q-38 67 -81 127zM37 192q0 -84 57 -147q5 10 15 23t32 38t56.5 48t73.5 36q4 1 9 2q-8 18 -18 37q-112 -33 -225 -31v-6zM256 -27q45 0 85 17q-13 80 -46 166h-0.5h-1.5q-34 -12 -64.5 -30.5t-48 -34
+t-32 -33.5t-19 -25.5t-7.5 -13.5q59 -46 134 -46zM378 10q79 54 94 147q-66 21 -136 9q30 -83 42 -156z" />
+    <glyph glyph-name="facebook" unicode="&#xf106;" horiz-adv-x="272" 
+d="M222 363q-26 0 -36 -11.5t-10 -32.5v-55h90l-11 -96h-79v-232h-96v232h-80v96h80v64q0 57 33 88.5t86 31.5q47 0 73 -3v-82h-50z" />
+    <glyph glyph-name="flickr" unicode="&#xf107;" 
+d="M392 312q50 0 85 -35t35 -85t-35 -85t-85 -35t-85 35t-35 85t35 85t85 35zM392 104q36 0 62 26t26 62t-26 62t-62 26t-62 -26t-26 -62t26 -62t62 -26zM0 192q0 112 112 112t112 -112t-112 -112t-112 112z" />
+    <glyph glyph-name="foursquare" unicode="&#xf108;" 
+d="M492 235l1 -1q18 -17 18 -42t-18 -42l-195 -196q-18 -17 -43 -17t-42 17l-195 196q-18 17 -18 42t18 42l195 196q17 17 42 17t43 -17l88 -88l-133 -133l-62 63q-14 13 -33 13t-33 -13l-40 -40q-14 -14 -14 -33.5t14 -33.5l135 -135q9 -9 22 -13l2 -1h9q20 0 34 14z
+M507 318q5 -5 5 -12t-5 -12l-243 -243q-5 -5 -12 -5v0h-2q-5 1 -10 5l-135 136q-5 5 -5 11.5t5 11.5l40 40q5 5 12 5t12 -5l83 -83l191 191q5 5 12 5t12 -5z" />
+    <glyph glyph-name="github" unicode="&#xf109;" 
+d="M256 442q106 0 181 -75t75 -181q0 -84 -49 -150.5t-126 -92.5q-9 -2 -13.5 2t-4.5 10q0 1 0.5 25.5t0.5 44.5q0 33 -18 48q25 2 43.5 8.5t36.5 19.5t27.5 38t9.5 60q0 40 -26 69q12 30 -3 68q-21 6 -70 -27q-30 9 -64 9t-64 -9q-22 15 -39.5 21.5t-24.5 5.5h-6
+q-15 -38 -3 -68q-26 -29 -26 -69q0 -35 9.5 -60t27.5 -38t36.5 -19.5t42.5 -8.5q-13 -12 -16 -35q-49 -22 -74 22q-14 24 -40 26q-2 0 -5 -0.5t-6.5 -4t10.5 -11.5q16 -8 28 -37l2.5 -5t7.5 -11.5t15 -12.5t25 -8t36 3q0 -12 0.5 -26.5t0.5 -17.5q0 -6 -4.5 -10t-13.5 -2
+q-77 25 -126 92t-49 151q0 106 75 181t181 75z" />
+    <glyph glyph-name="google-plus" unicode="&#xf10a;" 
+d="M311 440l-40 -24h-39q2 -4 4 -6t5 -4t4 -3q4 -3 15 -21q6 -10 11 -24t5 -33q-1 -35 -16 -55q-7 -10 -15 -19q-9 -8 -19 -17q-5 -6 -10 -13q-6 -8 -6 -19q0 -10 6 -16q5 -6 10 -11l21 -18q21 -17 36 -37q14 -20 15 -53q0 -47 -41 -83q-43 -37 -123 -38q-67 0 -101 29
+q-33 26 -33 62q0 18 11 40q10 22 38 39q31 17 65 23q34 5 57 6q-7 9 -13 19q-6 11 -6 25q0 8 2 14q4 9 4 11q-10 -1 -20 -1q-51 0 -78 32q-28 30 -28 69q0 48 40 87q29 24 56 30q42 9 55 9h128zM241 84q-17 18 -53 43h-14q-5 1 -25 -1q-20 -3 -41 -9q-5 -2 -14 -6t-18 -11
+q-9 -8 -15 -20q-7 -12 -7 -29q0 -34 31 -56q29 -22 79 -22q45 0 69 20q24 19 24 49q0 24 -16 42zM220 273q1 13 1 22q0 38 -19 77q-9 18 -24 30q-15 11 -35 11q-26 0 -43 -21q-15 -21 -14 -47q0 -35 20 -73q10 -17 25.5 -29.5t35.5 -12.5q26 1 42 18q9 13 11 25zM512 240
+v-40h-72v-72h-40v72h-64v0v40h64v64h40v-64h72v0z" />
+    <glyph glyph-name="instagram" unicode="&#xf10b;" 
+d="M452 448q25 0 42.5 -17.5t17.5 -41.5v-393q0 -25 -17.5 -42.5t-42.5 -17.5h-393q-24 0 -41.5 17.5t-17.5 42.5v393q0 24 17.5 41.5t41.5 17.5h393zM255.5 291q-40.5 0 -69.5 -29t-29 -69.5t29 -69.5t69.5 -29t69.5 29t29 69.5t-29 69.5t-69.5 29zM456 16v216h-48
+q5 -25 5 -39q0 -66 -46 -112t-111.5 -46t-111.5 46t-46 112q0 13 5 39h-47v-216q0 -9 7.5 -16.5t15.5 -7.5h353q9 0 16.5 7.5t7.5 16.5zM456 310v59q0 8 -7.5 15.5t-16.5 7.5h-58q-9 0 -15.5 -7t-6.5 -16v-59q0 -8 6.5 -15t15.5 -7h58q9 0 16.5 7t7.5 15z" />
+    <glyph glyph-name="lastfm" unicode="&#xf10c;" 
+d="M226 81q-4 -4 -11 -9t-32.5 -13.5t-54.5 -8.5q-62 0 -95 35t-33 102q0 70 34 108.5t98 38.5q59 0 91 -23.5t51 -80.5l19 -59q12 -35 34.5 -54.5t63.5 -19.5q61 0 61 31q0 27 -40 36l-40 10q-68 16 -68 76q0 45 30 64.5t75 19.5q94 0 101 -74l-59 -7q-3 35 -46 35
+q-19 0 -30 -8t-11 -23q0 -14 7 -22t26 -12l38 -8q77 -18 77 -84q0 -81 -122 -81q-70 0 -104.5 27t-50.5 75l-19 59q-13 38 -30 57t-52 19q-31 0 -51.5 -23.5t-20.5 -74.5q0 -41 19 -66t50 -25q20 0 39 8.5t28 16.5l9 9z" />
+    <glyph glyph-name="linkedin" unicode="&#xf10d;" 
+d="M8 278h107v-342h-107v342zM61.5 448q25.5 0 43.5 -18t18 -43.5t-18 -43.5t-43.5 -18t-43.5 18t-18 43.5t18 43.5t43.5 18zM181 278h102v-47h1q12 23 38.5 39t62.5 16q39 0 65 -12t39 -35.5t18 -50.5t5 -64v-188h-106v166q0 16 -0.5 25.5t-3.5 23.5t-8.5 22t-16.5 14
+t-26 6q-38 0 -51 -23.5t-13 -64.5v-169h-106v342z" />
+    <glyph glyph-name="pinterest" unicode="&#xf10e;" horiz-adv-x="396" 
+d="M210 448q82 0 134 -50t52 -118q0 -88 -44 -145t-114 -57q-23 0 -43.5 11t-28.5 26q-17 -68 -21 -81q-11 -42 -53 -96q-1 -2 -4 -1.5t-3 2.5q-9 69 1 112l38 160q-10 19 -10 47q0 32 16.5 54t40.5 22q19 0 29.5 -12.5t10.5 -31.5q0 -12 -4.5 -29t-11.5 -39.5t-10 -36.5
+q-6 -23 8.5 -39.5t37.5 -16.5q41 0 67 45.5t26 110.5q0 50 -32 81.5t-90 31.5q-65 0 -105 -41.5t-40 -99.5q0 -35 20 -58q6 -7 4 -16q-1 -3 -3 -12t-3 -12q-3 -12 -15 -7q-29 12 -44.5 42.5t-15.5 69.5q0 33 13.5 64.5t39 58.5t66.5 44t91 17z" />
+    <glyph glyph-name="quora" unicode="&#xf10f;" horiz-adv-x="446" 
+d="M398 -19q3 -21 5 -42q-15 -3 -28 -3.5t-24.5 2.5t-18 5t-16.5 10t-13.5 11t-15 15.5t-14.5 15.5q-42 -14 -83.5 -10t-73.5 23t-59 48t-40 66.5t-16.5 78.5t10.5 84q15 52 52 91t86 58q11 2 34.5 7t34.5 7q102 -4 160 -50q41 -32 57 -88t8 -111.5t-35.5 -105.5t-67.5 -71
+q0 -1 1 -4t2 -4q10 -12 14.5 -16.5t15 -9.5t25.5 -7zM312 89q14 33 21.5 72.5t5.5 80t-14 74t-41 54t-71 20.5q-6 -3 -20 -8.5t-20 -8.5t-15 -9.5t-15 -15.5q-23 -32 -31.5 -91.5t4.5 -117t44 -78.5q26 -17 91 -14q-7 36 -52 35q-5 37 -6 38h6q20 12 42.5 6.5t39 -17
+t26.5 -24.5q1 0 2.5 1.5z" />
+    <glyph glyph-name="stackoverflow" unicode="&#xf110;" horiz-adv-x="1033" 
+d="M671 48h202v-44h-202v44zM956 587l42 7l35 -199l-43 -7zM611 84l202 -18l-4 -43l-202 18zM533 109l195 -52l-11 -42l-195 52zM459 98l174 -102l-22 -37l-174 102zM114 1194l-114 167l36 24l113 -167zM908 -30v176h34v-200v-10h-323h-11v210h35v-176h265z" />
+    <glyph glyph-name="rdio" unicode="&#xf111;" 
+d="M499 308q20 -2 11 -28q-13 -34 -53 -53q-9 -4 -20 -7q2 -14 2 -26v-2q0 -88 -63 -149.5t-157 -61.5t-156.5 60.5t-62.5 148.5v2q0 88 63 149.5t157 61.5q32 0 62 -8v-124q-6 3 -11 5q-40 14 -79.5 -2t-61.5 -50l-1 -2q-21 -33 -10.5 -67t49.5 -47q40 -14 80 2t61 50l1 2
+q14 22 14 46v171q6 -3 9 -4q4 -2 8 -5q101 -64 158 -62z" />
+    <glyph glyph-name="reddit" unicode="&#xf112;" 
+d="M512 197q0 -34 -30 -50q2 -9 2 -17q0 -63 -67 -107.5t-162 -44.5t-162 44.5t-67 107.5q0 9 2 18q-28 16 -28 49q0 23 16.5 39.5t40.5 16.5q22 0 38 -15q65 43 156 44l37 118l100 -23q5 13 16.5 21t26.5 8q19 0 32.5 -13.5t13.5 -32.5t-13.5 -33t-32.5 -14t-33 14t-14 33
+v1l-2 1l-83 19l-30 -96l-2 -3q87 -4 149 -44q16 15 39 15q24 0 40.5 -16.5t16.5 -39.5zM468 129.5q0 56.5 -62.5 96.5t-150.5 40t-150.5 -40t-62.5 -96.5t62.5 -96t150.5 -39.5t150.5 39.5t62.5 96zM57 237q-17 0 -29 -11.5t-12 -28.5q0 -20 16 -33q13 36 50 65q-12 8 -25 8
+zM429 228q37 -29 49 -65q18 12 18 34q0 17 -12 28.5t-29 11.5q-14 0 -26 -9zM461 359.5q0 12.5 -9 21.5t-21.5 9t-21.5 -9t-9 -21.5t9 -21.5t21.5 -9t21.5 9t9 21.5zM214 157.5q0 -14.5 -10.5 -25t-25 -10.5t-25.5 10.5t-11 25t11 25.5t25.5 11t25 -11t10.5 -25.5zM334 194
+q15 0 25.5 -11t10.5 -25.5t-10.5 -25t-25.5 -10.5t-25.5 10.5t-10.5 25t10.5 25.5t25.5 11zM256 49v-16q-56 0 -82 25l12 11q20 -20 70 -20zM256 49v-16q56 0 82 25l-12 11q-20 -20 -70 -20z" />
+    <glyph glyph-name="soundcloud" unicode="&#xf113;" 
+d="M14 106q-1 -1 -3.5 -1t-2.5 1l-8 34l8 34q0 2 2.5 2t3.5 -2l9 -34zM55 199q4 0 5 -3l7 -56l-7 -55q-1 -3 -5 -3t-4 3l-7 55l7 56q0 3 4 3zM89 85zM99.5 220q5.5 0 6.5 -4l6 -76l-6 -55q-1 -4 -6.5 -4t-5.5 4l-6 55l6 76q0 4 5.5 4zM144 257q7 0 7 -5l6 -112l-6 -54
+q0 -5 -7 -5t-7 5l-5 54l5 112q0 5 7 5zM174 86zM189 259q8 0 8 -6l5 -113l-5 -53q0 -6 -8 -6t-9 6l-4 53l4 113q1 6 9 6zM239 275q4 -2 4 -5l4 -130l-3 -47l-1 -6q0 -2 -3 -4t-7 -2t-7 2q-2 2 -2 4l-4 53l4 128v2q0 3 4 5q3 1 5.5 1t5.5 -1zM240 87v0v0v0zM449 207
+q26 0 44.5 -18.5t18.5 -44.5t-18.5 -44.5t-44.5 -18.5h-175q-6 1 -6 7v200q0 5 6 8q19 7 40 7q43 0 75 -29t36 -72q11 5 24 5z" />
+    <glyph glyph-name="spotify" unicode="&#xf114;" 
+d="M414 34q-13 -19 -31 -7q-126 78 -317 34q-9 -2 -16.5 3t-10.5 13q-2 9 3 17t13 10q210 47 350 -39q9 -4 11 -13.5t-2 -17.5zM457 133q-7 -10 -17.5 -12.5t-20.5 3.5q-73 45 -173 57t-185 -15q-11 -3 -21.5 2t-12.5 16q-3 11 2 21t16 13q98 30 209.5 16.5t195.5 -65.5
+q8 -4 11 -15t-4 -21zM461 234q-55 33 -134 48.5t-153.5 13t-130.5 -19.5q-13 -4 -25 2.5t-17 18.5q-4 13 3 25t19 17q66 19 149 22t171 -15t152 -56q12 -7 15.5 -21t-2.5 -26q-7 -10 -21 -12.5t-26 3.5z" />
+    <glyph glyph-name="stumbleupon" unicode="&#xf115;" 
+d="M0 111v71h87v-70q0 -11 8 -19t19.5 -8t19.5 8t8 19v165q0 46 33.5 78t80.5 32t80.5 -32.5t33.5 -77.5v-37l-52 -15l-35 16v32q0 11 -8 19t-19 8t-19 -8t-8 -19v-164q0 -46 -33.5 -79t-81.5 -33q-47 0 -80.5 33t-33.5 81zM283 110v71l35 -16l52 16v-72q0 -12 8 -19.5
+t19.5 -7.5t19.5 7.5t8 19.5v73h87v-71q0 -48 -33.5 -81t-80.5 -33q-48 0 -81.5 33t-33.5 80z" />
+    <glyph glyph-name="tumblr" unicode="&#xf116;" horiz-adv-x="294" 
+d="M270 39l24 -73q-7 -11 -34 -20t-54 -10q-40 -1 -71 12t-48.5 34.5t-26 44.5t-8.5 46v167h-52v66q89 32 101 138q0 4 3 4h75v-130h103v-78h-103v-159q1 -52 49 -51q24 1 42 9z" />
+    <glyph glyph-name="twitter" unicode="&#xf117;" 
+d="M512 351q-21 -32 -52 -55v-13q0 -53 -20 -105.5t-56.5 -96t-94.5 -70.5t-128 -27q-87 0 -161 47q12 -1 25 -1q73 0 131 45q-35 0 -61.5 20.5t-37.5 52.5q10 -2 20 -2q14 0 28 3q-37 8 -60.5 37t-23.5 66v2q22 -13 47 -13q-47 31 -47 87q0 28 15 53q39 -49 95.5 -78
+t120.5 -32q-3 12 -3 24q0 44 31 74.5t74 30.5q46 0 77 -33q36 7 67 25q-12 -37 -46 -58q31 4 60 17z" />
+    <glyph glyph-name="viadeo" unicode="&#xf118;" horiz-adv-x="440" 
+d="M201 448q22 -36 40 -75t25 -59l7 -20q22 -63 20.5 -113t-19 -88t-38.5 -63t-38 -38l-17 -13l-26 2q39 14 65 52t36 82t14.5 85.5t2.5 69.5l-1 28q-3 30 -11.5 57t-18 43.5t-19 28t-16.5 16.5zM289 267q-1 2 -3 5.5t-5 14t-3.5 21t4.5 24t16 24.5q14 16 54 26q5 1 12 3.5
+t23.5 16.5t26.5 34q2 -2 4.5 -7t9 -20t10 -31t2.5 -40t-9 -47q-14 -37 -42 -54q-44 -26 -88 17q4 2 11 6t25 16.5t32 24.5t26 27.5t13 29.5l-2 -4t-6.5 -10.5t-11 -15t-16.5 -17.5t-21.5 -17.5t-27.5 -15.5t-34 -11zM316 119q0 31 -11 57q22 4 42 17q14 -34 14 -73
+q0 -74 -50.5 -129t-129.5 -55q-80 0 -130.5 55t-50.5 129q0 73 48 126q52 59 133 59q33 0 62 -10q-11 -22 -13 -43q-23 9 -50 9q-55 0 -95 -41.5t-40 -100.5q0 -38 18.5 -71t49 -51t67.5 -18t68 18t49.5 51t18.5 71z" />
+    <glyph glyph-name="vimeo" unicode="&#xf119;" 
+d="M512 311q-4 -75 -105 -205q-104 -136 -176 -136q-45 0 -76 83q-3 10 -18 66t-23 86q-23 82 -50 82q-5 0 -40 -24l-24 31q40 35 75 67q50 44 76 46q59 6 73 -82q15 -94 21 -117q17 -78 38 -78q16 0 48 50.5t35 77.5q4 44 -35 44q-18 0 -38 -9q38 124 144 120
+q79 -2 75 -102z" />
+    <glyph glyph-name="vine" unicode="&#xf11a;" horiz-adv-x="438" 
+d="M435 199v-56q-35 -10 -63 -10q-28 -60 -74 -119t-68 -71q-24 -14 -48 1q-12 7 -28 23t-40 52t-45.5 82t-40.5 118.5t-28 156.5h83q15 -129 47 -211.5t80 -140.5q51 51 90 129q-43 22 -68 65t-25 97q0 57 32 95t85 38q54 0 84 -30t30 -87q0 -46 -19 -86q-28 -5 -43.5 1
+t-24.5 23q8 28 8 56q0 25 -9.5 38.5t-24.5 13.5q-16 0 -27.5 -16.5t-11.5 -43.5q0 -123 106 -125q19 0 43 7z" />
+    <glyph glyph-name="yelp" unicode="&#xf11b;" horiz-adv-x="382" 
+d="M10 201.5q6 9.5 15 9.5q5 0 89 -36l23 -10q14 -5 14 -22q-1 -17 -15 -20l-33 -11q-78 -26 -82 -25q-10 0 -15 10q-3 6 -5 21q-2 22 0.5 48t8.5 35.5zM190 -52q-3 -10 -14 -12q-15 -2 -50.5 11t-45.5 25q-4 6 -5 11q0 4 1 7q2 5 61 75l16 20q10 12 25 6t14 -20v-36
+q0 -83 -2 -87zM318 -24q-10 -4 -18 2q-4 3 -51 82l-13 22q-9 13 2 26q10 13 23 7l33 -11q78 -26 81 -29q8 -6 6 -17q-2 -15 -25.5 -45.5t-37.5 -36.5zM279 166q-21 -5 -25 -6q-14 -4 -23 11q-9 13 0 24l21 30q48 67 51 69q9 6 19 1q13 -7 34 -38.5t23 -48.5v0q0 -12 -8 -17
+q-4 -3 -92 -25zM193 239q2 -30 -14.5 -35t-31.5 20q-104 166 -106 171q-2 9 5 18q12 12 58.5 25t62.5 9q11 -3 14 -13q1 -5 6 -87.5t6 -107.5z" />
+    <glyph glyph-name="openid" unicode="&#xf11c;" 
+d="M462 242l50 33v-94h-144l44 28q-51 23 -100 31v-231l-77 -50q-69 12 -118.5 33t-75 45.5t-36 52.5t-3 55.5t27 53t50 45.5t71 33.5t84.5 17.5v80l77 50v-132q78 -10 150 -51zM235 9v235q-44 -4 -79 -20.5t-54 -40t-22.5 -51.5t10.5 -52.5t51.5 -44t93.5 -26.5z" />
+    <glyph glyph-name="vk" unicode="&#xf11d;" 
+d="M507 78q16 -26 -15 -30q-2 -1 -3 -1l-69 -1q-14 -3 -34 11q-9 6 -23.5 22.5t-25.5 26.5t-19 8q-9 -3 -13.5 -14.5t-4.5 -22.5l-1 -10q0 -9 -4 -14q-2 -2 -5.5 -3.5t-5.5 -1.5l-3 -1h-30h-8t-20 2.5t-29.5 8t-34 18t-35.5 29.5q-29 30 -59.5 80.5t-46.5 85.5l-17 36
+q-3 8 1 13q1 2 5 3t7 1l3 1h73q7 -1 12 -5l6 -8q12 -30 27 -57q22 -38 34.5 -50.5t21.5 -8.5q6 4 9 22.5t2 35.5l-1 17q1 24 -7 35q-7 9 -23 11q-6 1 5 10q3 3 6 4q15 7 64 7q22 0 36 -4q8 -1 12 -4.5t5 -12t1 -15.5t-0.5 -24t-0.5 -30q0 -2 -0.5 -10.5t0 -13t1 -11t3 -10.5
+t6.5 -7q3 -2 8 0.5t17 16.5t28 41q7 12 14.5 27t10.5 24l4 9q2 6 6 8l10 2l77 1q23 2 27 -8q6 -17 -40 -78q-6 -9 -15 -21t-13 -16t-8 -12t-5.5 -9.5t-1 -7.5t1.5 -7.5t5.5 -8t8 -9.5t13.5 -12q35 -32 50 -58z" />
+    <glyph glyph-name="yahoo" unicode="&#xf11e;" 
+d="M467 280l-6 -8h-37q-10 -2 -12 -3q-11 -3 -70 -50.5t-64 -62.5q-1 -6 -0.5 -44.5t2.5 -46.5q3 -1 35 -1.5t37 -0.5l-2 -23q-7 1 -118 1q-7 0 -50 -1t-55 -1l4 22h18t30.5 1.5t17.5 6.5q3 3 3 40.5t-1 45.5q-4 10 -58.5 77t-72.5 82h-68v31h228v-2h1l-1 -6v-23h-69
+q18 -27 54 -73t40 -52l92 83h-55l-8 31h200l-1 -2h1l-15 -20v-1zM446 97l-1 143q27 -6 67 -7l-36 -138zM440 75l20 -2l18 -1l-5 -33l-17 1l-15 2z" />
+    <glyph glyph-name="xing" unicode="&#xf11f;" horiz-adv-x="484" 
+d="M484 448l-178 -311l114 -201h-119l-115 201l178 311h120zM135 354l67 -117l-89 -146h-113l89 146l-67 117h113z" />
+    <glyph glyph-name="youtube" unicode="&#xf120;" 
+d="M508 295q4 -39 4 -81v-38l-4 -83q-4 -36 -20 -51q-16 -18 -51 -22q-45 -3 -116 -4l-63 -1q-133 1 -174 5q-1 0 -10.5 1.5t-15 2.5t-15 6t-16 12t-12 19.5t-7.5 21.5l-2 10q-6 41 -6 83v38q0 19 1.5 39.5t3.5 32.5l1 11q6 36 21 51q5 5 10.5 8.5t9.5 5.5t9.5 3.5t8.5 2
+t8 1t6 0.5h359q30 -3 51 -25q7 -7 11.5 -19t6.5 -21zM205 128l139 72l-139 72v-144z" />
+    <glyph glyph-name="android" unicode="&#xf121;" horiz-adv-x="433" 
+d="M32 282q13 0 22 -9t9 -22v-133q0 -13 -9 -22t-22 -9t-22.5 9t-9.5 22v133q0 13 9.5 22t22.5 9zM286 401q33 -17 53 -47.5t20 -66.5h-285q0 36 20 66.5t53 47.5l-22 40q-2 4 1.5 6.5t6.5 -1.5l22 -41q29 13 61.5 13t62.5 -13l22 41q2 4 6 1.5t1 -5.5zM152 339q5 0 8.5 3.5
+t3.5 8.5t-3.5 8.5t-8.5 3.5t-8.5 -3.5t-3.5 -8.5t3.5 -8.5t8.5 -3.5zM281.5 339q4.5 0 8 3.5t3.5 8.5t-3.5 8.5t-8 3.5t-8 -3.5t-3.5 -8.5t3.5 -8.5t8 -3.5zM75 276h283v-205q0 -14 -10 -23.5t-24 -9.5h-23v-70q0 -13 -9 -22.5t-22 -9.5t-22.5 9.5t-9.5 22.5v70h-43v-70
+q0 -13 -9 -22.5t-22 -9.5t-22.5 9.5t-9.5 22.5v70h-23q-14 0 -23.5 9.5t-9.5 23.5zM433 251v-132q0 -14 -9 -23t-22 -9t-22.5 9t-9.5 22v133q0 13 9.5 22t22.5 9t22 -9t9 -22z" />
+    <glyph glyph-name="apple" unicode="&#xf122;" horiz-adv-x="417" 
+d="M348 176q1 -72 69 -104q-14 -41 -36 -72q-13 -21 -22 -31.5t-24.5 -21t-31.5 -10.5q-17 -1 -40.5 9.5t-43.5 10.5q-21 0 -45 -10t-39 -11q-23 -1 -41.5 16.5t-39.5 48.5q-23 34 -38 77.5t-15.5 93.5t20.5 87q17 29 45.5 46.5t60.5 17.5q19 0 48 -11t37 -11q6 0 40.5 13
+t57.5 10q61 -2 94 -51q-56 -36 -56 -97zM284 366q-14 -17 -35 -27.5t-41 -8.5q-6 41 27 79q14 16 35 27t40 12q5 -44 -26 -82z" />
+    <glyph glyph-name="windows" unicode="&#xf123;" horiz-adv-x="510" 
+d="M0 181l208 -1l1 -202l-209 29v174zM510 448v-243l-276 -2v205zM0 376l209 28v-201l-209 -1v174zM233 178h277v-242l-276 39z" />
+    <glyph glyph-name="linux" unicode="&#xf124;" horiz-adv-x="435" 
+d="M431 19.5q3 -3.5 3.5 -7t-0.5 -6.5t-4.5 -6t-6.5 -5.5t-8.5 -5.5t-9.5 -5l-9 -4.5t-8 -3.5q-10 -5 -24 -16t-22 -18q-4 -5 -19 -6t-25 4q-6 3 -9 7t-4.5 7t-6.5 5.5t-13 3.5h-37q-6 0 -17 -1h-16q-13 -1 -23 -5t-15 -8.5t-12.5 -8t-15.5 -3.5q-8 1 -31.5 9.5t-41.5 12.5
+l-15 2.5t-14 2.5t-11.5 2.5t-10 4t-4.5 5.5q-3 7 2 19.5t5 15.5q0 4 -1 11t-2.5 12.5t-1.5 10.5t3 8q4 3 16.5 3.5t16.5 3.5q9 5 12.5 10t3.5 15q6 -21 -9 -31q-10 -5 -24 -4q-10 1 -12 -3q-4 -4 1 -16q1 -2 2.5 -5.5t2 -5l1.5 -4.5t0 -7q0 -4 -4.5 -13.5t-4.5 -13.5
+q1 -5 11 -8q6 -1 24 -5q18 -3 29 -6q6 -2 20.5 -6.5t24 -6.5t15.5 -1q12 2 18.5 8t7 13.5t-2.5 17t-5.5 15t-5.5 10.5q-35 54 -48 69q-20 21 -33 11q-3 -2 -4 5q-1 4 -1 11q1 8 3.5 14.5t6.5 13.5t6 12q3 6 8 20q5 15 8.5 22.5t8.5 17.5t11 16q32 40 36 55q-4 32 -5 89
+q-1 26 6.5 43.5t30.5 29.5q11 6 30 6q15 0 30 -4t26 -12q16 -12 26 -34.5t8 -42.5q-1 -27 9 -61q9 -32 38 -62q15 -17 28 -46.5t17 -54.5q2 -14 1.5 -24t-3 -16t-6.5 -6q-2 -1 -6 -6l-8 -10t-11.5 -9.5t-17.5 -4.5q-5 1 -9 2t-6.5 4t-4 4.5t-3.5 5.5t-2 6q-6 10 -11.5 8
+t-8 -14t1.5 -28q6 -20 0 -55q-2 -19 6 -29t20.5 -9.5t24.5 10.5q17 14 25.5 19t29.5 12q15 5 22 10.5t5.5 10t-7.5 8t-15 6.5t-14 13.5t-4.5 21t4.5 13.5q1 -9 3 -16t4 -11.5t5.5 -8.5t6 -5.5t6.5 -3.5t4 -3q6 -3 9 -6.5zM278 295q-4 -4 2 -12t11 -9q3 0 4.5 2.5t0.5 5.5
+q0 2 -1.5 3t-4 1.5t-3.5 1.5q-2 1 -3 2.5t-2 2.5l-2 2q0 1 -0.5 1t-1.5 -1zM242.5 406.5q-1.5 -1.5 -1.5 -2.5t1 -3q1 0 2 0.5t3 2.5t5 3h2t4 0.5t3 1.5q0 1 -0.5 2t-2.5 2t-3 2q-4 4 -7 4q-2 0 -3 -2t-0.5 -4t-0.5 -4q0 -1 -1.5 -2.5zM104 193q-2 -3 0 -4q1 0 3.5 2t3.5 5
+q1 1 1 2t0.5 2t0.5 1.5v0.5v1v1l-1 1q-1 0 -1.5 -1t-1.5 -3.5t-2 -4t-3 -3.5zM291 16q1 6 -1.5 21t-2 28t6.5 20q4 5 14 5q1 11 10.5 15.5t20.5 3t17 -6.5q0 5 -16 12q2 4 3 7.5t1 7.5t0.5 6.5t0.5 6.5v5.5t-1 6.5t-1.5 6t-1.5 7q-1 5 -1 7q-3 14 -13.5 29.5t-20.5 21.5
+q6 -6 16 -24q25 -46 15 -79q-3 -11 -14 -12q-9 -1 -11 5.5t-2 24t-4 30.5q-2 11 -5 19.5t-5.5 13t-4.5 7t-4 4t-2 2.5q-4 17 -9 29t-8.5 16t-6.5 9.5t-4 11.5t1.5 15.5t1 14t-12.5 7.5q-4 0 -12.5 4.5t-10.5 4.5q-2 1 -3 8t2 14.5t11 7.5q10 1 14 -8.5t1 -16.5
+q-3 -6 -0.5 -8t8.5 0q4 1 4 10v11q-1 9 -3.5 14.5t-6 8.5t-7 4.5t-7.5 1.5q-31 -2 -26 -38v-4q-3 2 -8.5 2.5t-9 0t-4.5 1.5q0 16 -5 25.5t-13 10.5q-7 0 -11.5 -8t-4.5 -17q-1 -5 0.5 -11t4 -10.5t4.5 -3.5q3 0 4 4q2 2 -2 2q-2 0 -4 4t-3 10q0 6 3 10t10 4q4 0 7 -6t3 -11
+v-6q-7 -5 -9 -9q-3 -3 -8.5 -6.5l-5.5 -3.5q-4 -4 -4.5 -7.5t2.5 -5.5q4 -2 7 -5.5t4.5 -5.5t5.5 -3.5t10 -1.5q13 -1 29 4q1 0 7 2t9.5 3t8 3.5t6.5 5.5q2 4 6 2q1 -1 1.5 -2.5t-1 -3.5t-4.5 -3q-6 -1 -16.5 -5.5t-12.5 -5.5q-13 -6 -20 -7t-23 1q-3 0 -2.5 -1t4.5 -5
+q8 -7 20 -7q4 1 9.5 2.5t10.5 4t10 4.5q4 3 8 5l7 3.5t5 1t3 -3.5l-0.5 -1t-1 -1.5t-1.5 -1t-2.5 -1.5t-2.5 -1.5l-3 -1.5t-3 -1q-8 -4 -19.5 -12.5t-19 -12.5t-13.5 0q-6 3 -18 21q-7 8 -7 6q-1 -1 -1 -3q0 -7 -4 -16t-8.5 -16t-6 -16.5t3.5 -18.5q-7 -1 -18 -25t-14 -41
+v-19.5t-2 -16.5q-2 -7 -8 -1q-9 9 -10 27q-1 8 1 16q1 5 0 5l-1 -1q-11 -19 2 -48q2 -3 7.5 -7.5t6.5 -6.5q6 -6 30 -25.5t27 -21.5q4 -5 4.5 -11.5t-4 -12t-12.5 -6.5q2 -4 8 -12.5t8 -15.5t2 -20q13 7 2 26q-1 2 -3 5l-3 3t0 2t3.5 2.5t5.5 -0.5q13 -15 48 -11q38 5 50 25
+q7 11 10 9t3 -15q-1 -7 -7 -26q-2 -7 -1.5 -11t6.5 -4q1 5 4.5 21.5t3.5 25.5zM172 347q2 0 2 -4q-1 -6 2 -6q1 0 1 1q1 5 -1 9t-3 4q-3 1 -3 -2zM246 343q0 3 -1.5 5.5t-3.5 3.5t-3 1q-4 0 -2 -2l2 -1q4 -1 5 -9l2 1zM179 326q0 -1 1 -1q2 0 3 2.5t4 3.5h-3q-5 -1 -5 -5z
+M204 330q7 3 9 -1q1 -2 -1 -2q-1 -1 -3 1.5t-5 1.5z" />
+    <glyph glyph-name="wordpress" unicode="&#xf125;" 
+d="M256 448q106 0 181 -75t75 -181t-75 -181t-181 -75t-181 75t-75 181t75 181t181 75zM26 192q0 -67 35.5 -123t94.5 -84l-110 301q-20 -45 -20 -94zM256 -38q39 0 76 13q-1 2 -1 3l-71 194l-69 -201q32 -9 65 -9zM288 300l83 -248l23 77q17 56 17 75q0 30 -19 63
+q-22 37 -22 54q0 16 11 28.5t27 12.5h3q-66 60 -155 60q-59 0 -110 -28t-82 -76h15l61 3q9 1 10 -8.5t-9 -10.5q-12 -1 -26 -2l84 -249l50 151l-36 98l-24 2q-6 0 -8 5t1 9.5t9 4.5q38 -3 60 -3l62 3q9 1 9.5 -8.5t-8.5 -10.5q-12 -1 -26 -2zM372 -7q52 31 83 83.5t31 115.5
+q0 59 -28 110q2 -11 2 -23q0 -39 -18 -83z" />
+    <glyph glyph-name="drupal" unicode="&#xf126;" horiz-adv-x="448" 
+d="M335 353q10 -6 18.5 -12t27.5 -25t32 -39t24 -53.5t11 -70.5q0 -96 -65 -156.5t-157 -60.5q-91 0 -158.5 63.5t-67.5 157.5q0 44 15 82t38 61.5t37.5 35t26.5 17.5q6 3 15.5 8t15 8t14.5 8.5t18 12.5q22 18 26 58q37 -45 54 -56q13 -9 38 -20t37 -19zM338 -18q4 4 2 9
+q-1 6 -7 1q-21 -16 -63 -16q-39 0 -57 14q-1 1 -3 1q-4 0 -8 -3q-6 -5 0 -11q24 -21 84 -15q12 1 24.5 6t19 8.5t8.5 5.5zM252 27q-8 -7 -4 -13q3 -3 15 6q15 13 31 13q17 0 24 -13q4 -7 7 -6q7 4 4 10q-6 14 -11 18q-7 5 -23 5q-13 0 -20 -3q-9 -4 -23 -17zM383 23
+q10 0 16.5 5t16.5 18q16 25 16 60q0 15 -7.5 28t-23.5 13q-12 0 -47.5 -24t-47.5 -25q-12 0 -31.5 14.5t-45 28.5t-50.5 14q-34 0 -58 -23t-24 -52q-1 -32 22 -48q16 -11 48 -11q27 0 77.5 30t62.5 30t40 -28.5t36 -29.5z" />
+    <glyph glyph-name="joomla" unicode="&#xf127;" 
+d="M149 246l53 54l51 50l10 10q22 23 52.5 30.5t59.5 -1.5q3 25 22.5 42t45.5 17q28 0 48 -20t20 -49q0 -26 -17 -45t-42 -23q8 -28 0.5 -58.5t-29.5 -52.5l-4 -4l-50 50l4 4q12 12 12 29.5t-12.5 30t-29.5 12.5t-30 -12l-10 -10l-50 -51l-54 -53zM54 312q-23 6 -38 24.5
+t-15 42.5q0 29 20 49t48 20q26 0 45 -16.5t23 -40.5q28 6 56.5 -1.5t49.5 -29.5l4 -4l-51 -50l-4 4q-12 12 -29.5 12t-29.5 -12.5t-12 -30t12 -29.5l10 -10l50 -50l54 -54l-51 -50l-53 53l-51 51l-10 10q-22 22 -29.5 53t1.5 59zM453 72q25 -3 42 -22.5t17 -44.5
+q0 -29 -20 -49t-48 -20q-25 0 -44 15.5t-24 39.5q-28 -9 -59.5 -2t-53.5 30l-4 4l50 51l4 -4q12 -13 29.5 -13t30 12.5t12.5 30t-12 29.5l-10 10l-51 51l-53 53l50 51l54 -54l50 -50l10 -10q22 -22 29.5 -50.5t0.5 -57.5zM357 133l-54 -53l-50 -51l-10 -10
+q-22 -21 -50.5 -29t-57.5 -1q-5 -23 -23.5 -38t-42.5 -15q-29 0 -49 20t-20 49q0 24 15 42.5t38 23.5q-8 29 0 58t29 51l4 4l51 -51l-4 -4q-12 -12 -12 -29.5t12 -30t29.5 -12.5t29.5 13l10 10l51 50l53 54z" />
+    <glyph glyph-name="squarespace" unicode="&#xf128;" 
+d="M81.5 174.5q-7.5 7.5 -7.5 17.5t7 17l158 158q28 29 69 29t70 -29q7 -8 7 -18t-7 -17.5t-17 -7.5t-18 8q-14 14 -34.5 14t-35.5 -14l-157 -157q-7 -8 -17 -8t-17.5 7.5zM326 279l-157 -157q-29 -29 -70 -29t-70 29t-29 70t29 70l119 119q15 15 35.5 15t34.5 -15
+l-154 -154q-15 -15 -15 -35t14.5 -34.5t35 -14.5t35.5 14l157 157q7 8 17.5 8t17.5 -7.5t7 -17.5t-7 -18zM483 262q29 -29 29 -70t-29 -70l-119 -119q-15 -15 -35.5 -15t-34.5 15l154 154q15 15 15 35t-14.5 34.5t-35 14.5t-35.5 -14l-157 -157q-7 -8 -17.5 -8t-17.5 7.5
+t-7 17.5t7 18l157 157q29 29 70 29t70 -29zM430.5 209.5q7.5 -7.5 7.5 -17.5t-7 -17l-158 -158q-28 -29 -69 -29t-70 29q-8 8 -8 18t7.5 17.5t17.5 7.5t18 -8q14 -14 34.5 -14t35.5 14l157 157q7 8 17 8t17.5 -7.5z" />
+    <glyph glyph-name="medium" unicode="&#xf129;" 
+d="M492 334q-6 0 -11 -6t-5 -11v-252q0 -5 5 -11t11 -6h20v-58h-182v58h37v264h-2l-90 -322h-69l-89 322h-1v-264h38v-58h-154v58h20q6 0 11 6t5 11v252q0 5 -5 11t-11 6h-20v60h192l63 -234h2l64 234h191v-60h-20z" />
+    <glyph glyph-name="dropbox" unicode="&#xf12a;" 
+d="M151 430l105 -88l-152 -94l-104 84zM0 165l104 83l152 -93l-105 -88zM256 155l152 93l104 -83l-151 -98zM512 332l-104 -84l-152 94l105 88zM256 136l106 -88l45 30v-34l-151 -90l-151 90v34l46 -30z" />
+    <glyph glyph-name="codepen" unicode="&#xf12b;" 
+d="M512 273v-3v-156v-3v-1q-1 -1 -1 -2v-1q0 -1 -0.5 -1.5l-1 -1t-0.5 -1.5l-0.5 -1l-0.5 -1l-1.5 -1.5l-1 -1l-0.5 -0.5l-1 -1l-1 -1h-1l-234 -156q-5 -4 -12 -4t-12 4l-234 156h-1l-0.5 0.5l-1 1l-1 1l-1.5 1.5l-0.5 0.5t-1 1.5t-0.5 1.5t-0.5 1t-0.5 1.5q-1 0 -1 1v1
+t-1 2v1v3v156v3v1q1 1 1 2v1q0 1 1 1q0 1 0.5 1.5t0.5 1.5l0.5 1t1 1.5l0.5 0.5l1.5 1.5l1 1l1 1l0.5 0.5h1l234 156q12 8 24 0l234 -156h1l0.5 -0.5l1.5 -1.5l0.5 -0.5l1 -1l1 -1t1 -1.5l0.5 -1q0 -1 0.5 -1.5l1 -1t0.5 -1.5v-1t1 -2v-1zM278 385v-103l95 -64l77 52z
+M234 385l-172 -115l77 -52l95 64v103zM44 229v-74l55 37zM234 -1v103l-95 64l-77 -52zM256 140l78 52l-78 52l-78 -52zM278 -1l172 115l-77 52l-95 -64v-103zM468 155v74l-55 -37z" />
+    <glyph glyph-name="jsfiddle" unicode="&#xf12c;" 
+d="M495 171.5q17 -24.5 17 -55.5q0 -41 -29.5 -70t-71.5 -29h-2.5h-2.5h-305q-42 3 -71.5 32t-29.5 70q0 27 13.5 50.5t36.5 36.5q-3 10 -3 21q0 28 20.5 48.5t50.5 20.5q23 0 43 -14q19 38 55.5 61.5t81.5 23.5q41 0 76.5 -20t55.5 -54.5t20 -75.5v-4.5v-4.5
+q28 -12 45 -36.5zM388.5 93q20.5 18 21.5 48q0 30 -21 47.5t-52 17.5q-36 0 -60 -24q4 -4 7 -8q0 -1 9 -10q4 -6 7 -9q16 16 35 16q13 0 23 -8t10 -21q0 -14 -9 -23t-23 -9q-11 0 -21 5.5t-18 14t-16.5 18.5t-17.5 20.5t-19 19t-24 13.5t-30 5q-30 0 -51.5 -17.5
+t-21.5 -47.5t21 -48t52 -18q34 0 60 25q-4 5 -12 14t-11 13q-17 -16 -36 -16q-14 0 -23.5 8t-9.5 22q0 13 10 21.5t23 8.5q11 0 21 -5t18 -13.5t16 -19t17.5 -20.5t19.5 -18.5t24 -14t30 -5.5q31 0 51.5 18z" />
+    <glyph glyph-name="evernote" unicode="&#xf12d;" horiz-adv-x="428" 
+d="M43 349q-17 0 -30 -6l-5 -2l94 93l-1 -3q-6 -11 -6 -24v-1q0 -11 1 -52q0 -5 -5 -5h-48zM417 359q5 -28 9 -107.5t1 -111.5q-8 -86 -22 -130q-9 -27 -17 -42t-21 -22t-24.5 -8.5t-36.5 -1.5q-55 0 -74 13t-19 55q0 43 17.5 53.5t62.5 9.5q3 -2 3 -3t-2 -6.5t-2 -10.5
+q0 -4 1 -9t0.5 -6.5t-3.5 -1.5h-4h-5.5h-5t-5 -0.5l-4.5 -1.5t-4 -2.5t-3 -3t-2.5 -4t-0.5 -6.5q0 -7 2 -11.5t4 -7t9 -3.5t11 -1h17q29 0 37 6.5t8 32.5q0 39 -9.5 52.5t-28.5 16.5q-45 5 -61 10q-27 10 -27 61q0 1 -1 1t-1 -1q0 -34 -10 -62q-3 -10 -4 -12q-6 -12 -19 -13
+t-31 4q-63 8 -101 24q-12 6 -19 20q-16 34 -30 135l-2 26q0 20 8 30q5 7 13 10q10 5 24 5h48q8 0 13.5 5.5t5.5 13.5v1v3.5v5v6v6.5q-1 24 -1 30q0 14 7 23q8 11 25 16q7 4 37.5 3t50 -9t23.5 -31q41 1 70 -2q47 -6 66 -13q22 -8 27 -34zM319 206q19 -1 35 -8q-1 36 -27 37
+q-24 1 -28 -30q10 1 20 1z" />
+    <glyph glyph-name="envato" unicode="&#xf12e;" horiz-adv-x="465" 
+d="M401 445q36 -64 52 -139.5t10 -147.5t-46.5 -130t-112.5 -81q-48 -13 -95 -9.5t-88 27t-70.5 56t-43 78t-3.5 93.5q10 52 46 100q19 26 25 16q0 -2 -3 -27.5t-5 -54t7 -58.5t31 -42q-4 11 1.5 40.5t19 68.5t39 79t57.5 73t79 50t100 8z" />
+    <glyph glyph-name="skype" unicode="&#xf12f;" 
+d="M494 149q18 -32 18 -69q0 -60 -42 -101.5t-101 -41.5q-38 0 -71 18q1 0 2 0.5l1 0.5l-5 1q0 -1 1 -1.5l1 -0.5q-21 -4 -42 -4q-49 0 -94 19q-43 19 -76.5 52.5t-52.5 76.5q-19 45 -19 94q0 21 4 42l0.5 -1t0.5 -2l-1 5v-1v-1q-18 32 -18 69q0 60 42 101.5t101 41.5
+q36 0 67 -16l-2 -1l5 -1q-1 1 -1.5 1t-1.5 1q23 4 46 4q49 0 94 -19q44 -18 77.5 -51.5t51.5 -77.5q19 -45 19 -94q0 -22 -4 -44q0 1 -0.5 1.5t-0.5 1.5v-5q1 0 1 1v1zM257 45q59 0 90.5 25.5t31.5 66.5q0 67 -77 84l-57 13q-14 3 -22 6t-16 9.5t-8 16.5q0 15 13 24.5
+t36 9.5q21 0 35.5 -7t20.5 -15t14 -14.5t18 -6.5q13 0 22 7t9 19q0 28 -36.5 48t-78.5 20q-49 0 -83.5 -22t-34.5 -67q0 -62 72 -80l77 -19q29 -7 29 -31q0 -15 -15 -26.5t-40 -11.5q-23 0 -38.5 8t-21.5 18t-15 18.5t-21 8.5t-20 -8t-8 -20q0 -27 32.5 -50.5t91.5 -23.5z
+" />
+    <glyph glyph-name="paypal" unicode="&#xf130;" horiz-adv-x="434" 
+d="M137 144l-24 -155v3h-99q-7 0 -11 4.5t-3 10.5l66 420q2 9 8.5 15t14.5 6h159q86 0 121 -40q6 -7 14 -21q15 -29 8 -73q-1 -5 -2 -9q-28 -145 -184 -145h-47q-17 0 -21 -16zM424 281q16 -31 6 -81q-25 -128 -161 -128h-13q-17 0 -19 -15l-1 -4l-16 -99l-1 -3
+q-2 -15 -19 -15h-60l4 23l24 150q1 8 7.5 13.5t14.5 5.5h47q156 0 184 145q1 5 2 9z" />
+    <glyph glyph-name="feed" unicode="&#xf131;" horiz-adv-x="510" 
+d="M0 5q0 68 68 68t68 -68t-68 -68t-68 68zM0 448q104 0 198.5 -40.5t162.5 -109t108.5 -163.5t40.5 -199h-98q0 112 -55 207.5t-150 151t-207 55.5v98zM0 274q91 0 168.5 -45.5t123 -123t45.5 -169.5h-99q0 100 -69.5 170t-168.5 70v98z" />
+    <glyph glyph-name="html5" unicode="&#xf132;" horiz-adv-x="363" 
+d="M0 347h363l-33 -370l-149 -41l-148 41zM294 260l1 12h-114h-114l2 -12l11 -126h101h56l-5 -59l-51 -13v0l-50 13l-4 37h-45l6 -72l93 -25v0l93 25l1 8l11 120l1 12h-106h-60l-4 46h64h110l1 10zM330 402v-23h-56v69h23v-46h33zM57 402v-23h-23v69h23v-23h21v23h23v-69
+h-23v23h-21zM131 379v46h-20v23h64v-23h-21v-46h-23zM207 413v-34h-22v69h24l15 -24l15 24h24v-69h-23v34l-16 -24h-1z" />
+    <glyph glyph-name="css3" unicode="&#xf133;" horiz-adv-x="366" 
+d="M0 347h366l-35 -371l-148 -40l-149 40zM292 227l4 45h-113h-116l6 -45h110v0h5l-5 -2l-106 -44l4 -45h102v0h55l-4 -59l-51 -14v0h-1l-49 12l-3 37h-46l6 -70l93 -28v0l93 27l12 140h-105h-1h1zM291 402v-22h-56v22h22l-12.5 12.5l-9.5 9.5v24h56v-24h-22zM131 402v-22
+h-57v68h57v-24h-33v-22h33zM211 402v-22h-56v22h22q-6 6 -12.5 12t-9.5 10v24h56v-24h-22z" />
+    <glyph glyph-name="angular" unicode="&#xf134;" horiz-adv-x="483" 
+d="M240 193h3h48l-50 105l-45 -105h44zM241 448l242 -83l-38 -316l-204 -113l-203 112l-38 315zM343 73l53 -1l-156 333v0v0l-149 -332l56 1l30 75h63h70z" />
+    <glyph glyph-name="webchat" unicode="&#xf135;" 
+d="M187 144q-5 -27 4 -53q-36 -3 -73 10q-59 -35 -60 -36t-3 0.5t-2 2.5l16 56q-69 48 -69 125q0 65 54 112.5t129 46.5q72 -2 121 -40.5t62 -95.5q-32 3 -68 -7.5t-69.5 -42t-41.5 -78.5zM257 324q-10 0 -16.5 -7t-6.5 -16.5t6.5 -16.5t16.5 -7t17 7t7 16.5t-7 16.5t-17 7z
+M113.5 277q9.5 0 16.5 7t7 16.5t-7 16.5t-16.5 7t-16.5 -7t-7 -16.5t7 -16.5t16.5 -7zM512 128q0 -62 -54 -104l14 -44q0 -3 -4 -4l-46 27q-31 -12 -65 -12q-68 0 -113 40t-45 96t46 94t112 38q63 0 109 -38t46 -93zM299 156q9 0 15 6t6 15t-6 15t-15 6t-15 -6t-6 -15t6 -15
+t15 -6zM411.5 156q8.5 0 14.5 6t6 15t-6 15t-14.5 6t-15 -6t-6.5 -15t6.5 -15t15 -6z" />
+    <glyph glyph-name="qq" unicode="&#xf136;" horiz-adv-x="466" 
+d="M438 188q1 -2 3 -5q25 -40 25 -72q0 -22 -5.5 -41t-17.5 -19q-7 0 -19 15q-10 11 -15 21l-1.5 -6t-3.5 -12.5t-6 -14.5t-11 -15.5t-16 -12.5q27 -14 38 -23.5t11 -23.5q0 -10 -10.5 -20t-28.5 -16q-50 -14 -100 -1q-14 3 -48 22q-34 -19 -48 -22q-50 -13 -100 1
+q-18 6 -28.5 16t-10.5 20q0 14 11 23.5t38 23.5q-9 5 -16 12.5t-11 15.5t-6 14.5t-3.5 12.5l-1.5 6q-5 -10 -15 -21q-12 -15 -19 -15q-12 0 -17.5 19t-5.5 41q0 16 5 31t8.5 21.5t14.5 24.5q3 5 10 13.5t10 13.5q1 2 0.5 8.5t0.5 15.5q1 16 10 32q-1 9 3.5 36t14.5 45
+q17 32 42.5 53.5t51 29.5t39 10.5t23.5 2.5t23.5 -2.5t39 -10.5t51 -29.5t42.5 -53.5q10 -18 14.5 -45t3.5 -36q9 -16 10 -32q1 -8 0.5 -15.5t0.5 -8.5q3 -5 10 -13.5t10 -13.5z" />
+    <glyph glyph-name="zhihu" unicode="&#xf137;" 
+d="M507 380q5 0 5 -4v-189v-186q0 -6 -5 -6h-83q-11 -3 -72 -42q-3 9 -6.5 20t-5 16.5t-2.5 5.5h-31q-6 0 -6 6v230.5v143.5q0 5 6 5h106h94zM469 41q0 73 0.5 144.5t0.5 150.5q0 4 -4 4q-29 0 -55.5 -0.5t-63.5 -0.5q-4 0 -4 -3v-121v-174q0 -4 4 -4h13l1.5 -5t3.5 -14
+t4 -15q35 21 52 33q1 1 2 1h43q3 0 3 4zM167 164q-4 -35 -7 -48l-6 -24q4 4 24 21q37 -40 65 -75q4 -5 4 -7q9 -20 -2 -62h-1q-3 4 -29.5 37.5t-63.5 76.5q-24 -88 -67 -125q-4 -4 -21 -9q-7 -3 -18 -5.5t-25.5 -3t-19.5 4.5l1 2q18 14 35 30q52 53 75 121q9 29 13 65h-115
+v1q5 36 23 41h41h56q5 73 4 128q-36 0 -54 -1q-1 -3 -6 -19q-6 -16 -23 -29t-44 -15q11 21 22.5 50t21 57t12.5 35q5 10 11 15q12 11 27 15q13 3 16 2q-7 -15 -14 -38q-4 -12 -9 -31h75h82q7 -1 11 -13t2 -29h-88q-2 -79 -5 -127h51h42q11 -2 11 -41h-53h-54z" />
+    <glyph glyph-name="weibo" unicode="&#xf138;" 
+d="M389 199q26 -8 44.5 -25.5t18.5 -44.5q0 -52 -67.5 -98.5t-167.5 -46.5q-85 0 -151 38t-66 98q0 68 77 144q49 48 99 67.5t71 -1.5q19 -19 6 -60q-3 -8 4.5 -7.5t7.5 1.5q41 17 72 17t44 -18t0 -51q-3 -6 -0.5 -8.5t8.5 -4.5zM218 14q64 7 106 40.5t39 74.5v1
+q-4 42 -52.5 67t-112.5 19q-63 -6 -105 -38t-41 -73v-5q4 -42 52.5 -67t113.5 -19zM225 175q32 -8 46 -34t1 -54q-13 -29 -46 -42.5t-65 -3.5q-31 10 -42.5 36t2.5 53q13 26 43.5 39.5t60.5 5.5zM194 83q6 10 3.5 19.5t-12.5 14t-21.5 0.5t-17.5 -13.5t-3.5 -19t12.5 -14
+t21.5 -1t17.5 13.5zM221.5 117.5q5.5 9.5 -4.5 12.5q-9 3 -14 -5.5t4 -12.5t14.5 5.5zM477.5 354q24.5 -28 32 -65.5t-3.5 -71.5q-3 -8 -10 -11.5t-15 -1t-11.5 10t-0.5 15.5q16 54 -20 97q-18 20 -42.5 28t-48.5 2q-8 -1 -15 3.5t-8.5 12.5t3 15t12.5 9q34 8 68.5 -3.5
+t59 -39.5zM419 228q-7 2 -10 8.5t-1 13.5q6 18 -6.5 32.5t-30.5 10.5q-7 -2 -12.5 2t-7 11t2 13t10.5 8q37 8 62.5 -21t13.5 -67q-2 -7 -8 -10t-13 -1z" />
+    <glyph glyph-name="douban" unicode="&#xf139;" 
+d="M380 2h132v-59h-512v59h132l-31 103h-57v233h424v-233h-58zM117 163h278v116h-278v-116zM321 3l30 102h-191l31 -102h130zM14 441h484v-59h-484v59z" />
+    <glyph glyph-name="baidu" unicode="&#xf13a;" horiz-adv-x="471" 
+d="M121 346q-1 3 -1.5 9t-0.5 9q-2 9 0 20q9 43 34 58q5 3 13 5q1 0 3 0.5t3 0.5q11 0 18 -3q22 -9 34 -39t4 -62q-12 -48 -50 -54q-14 -2 -30 9q-19 15 -27 47zM63 178q-15 -3 -31 7q-17 11 -26.5 34t-3.5 49q9 43 34 58q5 3 12 4q1 0 3.5 0.5t3.5 0.5q23 0 40 -16.5
+t23 -38.5q7 -26 -2 -56q-12 -35 -53 -42zM307 285q-21 4 -31 15.5t-15 33.5q-2 15 0 27q2 14 3 17q11 36 43 54q2 1 5.5 2.5t4.5 1.5h3h3q10 1 23 -8q15 -9 26.5 -29.5t6.5 -42.5q-7 -39 -31 -57q-21 -18 -41 -14zM391 103q29 -23 38 -43q8 -22 4.5 -48.5t-15.5 -42.5
+q-8 -12 -21 -20q-14 -9 -36 -12t-44 1q-11 2 -21 4q-4 1 -13.5 3.5t-14.5 4.5q-5 1 -15 1.5t-14 1.5h-14q-2 0 -7 -0.5t-7 -0.5q-32 -6 -33 -6q-5 -1 -15 -2t-15 -2h-10q-9 -1 -16 0h-11q-2 0 -8.5 0.5t-9.5 1.5q-16 4 -30 15q-20 16 -28 48.5t6 61.5q7 12 16 22.5
+t15.5 16.5t21.5 17q5 4 14.5 13t14.5 13q3 3 9 10q3 3 10.5 12t11.5 14q2 2 7 10t8.5 13t8.5 8q18 14 34 19q2 1 7.5 1.5t8.5 1.5q28 1 52 -17q12 -8 29 -34l15 -18t11 -14q8 -9 22 -22q4 -3 15.5 -14.5t18.5 -17.5zM217 -17v174h-31h-1v-47h-1h-38q-35 -6 -49 -39
+q-2 -4 -3 -14q-2 -11 1 -24q8 -40 44 -50h35h43zM349 -17v124h-32v-95h-18q-24 0 -28 5q-1 2 -1.5 7.5t-0.5 9.5v5v68h-33v-65v-5q0 -34 11 -44q3 -3 7 -5t8 -3t10.5 -1.5t10 -0.5h12h11.5h43zM128 61q6 17 24 20h31v-69h-18q-14 0 -17 1q-13 4 -19 17.5t-1 30.5zM469 242
+q4 -14 1 -30v-10.5t-1 -10.5q-9 -38 -40 -46q-13 -4 -27 -1q-20 4 -30.5 11.5t-16.5 24.5q-1 5 -1.5 13.5t-1.5 11.5v23q4 25 5 26q8 26 29 35q7 2 10 3h3.5h3.5q50 1 66 -50z" />
+  </font>
+</defs></svg>

二進制
public/assets/global/fonts/brand-icons/brand-icons.ttf


二進制
public/assets/global/fonts/brand-icons/brand-icons.woff


二進制
public/assets/global/fonts/brand-icons/brand-icons.woff2


+ 2 - 0
resources/lang/en/auth.php

@@ -29,6 +29,7 @@ return [
         'account_baned'  => 'Your account has been banned!',
         'login_error'    => 'Login error, please try again later!',
         'login_failed'   => 'Login failed, please check whether the email or password is entered correctly!',
+        'not_found_user' => 'Did not find your account base on your account email, Please find a other way to login',
         'repeat_request' => 'Please refresh the page and try again',
         'url_timeout'    => 'The link has expired, please try again',
     ],
@@ -74,5 +75,6 @@ return [
     ],
     'remember_me'     => 'Remember me',
     'request'         => 'Request',
+    'sign_in_with'    => 'Sign in with :app',
     'tos'             => 'Terms of Service',
 ];

+ 2 - 0
resources/lang/zh_CN/auth.php

@@ -26,6 +26,7 @@ return [
         'account_baned'  => '您的账号已被禁止登录!',
         'login_error'    => '登录错误,请稍后重试!',
         'login_failed'   => '登录失败,请检查邮箱或密码是否输入正确!',
+        'not_found_user' => '未找到关联账号,请使用其他方式登录',
         'repeat_request' => '请勿重复请求,请刷新后重试',
         'url_timeout'    => '链接已失效, 请重新操作',
     ],
@@ -68,5 +69,6 @@ return [
     ],
     'remember_me'     => '记住我',
     'request'         => '获 取',
+    'sign_in_with'    => ':app账号登录',
     'tos'             => '用户条款',
 ];

+ 3 - 3
resources/views/admin/aff/index.blade.php

@@ -11,7 +11,7 @@
             <div class="panel-body">
                 <form class="form-row">
                     <div class="form-group col-lg-2 col-sm-4">
-                        <input type="text" class="form-control" name="email" value="{{Request::query('email')}}" placeholder="申请账号"/>
+                        <input type="text" class="form-control" name="username" value="{{Request::query('username')}}" placeholder="申请账号"/>
                     </div>
                     <div class="form-group col-lg-2 col-sm-4">
                         <select class="form-control" name="status" id="status" onchange="this.form.submit()">
@@ -50,10 +50,10 @@
                                 @else
                                     @can('admin.user.index')
                                         <a href="{{route('admin.user.index', ['id'=>$apply->user_id])}}" target="_blank">
-                                            {{$apply->user->email}}
+                                            {{$apply->user->username}}
                                         </a>
                                     @else
-                                        {{$apply->user->email}}
+                                        {{$apply->user->username}}
                                     @endcan
                                 @endif
                             </td>

+ 4 - 4
resources/views/admin/aff/rebate.blade.php

@@ -11,10 +11,10 @@
             <div class="panel-body">
                 <form class="form-row">
                     <div class="form-group col-lg-4 col-sm-6">
-                        <input type="text" class="form-control" name="invitee_email" value="{{Request::query('invitee_email')}}" placeholder="消费者"/>
+                        <input type="text" class="form-control" name="invitee_username" value="{{Request::query('invitee_username')}}" placeholder="消费者"/>
                     </div>
                     <div class="form-group col-lg-4 col-sm-6">
-                        <input type="text" class="form-control" name="inviter_email" value="{{Request::query('inviter_email')}}" placeholder="邀请人"/>
+                        <input type="text" class="form-control" name="inviter_username" value="{{Request::query('inviter_username')}}" placeholder="邀请人"/>
                     </div>
                     <div class="form-group col-lg-2 col-sm-6">
                         <select name="status" id="status" class="form-control" onchange="this.form.submit()">
@@ -51,14 +51,14 @@
                                 @if(empty($referralLog->invitee))
                                     【{{trans('common.deleted_item', ['attribute' => trans('common.account')])}}】
                                 @else
-                                    <a href="{{route('admin.aff.rebate',['invitee_email' => $referralLog->invitee->email])}}"> {{$referralLog->invitee->email}} </a>
+                                    <a href="{{route('admin.aff.rebate',['invitee_username' => $referralLog->invitee->username])}}"> {{$referralLog->invitee->username}} </a>
                                 @endif
                             </td>
                             <td>
                                 @if(empty($referralLog->inviter))
                                     【{{trans('common.deleted_item', ['attribute' => trans('common.account')])}}】
                                 @else
-                                    <a href="{{route('admin.aff.rebate',['inviter_email' => $referralLog->inviter->email])}}"> {{$referralLog->inviter->email}} </a>
+                                    <a href="{{route('admin.aff.rebate',['inviter_username' => $referralLog->inviter->username])}}"> {{$referralLog->inviter->username}} </a>
                                 @endif
                             </td>
                             <td> {{$referralLog->order_id}} </td>

+ 36 - 34
resources/views/admin/config/system.blade.php

@@ -81,8 +81,8 @@
                                     </div>
                                 </div>
                             </div>
-                            <x-system.select title="禁止访问模式" code="forbid_mode" :list="['关闭' => '', '阻拦大陆'=> 'ban_mainland', '阻拦中国' => 'ban_china', '阻拦海外' => 'ban_oversea']"
-                                             help="依据IP对对应地区进行阻拦,非阻拦地区可正常访问"/>
+                            <x-system.select title="禁止访问模式" code="forbid_mode" help="依据IP对对应地区进行阻拦,非阻拦地区可正常访问"
+                                             :list="['关闭' => '', '阻拦大陆'=> 'ban_mainland', '阻拦中国' => 'ban_china', '阻拦海外' => 'ban_oversea']"/>
                             <x-system.switch title="阻止机器人访问" code="is_forbid_robot" :check="$is_forbid_robot" help="如果是机器人、爬虫、代理访问网站则会抛出404错误"/>
                             <x-system.switch title="维护模式" code="maintenance_mode" :check="$maintenance_mode"
                                              help="启用后,用户访问转移至维护界面 | 管理员使用 <a href='javascript:(0)'>{{route('admin.login')}}</a> 登录"/>
@@ -92,6 +92,8 @@
                         </x-system.tab-pane>
                         <x-system.tab-pane id="account">
                             <x-system.switch title="用户注册" code="is_register" :check="$is_register" help="关闭后无法注册"/>
+                            <x-system.select title="第三方登录平台" code="oauth_path" help="请在.ENV中添加设置,再在此处开启平台"  multiple="1"
+                                             :list="array_flip(config('common.oauth'))"/>
                             <x-system.select title="邀请注册" code="is_invite_register" :list="['关闭' => '', '可选'=> 1, '必须' => 2]"/>
                             <x-system.select title="激活账号" code="is_activate_account" :list="['关闭' => '', '注册前激活'=> 1, '注册后激活' => 2]" help="启用后用户需要通过邮件来激活账号"/>
                             <x-system.select title="重置密码" code="password_reset_notification" :list="['关闭' => '', '邮箱'=> 'mail']" help="启用后用户可以重置密码"/>
@@ -104,8 +106,8 @@
                             <x-system.input-limit title="初始流量" code="default_traffic" :value="$default_traffic" unit="MB" help="用户注册时默认可用流量"/>
                             <x-system.input-limit title="可生成邀请码数" code="invite_num" :value="$invite_num" help="用户可以生成的邀请码数"/>
                             <x-system.input-limit title="重置密码次数" code="reset_password_times" :value="$reset_password_times" help="24小时内可以通过邮件重置密码次数"/>
-                            <x-system.select title="邮箱过滤机制" code="is_email_filtering" :list="['关闭' => '', '黑名单' => 1, '白名单' => 2]"
-                                             help="黑名单: 用户可使用任意黑名单外的邮箱注册;白名单:用户只能选择使用白名单中的邮箱后缀注册"/>
+                            <x-system.select title="邮箱过滤机制" code="is_email_filtering" help="黑名单: 用户可使用任意黑名单外的邮箱注册;白名单:用户只能选择使用白名单中的邮箱后缀注册"
+                                             :list="['关闭' => '', '黑名单' => 1, '白名单' => 2]"/>
                             <x-system.input-limit title="激活账号次数" code="active_times" :value="$active_times" help="24小时内可以通过邮件激活账号次数"/>
                             <x-system.input-limit title="同IP注册限制" code="register_ip_limit" :value="$register_ip_limit" help="同IP在24小时内允许注册数量,为0时不限制"/>
                             <x-system.input-limit title="用户-邀请码有效期" code="user_invite_days" :value="$user_invite_days" min="1" unit="天" help="用户自行生成邀请的有效期"/>
@@ -123,9 +125,8 @@
                             <x-system.input title="V2Ray TLS配置" :value="$v2ray_tls_provider" code="v2ray_tls_provider" help="后端自动签发/载入TLS证书时用(节点的设置值优先级高于此处)"/>
                         </x-system.tab-pane>
                         <x-system.tab-pane id="extend">
-                            <x-system.select title="DDNS模式" code="ddns_mode"
-                                             :list="['关闭' => '', 'Namesilo' => 'namesilo', '阿里云(国际&国内)' => 'aliyun', 'DNSPod' => 'dnspod', 'CloudFlare' => 'cloudflare']"
-                                             help="添加/编辑/删除节点的【域名、ipv4、ipv6】时,自动更新对应内容至DNS服务商"/>
+                            <x-system.select title="DDNS模式" code="ddns_mode" help="添加/编辑/删除节点的【域名、ipv4、ipv6】时,自动更新对应内容至DNS服务商"
+                                             :list="['关闭' => '', 'Namesilo' => 'namesilo', '阿里云(国际&国内)' => 'aliyun', 'DNSPod' => 'dnspod', 'CloudFlare' => 'cloudflare']"/>
                             <x-system.input title="DNS服务商Key" :value="$ddns_key" code="ddns_key"
                                             help="浏览<a href='https://proxypanel.gitbook.io/wiki/ddns' target='_blank'>设置指南</a>来设置"/>
                             <x-system.input title="DNS服务商Secret" :value="$ddns_secret" code="ddns_secret"/>
@@ -151,37 +152,37 @@
                             <x-system.input-limit title="提现限制" code="referral_money" :value="$referral_money" unit="元" help="满多少元才可以申请提现"/>
                         </x-system.tab-pane>
                         <x-system.tab-pane id="notify">
-                            <x-system.select title="账号过期通知" code="account_expire_notification" :list="['邮箱' => 'mail', '站内通知' => 'database']"
-                                             help="通知用户账号即将到期" multiple="1"/>
-                            <x-system.input-limit title="过期警告阈值" code="expire_days" :value="$expire_days" unit="元" help="【账号过期通知】开始阈值,每日通知用户"/>
-                            <x-system.select title="流量耗尽通知" code="data_exhaust_notification" :list="['邮箱' => 'mail', '站内通知' => 'database']"
-                                             help="通知用户流量即将耗尽" multiple="1"/>
-                            <x-system.input-limit title="流量警告阈值" code="traffic_warning_percent" :value="$traffic_warning_percent" unit="%" help="【流量耗尽通知】开始阈值,每日通知用户"/>
-                            <x-system.select title="节点离线提醒" code="node_offline_notification" :list="['邮箱' => 'mail', 'Bark' => 'bark', 'ServerChan' => 'serverChan', 'Telegram' => 'telegram']"
-                                             help="每10分钟检测节点离线并提醒管理员" multiple="1"/>
-                            <x-system.input-limit title="离线提醒次数" code="offline_check_times" :value="$offline_check_times" unit="次" help="24小时内提醒n次后不再提醒"/>
-                            <x-system.select title="节点阻断提醒" code="node_blocked_notification" :list="['邮箱' => 'mail', 'ServerChan' => 'serverChan', 'Telegram' => 'telegram']"
-                                             help="每小时检测节点是否被阻断并提醒管理员" multiple="1"/>
-                            <x-system.input-limit title="阻断检测提醒" code="detection_check_times" :value="$detection_check_times" max="12" unit="次"
-                                                  help="提醒N次后自动下线节点,为0时不限制,不超过12"/>
-                            <x-system.select title="支付成功通知" code="payment_received_notification" :list="['邮箱' => 'mail', '站内通知' => 'database', 'Telegram' => 'telegram']"
-                                             help="用户支付订单后通知用户订单状态" multiple="1"/>
-                            <x-system.select title="工单关闭通知" code="ticket_closed_notification" :list="['邮箱' => 'mail', 'Bark' => 'bark', 'ServerChan' => 'serverChan', 'Telegram' => 'telegram']"
-                                             help="工单关闭通知用户" multiple="1"/>
-                            <x-system.select title="新工单通知" code="ticket_created_notification" :list="['邮箱' => 'mail', 'Bark' => 'bark', 'ServerChan' => 'serverChan', 'Telegram' => 'telegram']"
-                                             help="新工单通知管理/用户,取决于谁创建了新工单" multiple="1"/>
-                            <x-system.select title="工单回复通知" code="ticket_replied_notification" :list="['邮箱' => 'mail', 'Bark' => 'bark', 'ServerChan' => 'serverChan', 'Telegram' => 'telegram']"
-                                             help="工单回复通知对方" multiple="1"/>
                             <x-system.input-test title="SCKEY" :value="$server_chan_key" code="server_chan_key" help='启用ServerChan,请务必填入本值(<a href=https://sc.ftqq.com
                                     target=_blank>申请SCKEY</a>)' holder="请到ServerChan申请" test="serverChan"/>
                             <x-system.input-test title="Bark设备号" :value="$bark_key" code="bark_key" holder="安装并打开Bark后取得" type="url"
                                                  help="推送消息到iOS设备,需要在iOS设备里装一个名为Bark的应用,取网址后的一长串代码,启用Bark,请务必填入本值" test="bark"/>
+                            <x-system.input-test title="Telegram Token" :value="$telegram_token" code="telegram_token" help="找 <a href=https://t.me/BotFather
+                                    target=_blank>@BotFather</a> 申请机器人"  test="telegram"/>
                             <x-system.switch title="PushBear" code="is_push_bear" :check="$is_push_bear"
                                              help='使用PushBear推送微信消息给用户(<a href="https://pushbear.ftqq.com/admin/#/signin" target="_blank">创建消息通道</a>)'/>
                             <x-system.input title="PushBear SendKey" :value="$push_bear_send_key" code="push_bear_send_key" help="启用PushBear,请务必填入本值" holder="创建消息通道后即可获取"/>
-                            <x-system.input title="TelegramToken" :value="$telegram_token" code="telegram_token" help="启用telegram_bot,请务必填入本值" holder="在@BotFather创建后即可获取"/>
                             <x-system.input title="PushBear订阅二维码" :value="$push_bear_qrcode" code="push_bear_qrcode" help="创建消息通道后,在二维码上点击右键“复制图片地址”并粘贴至此处"
                                             holder="填入消息通道的二维码URL" type="url"/>
+                            <hr class="col-10"/>
+                            <x-system.select title="账号过期通知" code="account_expire_notification" help="通知用户账号即将到期" multiple="1" :list="['邮箱' => 'mail', '站内通知' => 'database']"/>
+                            <x-system.input-limit title="过期警告阈值" code="expire_days" :value="$expire_days" unit="元" help="【账号过期通知】开始阈值,每日通知用户"/>
+                            <x-system.select title="流量耗尽通知" code="data_exhaust_notification" help="通知用户流量即将耗尽" multiple="1" :list="['邮箱' => 'mail', '站内通知' => 'database']"/>
+                            <x-system.input-limit title="流量警告阈值" code="traffic_warning_percent" :value="$traffic_warning_percent" unit="%" help="【流量耗尽通知】开始阈值,每日通知用户"/>
+                            <x-system.select title="节点离线提醒" code="node_offline_notification" help="每10分钟检测节点离线并提醒管理员" multiple="1"
+                                             :list="['邮箱' => 'mail', 'Bark' => 'bark', 'ServerChan' => 'serverChan', 'Telegram' => 'telegram']"/>
+                            <x-system.input-limit title="离线提醒次数" code="offline_check_times" :value="$offline_check_times" unit="次" help="24小时内提醒n次后不再提醒"/>
+                            <x-system.select title="节点阻断提醒" code="node_blocked_notification" help="每小时检测节点是否被阻断并提醒管理员" multiple="1"
+                                             :list="['邮箱' => 'mail', 'ServerChan' => 'serverChan', 'Telegram' => 'telegram']"/>
+                            <x-system.input-limit title="阻断检测提醒" code="detection_check_times" :value="$detection_check_times" max="12" unit="次"
+                                                  help="提醒N次后自动下线节点,为0时不限制,不超过12"/>
+                            <x-system.select title="支付成功通知" code="payment_received_notification" help="用户支付订单后通知用户订单状态" multiple="1"
+                                             :list="['邮箱' => 'mail', '站内通知' => 'database', 'Telegram' => 'telegram']"/>
+                            <x-system.select title="工单关闭通知" code="ticket_closed_notification" help="工单关闭通知用户" multiple="1"
+                                             :list="['邮箱' => 'mail', 'Bark' => 'bark', 'ServerChan' => 'serverChan', 'Telegram' => 'telegram']"/>
+                            <x-system.select title="新工单通知" code="ticket_created_notification" help="新工单通知管理/用户,取决于谁创建了新工单" multiple="1"
+                                             :list="['邮箱' => 'mail', 'Bark' => 'bark', 'ServerChan' => 'serverChan', 'Telegram' => 'telegram']"/>
+                            <x-system.select title="工单回复通知" code="ticket_replied_notification" help="工单回复通知对方" multiple="1"
+                                             :list="['邮箱' => 'mail', 'Bark' => 'bark', 'ServerChan' => 'serverChan', 'Telegram' => 'telegram']"/>
                         </x-system.tab-pane>
                         <x-system.tab-pane id="auto">
                             <x-system.switch title="自动清除日志" code="is_clear_log" :check="$is_clear_log" help='(推荐)启用后自动清除无用日志'/>
@@ -189,14 +190,14 @@
                             <x-system.switch title="订阅异常自动封禁" code="is_subscribe_ban" :check="$is_subscribe_ban" help='启用后用户订阅链接请求超过设定阈值则自动封禁'/>
                             <x-system.input-limit title="订阅请求阈值" code="subscribe_ban_times" :value="$subscribe_ban_times" help="24小时内订阅链接请求次数限制"/>
                             <x-system.switch title="异常自动封号" code="is_traffic_ban" :check="$is_traffic_ban" help='1小时内流量超过异常阈值则自动封号(仅禁用代理)'/>
-                            <x-system.select title="流量异常通知" code="data_anomaly_notification" :list="['邮箱' => 'mail', 'Bark' => 'bark', 'ServerChan' => 'serverChan']"
-                                             help="1小时内流量超过异常阈值通知超管" multiple="1"/>
+                            <x-system.select title="流量异常通知" code="data_anomaly_notification" help="1小时内流量超过异常阈值通知超管" multiple="1"
+                                             :list="['邮箱' => 'mail', 'Bark' => 'bark', 'ServerChan' => 'serverChan', 'Telegram' => 'telegram']"/>
                             <x-system.input-limit title="流量异常阈值" code="traffic_ban_value" :value="$traffic_ban_value" min="1" unit="GB" help="1小时内超过该值,则触发自动封号"/>
                             <x-system.input-limit title="封号时长" code="traffic_ban_time" :value="$traffic_ban_time" unit="分钟" help="触发流量异常导致用户被封禁的时长,到期后自动解封"/>
                             <x-system.switch title="端口回收机制" code="auto_release_port" :check="$auto_release_port" help="被封禁/过期{{config('tasks.release_port')}}天的账号端口自动释放"/>
                             <x-system.switch title="过期自动封禁" code="is_ban_status" :check="$is_ban_status" help="(慎重)封禁整个账号会重置账号的所有数据且会导致用户无法登录,不开启状态下只封禁用户代理"/>
-                            <x-system.select title="节点使用报告" code="node_daily_notification" :list="['邮箱' => 'mail', 'ServerChan' => 'serverChan']"
-                                             help="报告各节点流量昨日消耗情况" multiple="1"/>
+                            <x-system.select title="节点使用报告" code="node_daily_notification" help="报告各节点流量昨日消耗情况" multiple="1"
+                                             :list="['邮箱' => 'mail', 'ServerChan' => 'serverChan', 'Telegram' => 'telegram']"/>
                         </x-system.tab-pane>
                         <x-system.tab-pane id="other">
                             @if($errors->any())
@@ -404,6 +405,7 @@
             $('#is_QQPay').selectpicker('val', '{{$is_QQPay}}');
             $('#is_WeChatPay').selectpicker('val', '{{$is_WeChatPay}}');
             $('#is_otherPay').selectpicker('val', '{{$is_otherPay}}');
+            $('#oauth_path').selectpicker('val', {!! $oauth_path !!});
             $('#account_expire_notification').selectpicker('val', {!! $account_expire_notification !!});
             $('#data_anomaly_notification').selectpicker('val', {!! $data_anomaly_notification !!});
             $('#data_exhaust_notification').selectpicker('val', {!! $data_exhaust_notification !!});
@@ -497,7 +499,7 @@
             }
         }
 
-        // 发送Bark测试消息
+        // 使用通知渠道 发送测试消息
         @can('admin.test.notify')
         function sendTestNotification(channel) {
             $.post('{{route('admin.test.notify')}}', {_token: '{{csrf_token()}}', channel: channel}, function(ret) {

+ 2 - 2
resources/views/admin/inviteList.blade.php

@@ -54,13 +54,13 @@
                                     </td>
                                     <td> {{$invite->dateline}} </td>
                                     <td>
-                                        {{$invite->inviter_id === null ? '系统生成' : ($invite->inviter->email ?? '【'.trans('common.deleted_item', ['attribute' => trans('common.account')]).'】')}}
+                                        {{$invite->inviter_id === null ? '系统生成' : ($invite->inviter->username ?? '【'.trans('common.deleted_item', ['attribute' => trans('common.account')]).'】')}}
                                     </td>
                                     <td>
                                         {!!$invite->status_label!!}
                                     </td>
                                     <td>
-                                        {{$invite->status === 1 ? ($invite->invitee->email ?? '【'.trans('common.deleted_item', ['attribute' => trans('common.account')]).'】') : ''}}
+                                        {{$invite->status === 1 ? ($invite->invitee->username ?? '【'.trans('common.deleted_item', ['attribute' => trans('common.account')]).'】') : ''}}
                                     </td>
                                 </tr>
                             @endforeach

+ 7 - 0
resources/views/admin/layouts.blade.php

@@ -85,6 +85,13 @@
                                     </a>
                                 </li>
                             @endcan
+                            @can('admin.user.oauth')
+                                <li class="site-menu-item {{request()->routeIs('admin.user.oauth') ? 'active open' : ''}}">
+                                    <a href="{{route('admin.user.oauth')}}">
+                                        <span class="site-menu-title">用户授权</span>
+                                    </a>
+                                </li>
+                            @endcan
                             @can('admin.user.group.index')
                                 <li class="site-menu-item {{request()->routeIs('admin.user.group.*') ? 'active open' : ''}}">
                                     <a href="{{route('admin.user.group.index')}}">

+ 1 - 1
resources/views/admin/logs/notification.blade.php

@@ -11,7 +11,7 @@
             <div class="panel-body">
                 <form class="form-row">
                     <div class="form-group col-lg-3 col-sm-4">
-                        <input type="text" class="form-control" name="email" value="{{Request::query('email')}}" placeholder="用户账号"/>
+                        <input type="text" class="form-control" name="username" value="{{Request::query('username')}}" placeholder="用户账号"/>
                     </div>
                     <div class="form-group col-lg-2 col-sm-4">
                         <select class="form-control" name="type" id="type" onchange="this.form.submit()">

+ 2 - 2
resources/views/admin/logs/onlineIPMonitor.blade.php

@@ -16,7 +16,7 @@
                         <input type="number" class="form-control" name="id" value="{{Request::query('id')}}" placeholder="用户ID"/>
                     </div>
                     <div class="form-group col-lg-2 col-sm-5">
-                        <input type="text" class="form-control" name="email" value="{{Request::query('email')}}" placeholder="用户账号"/>
+                        <input type="text" class="form-control" name="username" value="{{Request::query('username')}}" placeholder="用户账号"/>
                     </div>
                     <div class="form-group col-lg-2 col-sm-5">
                         <input type="text" class="form-control" name="ip" value="{{Request::query('ip')}}" placeholder="IP"/>
@@ -55,7 +55,7 @@
                             <td>{{$log->id}}</td>
                             <td>{{$log->type}}</td>
                             <td>{{$log->node->name ?? '【节点已删除】'}}</td>
-                            <td>{{$log->user->email ?? '【用户已删除】'}}</td>
+                            <td>{{$log->user->username ?? '【用户已删除】'}}</td>
                             <td>
                                 @if (strpos($log->ip, ',') !== false)
                                     @foreach (explode(',', $log->ip) as $ip)

+ 3 - 3
resources/views/admin/logs/order.blade.php

@@ -12,7 +12,7 @@
             <div class="panel-body">
                 <form class="form-row">
                     <div class="form-group col-lg-2 col-sm-6">
-                        <input type="text" class="form-control" name="email" value="{{Request::query('email')}}" placeholder="用户账号"/>
+                        <input type="text" class="form-control" name="username" value="{{Request::query('username')}}" placeholder="用户账号"/>
                     </div>
                     <div class="form-group col-lg-2 col-sm-6">
                         <input type="number" class="form-control" name="sn" value="{{Request::query('sn')}}" placeholder="订单号"/>
@@ -102,9 +102,9 @@
                                     【账号不存在】
                                 @else
                                     @can('admin.user.index')
-                                        <a href="{{route('admin.user.index', ['id'=>$order->user->id])}}" target="_blank">{{$order->user->email}} </a>
+                                        <a href="{{route('admin.user.index', ['id'=>$order->user->id])}}" target="_blank">{{$order->user->username}} </a>
                                     @else
-                                        {{$order->user->email}}
+                                        {{$order->user->username}}
                                     @endcan
                                 @endif
                             </td>

+ 3 - 3
resources/views/admin/logs/traffic.blade.php

@@ -15,7 +15,7 @@
                         <input type="number" class="form-control" name="user_id" value="{{Request::query('user_id')}}" placeholder="用户ID"/>
                     </div>
                     <div class="form-group col-lg-3 col-sm-8">
-                        <input type="text" class="form-control" name="email" value="{{Request::query('email')}}" placeholder="用户账号"/>
+                        <input type="text" class="form-control" name="username" value="{{Request::query('username')}}" placeholder="用户账号"/>
                     </div>
                     <div class="form-group col-lg-2 col-sm-4">
                         <input type="number" class="form-control" name="port" value="{{Request::query('port')}}" placeholder="用户端口"/>
@@ -69,9 +69,9 @@
                                     【{{trans('common.deleted_item', ['attribute' => trans('common.account')])}}】
                                 @else
                                     @can('admin.user.index')
-                                        <a href="{{route('admin.user.index', ['id' => $log->user->id])}}" target="_blank"> {{$log->user->email}} </a>
+                                        <a href="{{route('admin.user.index', ['id' => $log->user->id])}}" target="_blank"> {{$log->user->username}} </a>
                                     @else
-                                        {{$log->user->email}}
+                                        {{$log->user->username}}
                                     @endcan
                                 @endif
                             </td>

+ 3 - 3
resources/views/admin/logs/userBanHistory.blade.php

@@ -11,7 +11,7 @@
             <div class="panel-body">
                 <form class="form-row">
                     <div class="form-group col-lg-3 col-sm-6">
-                        <input type="text" class="form-control" name="email" value="{{Request::query('email')}}" placeholder="用户账号"/>
+                        <input type="text" class="form-control" name="username" value="{{Request::query('username')}}" placeholder="用户账号"/>
                     </div>
                     <div class="form-group col-lg-2 col-sm-6 btn-group">
                         <button type="submit" class="btn btn-primary">搜 索</button>
@@ -38,9 +38,9 @@
                             <td>
                                 @if ($log->user)
                                     @can('admin.user.index')
-                                        <a href="{{route('admin.user.index', ['email'=>$log->user->email])}}" target="_blank"> {{$log->user->email}}</a>
+                                        <a href="{{route('admin.user.index', ['username'=>$log->user->username])}}" target="_blank"> {{$log->user->username}}</a>
                                     @else
-                                        {{$log->user->email}}
+                                        {{$log->user->username}}
                                     @endcan
                                 @else
                                     【{{trans('common.deleted_item', ['attribute' => trans('common.account')])}}】

+ 2 - 2
resources/views/admin/logs/userCreditHistory.blade.php

@@ -11,7 +11,7 @@
             <div class="panel-body">
                 <form class="form-row">
                     <div class="form-group col-lg-3 col-sm-6">
-                        <input type="text" class="form-control" name="email" value="{{Request::query('email')}}" placeholder="用户账号"/>
+                        <input type="text" class="form-control" name="username" value="{{Request::query('username')}}" placeholder="用户账号"/>
                     </div>
                     <div class="form-group col-lg-2 col-sm-6 btn-group">
                         <button type="submit" class="btn btn-primary">搜 索</button>
@@ -39,7 +39,7 @@
                                 @if(empty($log->user))
                                     【{{trans('common.deleted_item', ['attribute' => trans('common.account')])}}】
                                 @else
-                                    <a href="{{route('admin.log.credit', ['email'=>$log->user->email])}}"> {{$log->user->email}} </a>
+                                    <a href="{{route('admin.log.credit', ['username'=>$log->user->username])}}"> {{$log->user->username}} </a>
                                 @endif
                             </td>
                             <td> {{$log->order_id}} </td>

+ 1 - 1
resources/views/admin/logs/userMonitor.blade.php

@@ -9,7 +9,7 @@
                 <button class="close" data-dismiss="alert" aria-label="Close">
                     <span aria-hidden="true">&times;</span><span class="sr-only">{{trans('common.close')}}</span>
                 </button>
-                <h4 class="block">{{$email}}</h4>
+                <h4 class="block">{{$username}}</h4>
                 <strong>提示:</strong> 如果无统计数据,请检查定时任务是否正常。
             </div>
             <div class="panel-body">

+ 2 - 2
resources/views/admin/logs/userOnlineIP.blade.php

@@ -16,7 +16,7 @@
                         <input type="number" class="form-control" name="id" value="{{Request::query('id')}}" placeholder="ID"/>
                     </div>
                     <div class="form-group col-lg-3 col-sm-8">
-                        <input type="text" class="form-control" name="email" value="{{Request::query('email')}}" placeholder="用户账号"/>
+                        <input type="text" class="form-control" name="username" value="{{Request::query('username')}}" placeholder="用户账号"/>
                     </div>
                     <div class="form-group col-lg-2 col-sm-6">
                         <input type="text" class="form-control" name="wechat" value="{{Request::query('wechat')}}" placeholder="微信"/>
@@ -47,7 +47,7 @@
                     @foreach ($userList as $user)
                         <tr>
                             <td> {{$user->id}} </td>
-                            <td> {{$user->email}} </td>
+                            <td> {{$user->username}} </td>
                             <td> {{$user->port}} </td>
                             <td>
                                 @if ($user->status > 0)

+ 2 - 2
resources/views/admin/logs/userTraffic.blade.php

@@ -11,7 +11,7 @@
             <div class="panel-body">
                 <form class="form-row">
                     <div class="form-group col-lg-4 col-sm-6">
-                        <input type="text" class="form-control" name="email" value="{{Request::query('email')}}" placeholder="用户账号"/>
+                        <input type="text" class="form-control" name="username" value="{{Request::query('username')}}" placeholder="用户账号"/>
                     </div>
                     <div class="form-group col-lg-2 col-sm-6 btn-group">
                         <button type="submit" class="btn btn-primary">搜 索</button>
@@ -38,7 +38,7 @@
                                 @if(empty($log->user))
                                     【{{trans('common.deleted_item', ['attribute' => trans('common.account')])}}】
                                 @else
-                                    <a href="{{route('admin.log.flow', ['email' => $log->user->email])}}"> {{$log->user->email}} </a>
+                                    <a href="{{route('admin.log.flow', ['username' => $log->user->username])}}"> {{$log->user->username}} </a>
                                 @endif
                             </td>
                             <td>

+ 2 - 2
resources/views/admin/rule/log.blade.php

@@ -21,7 +21,7 @@
                         <input type="number" class="form-control" name="user_id" value="{{Request::query('user_id')}}" placeholder="用户ID"/>
                     </div>
                     <div class="form-group col-xxl-2 col-lg-3 col-md-3 col-sm-4">
-                        <input type="text" class="form-control" name="email" value="{{Request::query('email')}}" placeholder="用户账号"/>
+                        <input type="text" class="form-control" name="username" value="{{Request::query('username')}}" placeholder="用户账号"/>
                     </div>
                     <div class="form-group col-xxl-1 col-lg-3 col-md-3 col-4">
                         <select class="form-control" id="node_id" name="node_id">
@@ -61,7 +61,7 @@
                         <tr>
                             <td> {{$ruleLog->id}} </td>
                             <td> {{$ruleLog->user->id ?? '【'.trans('common.deleted_item', ['attribute' => trans('common.account')]).'】'}} </td>
-                            <td> {{$ruleLog->user->email ?? '【'.trans('common.deleted_item', ['attribute' => trans('common.account')]).'】'}} </td>
+                            <td> {{$ruleLog->user->username ?? '【'.trans('common.deleted_item', ['attribute' => trans('common.account')]).'】'}} </td>
                             <td> {{empty($ruleLog->node) ? '【节点已删除】' : '【节点ID:' . $ruleLog->node_id . '】' . $ruleLog->node->name}} </td>
                             <td> {{$ruleLog->rule_id ? '⛔  ' . ($ruleLog->rule->name ?? '【规则已删除】') : '✅  访问非规则允许内容'}} </td>
                             <td> {{$ruleLog->reason}} </td>

+ 3 - 3
resources/views/admin/subscribe/index.blade.php

@@ -14,7 +14,7 @@
                         <input type="number" class="form-control" name="user_id" value="{{Request::query('user_id')}}" placeholder="ID"/>
                     </div>
                     <div class="form-group col-lg-4 col-sm-6">
-                        <input type="text" class="form-control" name="email" value="{{Request::query('email')}}" placeholder="用户账号"/>
+                        <input type="text" class="form-control" name="username" value="{{Request::query('username')}}" placeholder="用户账号"/>
                     </div>
                     <div class="form-group col-lg-3 col-sm-6">
                         <select name="status" id="status" class="form-control" onchange="this.form.submit()">
@@ -50,9 +50,9 @@
                                     【{{trans('common.deleted_item', ['attribute' => trans('common.account')])}}】
                                 @else
                                     @can('admin.user.index')
-                                        <a href="{{route('admin.user.index', ['id'=>$subscribe->user->id])}}" target="_blank">{{$subscribe->user->email}}</a>
+                                        <a href="{{route('admin.user.index', ['id'=>$subscribe->user->id])}}" target="_blank">{{$subscribe->user->username}}</a>
                                     @else
-                                        {{$subscribe->user->email}}
+                                        {{$subscribe->user->username}}
                                     @endcan
                                 @endif
                             </td>

+ 1 - 1
resources/views/admin/subscribe/log.blade.php

@@ -24,7 +24,7 @@
                     @foreach($subscribeLog as $subscribe)
                         <tr>
                             <td>{{$subscribe->id}}</td>
-                            <td>{{$subscribe->user->email ?? '用户已删除'}}</td>
+                            <td>{{$subscribe->user->username ?? '用户已删除'}}</td>
                             <td>
                                 @if ($subscribe->request_ip)
                                     <a href="https://www.ipip.net/ip/{{$subscribe->request_ip}}.html" target="_blank">{{$subscribe->request_ip}}</a>

+ 7 - 7
resources/views/admin/ticket/index.blade.php

@@ -106,11 +106,11 @@
                         <div class="form-group row">
                             <label for="domain" class="col-2 col-form-label">域名</label>
                             <div class="input-group col-10">
-                                <input type="number" class="form-control col-md-4" name="user_id" id="user_id" placeholder="用户ID"/>
+                                <input type="number" class="form-control col-md-4" name="uid" id="uid" placeholder="用户ID"/>
                                 <div class="input-group-prepend">
                                     <span class="input-group-text">或</span>
                                 </div>
-                                <input type="email" class="form-control col-md-8" name="user_email" id="user_email" placeholder="用户邮箱"/>
+                                <input type="text" class="form-control col-md-8" name="username" id="username" placeholder="用户邮箱"/>
                             </div>
                         </div>
                         <div class="form-group">
@@ -136,12 +136,12 @@
         @can('admin.ticket.store')
         // 发起工单
         function createTicket() {
-            const id = $('#user_id').val();
-            const email = $('#user_email').val();
+            const uid = $('#uid').val();
+            const username = $('#username').val();
             const title = $('#title').val();
             const content = $('#content').val();
 
-            if (id.trim() === '' && email.trim() === '') {
+            if (uid.trim() === '' && username.trim() === '') {
                 swal.fire({title: '请填入目标用户信息!', icon: 'warning'});
                 return false;
             }
@@ -169,8 +169,8 @@
                         url: "{{route('admin.ticket.store')}}",
                         data: {
                             _token: '{{csrf_token()}}',
-                            id: id,
-                            email: email,
+                            uid: uid,
+                            username: username,
                             title: title,
                             content: content,
                         },

+ 1 - 1
resources/views/admin/user/export.blade.php

@@ -7,7 +7,7 @@
     <div class="page-content container-fluid">
         <div class="panel">
             <div class="panel-heading">
-                <h2 class="panel-title">【{{$user->email}}】连接配置信息</h2>
+                <h2 class="panel-title">【{{$user->username}}】连接配置信息</h2>
             </div>
             <div class="panel-body">
                 <table class="text-md-center" data-toggle="table" data-mobile-responsive="true">

+ 8 - 8
resources/views/admin/user/index.blade.php

@@ -35,7 +35,7 @@
                         <input type="number" class="form-control" name="id" value="{{Request::query('id')}}" placeholder="ID"/>
                     </div>
                     <div class="form-group col-xxl-2 col-lg-3 col-md-3 col-sm-4">
-                        <input type="text" class="form-control" name="email" value="{{Request::query('email')}}" placeholder="用户账号"/>
+                        <input type="text" class="form-control" name="username" value="{{Request::query('username')}}" placeholder="用户账号"/>
                     </div>
                     <div class="form-group col-xxl-2 col-lg-3 col-md-3 col-sm-4">
                         <input type="text" class="form-control" name="wechat" value="{{Request::query('wechat')}}" placeholder="微信"/>
@@ -102,7 +102,7 @@
                     @foreach ($userList as $user)
                         <tr class="{{$user->isTrafficWarning() ? ' table-danger' : ''}}">
                             <td> {{$user->id}} </td>
-                            <td> {{$user->email}} </td>
+                            <td> {{$user->username}} </td>
                             <td> {{$user->credit}} </td>
                             <td>
                                 {!!$user->port? : '<span class="badge badge-lg badge-danger"> 未分配 </span>'!!}
@@ -158,7 +158,7 @@
                                                 </a>
                                             @endcan
                                             @can('admin.user.destroy')
-                                                <a class="dropdown-item" href="javascript:delUser('{{route('admin.user.destroy', $user->id)}}','{{$user->email}}')" role="menuitem">
+                                                <a class="dropdown-item" href="javascript:delUser('{{route('admin.user.destroy', $user->id)}}','{{$user->username}}')" role="menuitem">
                                                     <i class="icon wb-trash" aria-hidden="true"></i> 删除
                                                 </a>
                                             @endcan
@@ -178,7 +178,7 @@
                                                 </a>
                                             @endcan
                                             @can('admin.user.reset')
-                                                <a class="dropdown-item" href="javascript:resetTraffic('{{$user->id}}','{{$user->email}}')" role="menuitem">
+                                                <a class="dropdown-item" href="javascript:resetTraffic('{{$user->id}}','{{$user->username}}')" role="menuitem">
                                                     <i class="icon wb-reload" aria-hidden="true"></i> 重置流量
                                                 </a>
                                             @endcan
@@ -252,10 +252,10 @@
 
         @can('admin.user.destroy')
         // 删除账号
-        function delUser(url, email) {
+        function delUser(url, username) {
             swal.fire({
                 title: '{{trans('common.warning')}}',
-                text: '确定删除用户 【' + email + '】 ?',
+                text: '确定删除用户 【' + username + '】 ?',
                 icon: 'warning',
                 showCancelButton: true,
                 cancelButtonText: '{{trans('common.close')}}',
@@ -282,10 +282,10 @@
 
         @can('admin.user.reset')
         // 重置流量
-        function resetTraffic(id, email) {
+        function resetTraffic(id, username) {
             swal.fire({
                 title: '{{trans('common.warning')}}',
-                text: '确定重置 【' + email + '】 流量吗?',
+                text: '确定重置 【' + username + '】 流量吗?',
                 icon: 'warning',
                 showCancelButton: true,
                 cancelButtonText: '{{trans('common.close')}}',

+ 7 - 7
resources/views/admin/user/info.blade.php

@@ -22,15 +22,15 @@
                         <div class="col-lg-6">
                             <h4 class="example-title">账号信息</h4>
                             <div class="form-group row">
-                                <label class="col-md-2 col-sm-3 col-form-label" for="username">昵称</label>
+                                <label class="col-md-2 col-sm-3 col-form-label" for="nickname">昵称</label>
                                 <div class="col-xl-6 col-sm-8">
-                                    <input type="text" class="form-control" name="username" id="username" required/>
+                                    <input type="text" class="form-control" name="nickname" id="nickname" required/>
                                 </div>
                             </div>
                             <div class="form-group row">
-                                <label class="col-md-2 col-sm-3 col-form-label" for="email">邮箱</label>
+                                <label class="col-md-2 col-sm-3 col-form-label" for="username">账号</label>
                                 <div class="col-xl-6 col-sm-8">
-                                    <input type="email" class="form-control" name="email" id="email" required/>
+                                    <input type="text" class="form-control" name="username" id="username" required/>
                                 </div>
                             </div>
                             <div class="form-group row">
@@ -283,7 +283,7 @@
                                 <div class="form-group row">
                                     <label class="col-md-2 col-sm-3 col-form-label" for="inviter">邀请人</label>
                                     <div class="col-xl-6 col-sm-8">
-                                        <p class="form-control"> {{$user->inviter->email ?? '无邀请人'}} </p>
+                                        <p class="form-control"> {{$user->inviter->username ?? '无邀请人'}} </p>
                                     </div>
                                 </div>
                                 <div class="form-group row">
@@ -341,8 +341,8 @@
     <script>
         $(document).ready(function() {
             @isset($user)
+            $('#nickname').val('{{$user->nickname}}');
             $('#username').val('{{$user->username}}');
-            $('#email').val('{{$user->email}}');
             $('#level').selectpicker('val', '{{$user->level}}');
             $('#group').selectpicker('val', '{{$user->user_group_id}}');
             $('#invite_num').val('{{$user->invite_num}}');
@@ -451,8 +451,8 @@
                 dataType: 'json',
                 data: {
                     _token: '{{csrf_token()}}',
+                    nickname: $('#nickname').val(),
                     username: $('#username').val(),
-                    email: $('#email').val(),
                     password: $('#password').val(),
                     port: $('#port').val(),
                     passwd: $('#passwd').val(),

+ 54 - 0
resources/views/admin/user/oauth.blade.php

@@ -0,0 +1,54 @@
+@extends('admin.layouts')
+@section('css')
+    <link href="/assets/global/vendor/bootstrap-table/bootstrap-table.min.css" rel="stylesheet">
+@endsection
+@section('content')
+    <div class="page-content container-fluid">
+        <div class="panel">
+            <div class="panel-heading">
+                <h2 class="panel-title">用户OAuth授权</h2>
+            </div>
+            <div class="panel-body">
+                <table class="text-md-center" data-toggle="table" data-mobile-responsive="true">
+                    <thead class="thead-default">
+                    <tr>
+                        <th> #</th>
+                        <th> 用户</th>
+                        <th> 渠道</th>
+                        <th> 唯一标识</th>
+                        <th> {{trans('common.action')}}</th>
+                    </tr>
+                    </thead>
+                    <tbody>
+                    @foreach ($list as $item)
+                        <tr>
+                            <td> {{$item->id}} </td>
+                            <td> {{$item->user->username ?? $item->user->id}} </td>
+                            <td> {{$item->type}} </td>
+                            <td> {{$item->identifier}} </td>
+                            <td>
+                            </td>
+                        </tr>
+                    @endforeach
+                    </tbody>
+                </table>
+            </div>
+            <div class="panel-footer">
+                <div class="row">
+                    <div class="col-sm-4">
+                        共 <code>{{$list->total()}}</code> 个授权
+                    </div>
+                    <div class="col-sm-8">
+                        <nav class="Page navigation float-right">
+                            {{$list->links()}}
+                        </nav>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+@endsection
+@section('javascript')
+    <script src="/assets/global/vendor/bootstrap-table/bootstrap-table.min.js"></script>
+    <script src="/assets/global/vendor/bootstrap-table/extensions/mobile/bootstrap-table-mobile.min.js"></script>
+@endsection

+ 1 - 1
resources/views/auth/activeUser.blade.php

@@ -14,7 +14,7 @@
                 <span class="form-title">{{trans('common.active_item', ['attribute' => trans('common.account')])}}</span>
             </div>
             <div class="form-group form-material floating" data-plugin="formMaterial">
-                <input type="email" class="form-control" name="email" value="{{Request::query('email')}}" required/>
+                <input type="text" class="form-control" name="username" value="{{Request::query('username')}}" required/>
                 <label class="floating-label" for="email">{{trans('validation.attributes.email')}}</label>
             </div>
         @else

+ 9 - 2
resources/views/auth/login.blade.php

@@ -10,8 +10,8 @@
             <x-alert type="success" :message="Session::get('successMsg')"/>
         @endif
         <div class="form-group form-material floating" data-plugin="formMaterial">
-            <input type="email" class="form-control" name="email" value="{{Request::old('email')}}" required/>
-            <label class="floating-label" for="email">{{trans('validation.attributes.email')}}</label>
+            <input type="text" class="form-control" name="username" value="{{Request::old('username')}}" required/>
+            <label class="floating-label" for="username">{{trans('validation.attributes.email')}}</label>
         </div>
         <div class="form-group form-material floating" data-plugin="formMaterial">
             <input type="password" class="form-control" name="password" value="{{Request::old('password')}}" autocomplete required/>
@@ -28,6 +28,13 @@
             </a>
         </div>
         <button type="submit" class="btn btn-lg btn-block mt-40 bg-indigo-500 text-white">{{trans('auth.login')}}</button>
+        @if(sysConfig('oauth_path'))
+                @foreach (sysConfig('oauth_path') as $item)
+                <a href="{{route('oauth.route', ['type' => $item, 'action' => 'login'])}}" class="btn btn-lg btn-block mt-40 bg-blue-500 text-white">{{trans('auth.sign_in_with', ['app'
+         => config('common.oauth')[$item]])}}</a>
+                @endforeach
+        @endif
+
     </form>
     @if(sysConfig('is_register'))
         <p>

+ 16 - 5
resources/views/auth/register.blade.php

@@ -2,6 +2,7 @@
 @section('title', trans('auth.register.attribute'))
 @section('css')
     <link href="/assets/global/vendor/bootstrap-select/bootstrap-select.min.css" rel="stylesheet">
+    <link href="/assets/global/fonts/brand-icons/brand-icons.min.css" rel="stylesheet">
 @endsection
 @section('content')
     <form action="{{route('register')}}" method="post" id="register-form">
@@ -13,8 +14,8 @@
             <input type="hidden" name="register_token" value="{{Session::get('register_token')}}"/>
             <input type="hidden" name="aff" value="{{Request::query('aff')}}"/>
             <div class="form-group form-material floating" data-plugin="formMaterial">
-                <input type="text" class="form-control" name="username" id="username" 
-		value="{{Request::old('username') ? : Request::query('username')}}" autocomplete="off" required/>
+                <input type="text" class="form-control" name="nickname" id="nickname"
+                       value="{{Request::old('nickname') ? : Request::query('nickname')}}" autocomplete="off" required/>
                 <label class="floating-label" for="username">{{trans('validation.attributes.username')}}</label>
             </div>
             <div class="form-group form-material floating" data-plugin="formMaterial">
@@ -30,11 +31,11 @@
                                 <option value="{{$email->words}}">{{$email->words}}</option>
                             @endforeach
                         </select>
-                        <input type="text" name="email" id="email" hidden/>
+                        <input type="text" name="username" id="username" hidden/>
                     </div>
                 @else
-                    <input type="email" class="form-control" name="email" id="email" value="{{Request::old('email')}}" required/>
-                    <label class="floating-label" for="email">{{trans('validation.attributes.email')}}</label>
+                    <input type="text" class="form-control" name="username" id="username" value="{{Request::old('username')}}" required/>
+                    <label class="floating-label" for="username">{{trans('validation.attributes.email')}}</label>
                 @endif
             </div>
             @if(sysConfig('is_activate_account') == 1)
@@ -97,6 +98,16 @@
             <button type="submit" class="btn btn-primary btn-lg float-right">{{trans('auth.register.attribute')}}</button>
         @endif
     </form>
+    @if(sysConfig('is_register') && sysConfig('oauth_path'))
+        <div class="row" style="display: inline-block;">
+            <h6>快速注册</h6>
+            @foreach (sysConfig('oauth_path') as $item)
+                <a class="btn btn-info" href="{{route('oauth.route', ['type' => $item, 'action' => 'register'])}}">
+                    {{config('common.oauth')[$item]}}
+                </a>
+            @endforeach
+        </div>
+    @endif
 @endsection
 @section('modal')
     <div class="modal fade modal-info text-left" id="tos" aria-hidden="true" aria-labelledby="tos" role="dialog"

+ 1 - 1
resources/views/auth/resetPassword.blade.php

@@ -14,7 +14,7 @@
                 {{trans('auth.password.reset.attribute')}}
             </div>
             <div class="form-group form-material floating" data-plugin="formMaterial">
-                <input type="email" class="form-control" name="email" value="{{Request::old('email')}}" required="required" autofocus="autofocus"/>
+                <input type="text" class="form-control" name="username" value="{{Request::old('username')}}" required="required" autofocus="autofocus"/>
                 <label class="floating-label">{{trans('validation.attributes.email')}}</label>
             </div>
         @else

+ 2 - 2
resources/views/components/avatar.blade.php

@@ -1,7 +1,7 @@
 @if($user->qq)
     <img src="https://q1.qlogo.cn/g?b=qq&nk={{$user->qq}}&s=640" alt="{{trans('common.avatar')}}">
-@elseif(stripos(strtolower($user->email),'@qq.com') !== false)
-    <img src="https://q1.qlogo.cn/g?b=qq&nk={{$user->email}}&s=640" alt="{{trans('common.avatar')}}">
+@elseif(stripos(strtolower($user->username),'@qq.com') !== false)
+    <img src="https://q1.qlogo.cn/g?b=qq&nk={{$user->username}}&s=640" alt="{{trans('common.avatar')}}">
 @else
     <img src="/assets/images/avatar.svg" alt="{{trans('common.avatar')}}">
 @endif

+ 1 - 1
resources/views/components/chat-unit.blade.php

@@ -5,7 +5,7 @@
     chat-left
 @endif">
     <div class="chat-avatar">
-        <p class="avatar" data-toggle="tooltip" href="#" data-placement="right" title="" data-original-title="{{($ticket->admin ?? $ticket->user)->email}}">
+        <p class="avatar" data-toggle="tooltip" href="#" data-placement="right" title="" data-original-title="{{($ticket->admin ?? $ticket->user)->username}}">
             <x-avatar :user="$ticket->admin ?? $ticket->user"/>
         </p>
     </div>

+ 22 - 5
resources/views/user/profile.blade.php

@@ -1,15 +1,18 @@
 @extends('user.layouts')
+@section('css')
+    <link href="/assets/global/fonts/brand-icons/brand-icons.min.css" rel="stylesheet">
+@endsection
 @section('content')
     <div class="page-content container">
         <div class="row">
             <div class="col-lg-5">
-                <div class="card">
-                    <div class="card-header white bg-cyan-600 p-30 clearfix">
+                <div class="card mb-0">
+                    <div class="card-header white bg-cyan-400 p-30 clearfix">
                         <span class="avatar avatar-100 float-left mr-20">
                             <x-avatar :user="Auth::getUser()"/>
                         </span>
                         <div class="float-left">
-                            <div class="font-size-20 mb-15">{{Auth::getUser()->username}}</div>
+                            <div class="font-size-20 mb-15">{{Auth::getUser()->nickname}}</div>
                             <p class="mb-5 text-nowrap"><i class="icon bd-webchat mr-10" aria-hidden="true"></i>
                                 <span class="text-break">{{trans('common.payment.wechat')}}:
                                     @if(Auth::getUser()->wechat) {{Auth::getUser()->wechat}} @else {{trans('common.none')}} @endif
@@ -23,6 +26,20 @@
                         </div>
                     </div>
                 </div>
+                @if(sysConfig('oauth_path'))
+                    <div class="card">
+                        <div class="card-header white bg-indigo-400 p-30 clearfix">
+                            <div class="float-left">
+                                <div class="font-size-20 mb-15"><i class="icon wb-user-circle"></i> 绑定社交账号</div>
+                                @foreach (sysConfig('oauth_path') as $item)
+                                    <a class="btn btn-info" href="{{route('oauth.route', ['type' => $item, 'action' => 'binding'])}}">
+                                        {{config('common.oauth')[$item]}}
+                                    </a>
+                                @endforeach
+                            </div>
+                        </div>
+                    </div>
+                @endif
             </div>
             <div class="col-lg-7">
                 <div class="panel">
@@ -65,8 +82,8 @@
                                 <form action="{{route('profile')}}" method="post" enctype="multipart/form-data" class="form-horizontal">
                                     @csrf
                                     <div class="form-group row">
-                                        <label for="username" class="col-md-2 col-form-label">{{trans('validation.attributes.username')}}</label>
-                                        <input type="text" class="form-control col-md-5 round" name="username" id="username" value="{{Auth::getUser()->username}}"/>
+                                        <label for="nickname" class="col-md-2 col-form-label">{{trans('validation.attributes.username')}}</label>
+                                        <input type="text" class="form-control col-md-5 round" name="nickname" id="nickname" value="{{Auth::getUser()->nickname}}"/>
                                     </div>
                                     <div class="form-group row">
                                         <label for="wechat" class="col-md-2 col-form-label">{{trans('common.payment.wechat')}}</label>

+ 2 - 2
resources/views/user/referral.blade.php

@@ -44,7 +44,7 @@
                             @foreach($referralUserList as $user)
                                 <tr>
                                     <td> {{$loop->iteration}} </td>
-                                    <td> {{str_replace(mb_substr($user->email, 3, 4), "****", $user->email)}}  </td>
+                                    <td> {{str_replace(mb_substr($user->username, 3, 4), "****", $user->username)}}  </td>
                                     <td> {{$user->created_at}} </td>
                                 </tr>
                             @endforeach
@@ -87,7 +87,7 @@
                             @foreach($referralLogList as $referralLog)
                                 <tr>
                                     <td> {{$loop->iteration}} </td>
-                                    <td> {{empty($referralLog->invitee) ? '【'.trans('common.deleted_item', ['attribute' => trans('common.account')]).'】' : str_replace(mb_substr($referralLog->invitee->email, 3, 4), "****", $referralLog->invitee->email)}} </td>
+                                    <td> {{empty($referralLog->invitee) ? '【'.trans('common.deleted_item', ['attribute' => trans('common.account')]).'】' : str_replace(mb_substr($referralLog->invitee->username, 3, 4), "****", $referralLog->invitee->username)}} </td>
                                     <td> ¥{{$referralLog->amount}} </td>
                                     <td> ¥{{$referralLog->commission}} </td>
                                     <td> {{$referralLog->created_at}} </td>

+ 1 - 0
routes/admin.php

@@ -11,6 +11,7 @@ Route::prefix('admin')->name('admin.')->group(function () {
     Route::namespace('Admin')->group(function () {
         Route::resource('user', 'UserController')->except('show');
         Route::name('user.')->group(function () {
+            Route::get('oauth', 'UserController@oauth')->name('oauth'); // 第三方登录信息
             Route::post('batchAdd', 'UserController@batchAddUsers')->name('batch'); // 批量生成账号
             Route::resource('group', 'UserGroupController')->except('show'); // 用户分组管理
             Route::get('monitor/{user}', 'LogsController@userTrafficMonitor')->name('monitor'); // 用户流量监控

+ 8 - 0
routes/web.php

@@ -15,6 +15,14 @@ Route::post('api/telegram/webhook', 'TelegramController@webhook'); // Telegram f
 Route::middleware(['isForbidden', 'affiliate', 'isMaintenance'])->group(function () {
     Route::get('lang/{locale}', 'AuthController@switchLang')->name('lang'); // 语言切换
     Route::get('login', 'AuthController@showLoginForm')->middleware('isSecurity')->name('login'); // 登录页面
+
+    Route::namespace('OAuth')->prefix('oauth/')->name('oauth.')->group(function () { // 用户第三方登录默认登录/转跳方式
+        Route::get('{type}/redirect', 'BaseController@redirect')->name('redirect');
+        Route::get('{type}/bind', 'BaseController@bind')->name('bind');
+        Route::get('{type}/register', 'BaseController@register')->name('register');
+        Route::get('{type}/{action}', 'BaseController@route')->name('route');
+    });
+
     Route::post('login', 'AuthController@login')->middleware('isSecurity'); // 登录
     Route::get('logout', 'AuthController@logout')->name('logout'); // 退出
     Route::get('register', 'AuthController@showRegistrationForm')->name('register'); // 注册

Some files were not shown because too many files changed in this diff