From af33e5cba7fbd9c8f9dd5dd72eaa0300f1b68756 Mon Sep 17 00:00:00 2001 From: xiaomlove Date: Thu, 1 May 2025 14:18:30 +0700 Subject: [PATCH] finish oauth provider + docker service wait for MySQL --- .docker/openresty/entrypoint.sh | 12 +- .docker/php/entrypoint.sh | 12 ++ app/Exceptions/Handler.php | 15 +- .../Resources/Oauth/ProviderResource.php | 11 + app/Http/Controllers/OauthController.php | 102 +++++++++- app/Http/Controllers/ToolController.php | 5 + app/Http/Middleware/Locale.php | 2 +- app/Http/Resources/UserResource.php | 3 + app/Models/OauthProvider.php | 1 + app/Models/SocialAccount.php | 22 ++ ...23_042250_create_oauth_providers_table.php | 2 + ...30_215644_create_social_accounts_table.php | 34 ++++ include/constants.php | 2 +- include/functions.php | 3 +- nexus/Install/Update.php | 2 + public/fastdelete.php | 8 +- public/messages.php | 1 - resources/lang/en/claim.php | 12 +- resources/lang/en/label.php | 2 +- resources/lang/en/oauth.php | 8 + resources/lang/zh_CN/claim.php | 12 +- resources/lang/zh_CN/oauth.php | 8 + resources/lang/zh_TW/claim.php | 12 +- resources/lang/zh_TW/oauth.php | 8 + resources/views/error.blade.php | 190 ++++++++++++++++++ routes/web.php | 2 + 26 files changed, 450 insertions(+), 41 deletions(-) create mode 100644 app/Models/SocialAccount.php create mode 100644 database/migrations/2025_04_30_215644_create_social_accounts_table.php create mode 100644 resources/views/error.blade.php diff --git a/.docker/openresty/entrypoint.sh b/.docker/openresty/entrypoint.sh index 7fb4bd1f..1a0b98a2 100644 --- a/.docker/openresty/entrypoint.sh +++ b/.docker/openresty/entrypoint.sh @@ -53,7 +53,17 @@ fi echo_info "USE_HTTPS: $USE_HTTPS" # 组合子域名变量 -export PHPMYADMIN_SERVER_NAME="phpmyadmin.${NP_DOMAIN}" +dot_count_tmp="${NP_DOMAIN//[^.]/}" +dot_count="${#dot_count_tmp}" +PHPMYADMIN="phpmyadmin" +if [ "$dot_count" -eq 1 ]; then + PHPMYADMIN="${PHPMYADMIN}." +else + PHPMYADMIN="${PHPMYADMIN}-" +fi +export PHPMYADMIN_SERVER_NAME="${PHPMYADMIN}${NP_DOMAIN}" + +echo_info "PHPMYADMIN_SERVER_NAME: ${PHPMYADMIN_SERVER_NAME}" # 生成配置 APP_CONF="/etc/nginx/conf.d/app.conf" diff --git a/.docker/php/entrypoint.sh b/.docker/php/entrypoint.sh index 6688a080..664b66b5 100644 --- a/.docker/php/entrypoint.sh +++ b/.docker/php/entrypoint.sh @@ -36,6 +36,18 @@ VENDOR_DIR="${ROOT_PATH}/vendor" chown -R www-data:www-data $ROOT_PATH +until nc -z mysql 3306; do + echo_info "Waiting for MySQL to be ready..." + sleep 2 +done +echo_success "MySQL is ready." + +until nc -z redis 6379; do + echo_info "Waiting for Redis to be ready..." + sleep 2 +done +echo_success "Redis is ready." + if [ "$SERVICE_NAME" = "php" ]; then if [ ! -f "$ENV_FILE" ]; then echo_info ".env file: $ENV_FILE not exists, copy $SOURCE_DIR to $TARGET_DIR ..." diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 34d5ac08..40455824 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -45,20 +45,23 @@ class Handler extends ExceptionHandler if (app()->runningInConsole()) { return; } - $this->reportable(function (InsufficientPermissionException $e) { - if (request()->expectsJson()) { - return response()->json(fail($e->getMessage(), request()->all()), 403); + $request = request(); + $this->reportable(function (InsufficientPermissionException $e) use ($request) { + if ($request->expectsJson()) { + return response()->json(fail($e->getMessage(), $request->all()), 403); } else { return abort(403); } }); - $this->renderable(function (PassportAuthenticationException $e) { - $request = request(); + $this->renderable(function (PassportAuthenticationException $e) use ($request) { return response()->redirectTo(sprintf("%s/login.php?returnto=%s", $request->getSchemeAndHttpHost(), urlencode($request->fullUrl()))); }); //Other Only handle in json request - if (!request()->expectsJson()) { + if (!$request->expectsJson()) { + $this->renderable(function (NexusException $e) use ($request) { + return redirect(url('/error?error=' . urlencode($e->getMessage()))); + }); return; } diff --git a/app/Filament/Resources/Oauth/ProviderResource.php b/app/Filament/Resources/Oauth/ProviderResource.php index 5ccba4e0..0e49aa99 100644 --- a/app/Filament/Resources/Oauth/ProviderResource.php +++ b/app/Filament/Resources/Oauth/ProviderResource.php @@ -5,6 +5,7 @@ namespace App\Filament\Resources\Oauth; use App\Filament\Resources\Oauth\ProviderResource\Pages; use App\Filament\Resources\Oauth\ProviderResource\RelationManagers; use App\Models\OauthProvider; +use App\Models\User; use Filament\Forms; use Filament\Forms\Form; use Filament\Resources\Resource; @@ -71,6 +72,14 @@ class ProviderResource extends Resource Forms\Components\TextInput::make('email_claim') ->label(__('oauth.email_claim')) , + Forms\Components\TextInput::make('level_claim') + ->label(__('oauth.level_claim')) + , + Forms\Components\TextInput::make('level_limit') + ->numeric() + ->label(__('oauth.level_limit')) + ->helperText(__('oauth.level_limit_help')) + , Forms\Components\TextInput::make('priority') ->label(__('label.priority')) ->default(0) @@ -88,6 +97,7 @@ class ProviderResource extends Resource return $table ->columns([ Tables\Columns\TextColumn::make('id'), + Tables\Columns\TextColumn::make('name')->label(__('label.name')), Tables\Columns\TextColumn::make('client_id')->label(__('oauth.client_id')), Tables\Columns\TextColumn::make('client_secret')->label(__('oauth.secret')), Tables\Columns\TextColumn::make('authorization_endpoint_url')->label(__('oauth.authorization_endpoint_url')), @@ -97,6 +107,7 @@ class ProviderResource extends Resource , Tables\Columns\TextColumn::make('priority')->label(__('label.priority')), Tables\Columns\TextColumn::make('updated_at')->label(__('label.updated_at')), + Tables\Columns\TextColumn::make('level_limit')->label(__('oauth.level_limit')), Tables\Columns\IconColumn::make('enabled')->boolean()->label(__('label.enabled')), ]) ->defaultSort('priority', 'desc') diff --git a/app/Http/Controllers/OauthController.php b/app/Http/Controllers/OauthController.php index 961ada82..dd418e8f 100644 --- a/app/Http/Controllers/OauthController.php +++ b/app/Http/Controllers/OauthController.php @@ -1,9 +1,13 @@ $provider->client_id, - 'redirect_uri' => $provider->redirect, + 'redirect_uri' => $this->getRedirectUri($provider), 'response_type' => 'code', 'scope' => '', 'state' => $state, @@ -42,6 +46,11 @@ class OauthController extends Controller } + private function getRedirectUri(OauthProvider $provider): string + { + return sprintf("%s/oauth/callback/%s", getSchemeAndHttpHost(), $provider->uuid); + } + /** * authorization server redirect to this url with auth code after user authorized * and then use auth code to request to authorization server token endpoint url to get access token @@ -63,23 +72,98 @@ class OauthController extends Controller $provider = OauthProvider::query()->where('uuid', $uuid)->firstOrFail(); - $response = Http::asForm()->post($provider->token_endpoint_url, [ + $params = [ 'grant_type' => 'authorization_code', 'client_id' => $provider->client_id, 'client_secret' => $provider->client_secret, -// 'redirect_uri' => url("oauth/login"), + 'redirect_uri' => $this->getRedirectUri($provider), 'code' => $request->code, - ]); + ]; + $response = Http::asForm()->post($provider->token_endpoint_url, $params); $tokenInfo = $response->json(); - do_log("tokenInfo: " . $response->body()); + if (empty($tokenInfo['access_token'])) { + do_log("Get tokenInfo with: " . json_encode($params) . " error: " . $response->body(), 'error'); + throw new NexusException(nexus_trans('oauth.get_access_token_error', ['error' => $tokenInfo['error'] ?? ''])); + } //use token get user-info $response = Http::withToken($tokenInfo['access_token'])->get($provider->user_info_endpoint_url); $userInfo = $response->json(); do_log("userInfo: " . $response->body()); - $userId = data_get($userInfo, $provider->id_claim); - $username = data_get($userInfo, $provider->username_claim); - $email = data_get($userInfo, $provider->email_claim); - dd($userInfo, $userId, $username, $email); + $providerUserId = data_get($userInfo, $provider->id_claim); + if (empty($providerUserId)) { + throw new NexusException(nexus_trans('oauth.get_provider_user_id_error', ['id_claim' => $provider->id_claim])); + } + $providerUsername = data_get($userInfo, $provider->username_claim); + $providerEmail = data_get($userInfo, $provider->email_claim); + $providerLevel = data_get($userInfo, $provider->level_claim); + $homeUrl = getSchemeAndHttpHost() . "/index.php"; + $socialAccount = SocialAccount::query() + ->where('provider_id', $provider->id) + ->where('provider_user_id', $providerUserId) + ->first(); + if ($socialAccount) { + //already bind, login directly + $authUser = $socialAccount->user; + logincookie($authUser->id, $authUser->auth_key); + return redirect($homeUrl); + } + $minLevel = $provider->level_limit; + if ($minLevel) { + if (!$providerLevel) { + throw new NexusException(nexus_trans('oauth.get_provider_level_error', ['level_claim' => $provider->level_claim])); + } + if ($providerLevel < $minLevel) { + throw new NexusException(nexus_trans("oauth.provider_level_not_allowed", ['level_limit' => $provider->level_limit])); + } + } + if ($providerEmail) { + $sameEmailUser = User::query()->where('email', $providerEmail)->first(); + if ($sameEmailUser) { + //login to bind is better, not implement this time + throw new NexusException(nexus_trans('oauth.provider_email_already_exists', ['email' => $providerEmail])); + } + } + $newUser = $this->createUser($providerUsername, $providerEmail); + $socialAccountData = [ + 'user_id' => $newUser->id, + 'provider_id' => $provider->id, + 'provider_user_id' => $providerUserId, + 'provider_username' => $providerUsername, + 'provider_email' => $providerEmail, + ]; + SocialAccount::query()->create($socialAccountData); + do_log(sprintf("newUser: %s, socialAccount: %s", json_encode($newUser), json_encode($socialAccountData))); + logincookie($newUser->id, $newUser->auth_key); + return redirect($homeUrl); + } + + private function createUser($username, $email): User + { + if ($username) { + if (User::query()->where('username', $username)->exists()) { + //already in use + $username .= Str::random(2); + } + } else { + $username = $email; + } + $password = Str::random(10); + $userData = [ + 'email' => $email, + 'password' => $password, + 'password_confirmation' => $password, + ]; + $userRep = new UserRepository(); + for ($i = 0; $i < 3; $i++) { + $userData['username'] = $username; + try { + return $userRep->store($userData); + } catch (\Throwable $e) { + do_log($e->getMessage(), "error"); + } + $username = Str::random(2) . $username; + } + throw new NexusException("Unable to create user"); } public function debug(Request $request) diff --git a/app/Http/Controllers/ToolController.php b/app/Http/Controllers/ToolController.php index ffba7767..51a232e3 100644 --- a/app/Http/Controllers/ToolController.php +++ b/app/Http/Controllers/ToolController.php @@ -37,4 +37,9 @@ class ToolController extends Controller return $this->success($resource); } + public function error(Request $request) + { + return view('error', ['error' => $request->query('error')]); + } + } diff --git a/app/Http/Middleware/Locale.php b/app/Http/Middleware/Locale.php index 43c45c66..bb6e0af7 100644 --- a/app/Http/Middleware/Locale.php +++ b/app/Http/Middleware/Locale.php @@ -41,7 +41,7 @@ class Locale /** @var Response $response */ $response = $next($request); if ($response instanceof Response || $response instanceof JsonResponse) { - $response->header('X-Request-Id', nexus()->getRequestId())->header('X-NexusPHP-Version', VERSION_NUMBER); + $response->header('X-Request-Id', nexus()->getRequestId())->header('X-Nexusphp-Version', VERSION_NUMBER); } return $response; } diff --git a/app/Http/Resources/UserResource.php b/app/Http/Resources/UserResource.php index 0b6d50e8..63fce469 100644 --- a/app/Http/Resources/UserResource.php +++ b/app/Http/Resources/UserResource.php @@ -27,6 +27,8 @@ class UserResource extends JsonResource 'added_human' => gettime($this->added), 'last_access' => format_datetime($this->last_access), 'last_access_human' => gettime($this->last_access), + 'last_login' => format_datetime($this->last_login), + 'last_login_human' => gettime($this->last_login), 'class' => $this->class, 'class_text' => $this->class_text, 'avatar' => $this->avatar, @@ -44,6 +46,7 @@ class UserResource extends JsonResource 'seedtime_text' => mkprettytime($this->seedtime), 'leechtime' => $this->leechtime, 'leechtime_text' => mkprettytime($this->leechtime), + 'share_ratio' => get_ratio($this->id), 'inviter' => new UserResource($this->whenLoaded('inviter')), 'valid_medals' => MedalResource::collection($this->whenLoaded('valid_medals')), ]; diff --git a/app/Models/OauthProvider.php b/app/Models/OauthProvider.php index eeec084b..0efb7e67 100644 --- a/app/Models/OauthProvider.php +++ b/app/Models/OauthProvider.php @@ -10,6 +10,7 @@ class OauthProvider extends NexusModel protected $fillable = [ 'uuid', 'name', 'client_id', 'client_secret', 'authorization_endpoint_url', 'token_endpoint_url', 'user_info_endpoint_url', 'id_claim', 'username_claim', 'email_claim', 'enabled', 'priority', + 'level_claim', 'level_limit', ]; public $timestamps = true; diff --git a/app/Models/SocialAccount.php b/app/Models/SocialAccount.php new file mode 100644 index 00000000..4d54b5fb --- /dev/null +++ b/app/Models/SocialAccount.php @@ -0,0 +1,22 @@ +belongsTo(User::class, 'user_id'); + } + +} diff --git a/database/migrations/2025_04_23_042250_create_oauth_providers_table.php b/database/migrations/2025_04_23_042250_create_oauth_providers_table.php index 72c7ed0c..f3ebde79 100644 --- a/database/migrations/2025_04_23_042250_create_oauth_providers_table.php +++ b/database/migrations/2025_04_23_042250_create_oauth_providers_table.php @@ -23,6 +23,8 @@ return new class extends Migration $table->string('id_claim'); $table->string('username_claim')->nullable(); $table->string('email_claim')->nullable(); + $table->string('level_claim')->nullable(); + $table->string('level_limit')->nullable(); $table->boolean('enabled'); $table->integer('priority'); $table->timestamps(); diff --git a/database/migrations/2025_04_30_215644_create_social_accounts_table.php b/database/migrations/2025_04_30_215644_create_social_accounts_table.php new file mode 100644 index 00000000..2e9ac8bc --- /dev/null +++ b/database/migrations/2025_04_30_215644_create_social_accounts_table.php @@ -0,0 +1,34 @@ +id(); + $table->bigInteger('user_id'); + $table->bigInteger('provider_id'); + $table->string('provider_user_id'); + $table->string('provider_email'); + $table->string('provider_username'); + $table->timestamps(); + $table->unique(['user_id', 'provider_id']); + $table->unique(['provider_id', 'provider_user_id']); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('social_accounts'); + } +}; diff --git a/include/constants.php b/include/constants.php index a64ded92..40fe7fed 100644 --- a/include/constants.php +++ b/include/constants.php @@ -1,6 +1,6 @@ ".$ratio.""; } elseif ($uped > 0) - $ratio = $lang_functions['text_inf']; + $ratio = nexus_trans("label.infinite"); else $ratio = "---"; } diff --git a/nexus/Install/Update.php b/nexus/Install/Update.php index 0e84dab1..5944a474 100644 --- a/nexus/Install/Update.php +++ b/nexus/Install/Update.php @@ -9,6 +9,7 @@ use App\Models\Exam; use App\Models\ExamUser; use App\Models\HitAndRun; use App\Models\Icon; +use App\Models\Language; use App\Models\SearchBox; use App\Models\Setting; use App\Models\Tag; @@ -342,6 +343,7 @@ class Update extends Install $this->runMigrate("database/migrations/2025_01_08_133552_create_torrent_extra_table.php"); Artisan::call("upgrade:migrate_torrents_table_text_column"); } + Language::updateTransStatus(); } public function runExtraMigrate() diff --git a/public/fastdelete.php b/public/fastdelete.php index 804ee0f1..21fc3a95 100644 --- a/public/fastdelete.php +++ b/public/fastdelete.php @@ -50,7 +50,13 @@ if (\App\Models\User::query()->where("id", $row['owner'])->exists()) { $dt = sqlesc(date("Y-m-d H:i:s")); $subject = nexus_trans("torrent.msg_torrent_deleted", [], get_user_locale($row['owner'])); $msg = nexus_trans("torrent.msg_the_torrent_you_uploaded", [], get_user_locale($row['owner'])); - sql_query("INSERT INTO messages (sender, receiver, subject, added, msg) VALUES(0, $row[owner], $subject, $dt, $msg)") or sqlerr(__FILE__, __LINE__); + \App\Models\Message::add([ + 'sender' => 0, + 'receiver' => $row['owner'], + 'subject' => $subject, + 'msg' => $msg, + 'added' => $dt, + ]); } } header("Location: torrents.php"); diff --git a/public/messages.php b/public/messages.php index 886c67ad..485e1330 100644 --- a/public/messages.php +++ b/public/messages.php @@ -229,7 +229,6 @@ $reply = " [ 'Claim settle result last month(:month):', 'msg_subject' => ':month claim settlement', - 'claim_total' => 'Claim torrent total: :total', - 'claim_reached_counts' => 'Reached torrent counts: :counts', - 'claim_reached_summary' => 'Reached torrent get bonus per hour: :bonus_per_hour, seed time average(hour): :hours, get bonus total: :bonus_total', - 'claim_unreached_remain_counts' => 'Unreached torrent remain counts: :counts', - 'claim_unreached_remove_counts' => 'Unreached torrent remove counts: :counts', - 'claim_unreached_summary' => 'Deduct bonus every unreached torrent::deduct_per_torrent, total deduct: :deduct_total', + 'claim_total' => 'Claim torrent total: [b]:total[/b]', + 'claim_reached_counts' => 'Reached torrent counts: [b]:counts[/b]', + 'claim_reached_summary' => 'Reached torrent get bonus per hour: [b]:bonus_per_hour[/b], seed time average(hour): [b]:hours[/b], get bonus total: [b]:bonus_total[/b]', + 'claim_unreached_remain_counts' => 'Unreached torrent remain counts: [b]:counts[/b]', + 'claim_unreached_remove_counts' => 'Unreached torrent remove counts: [b]:counts[/b]', + 'claim_unreached_summary' => 'Deduct bonus every unreached torrent:[b]:deduct_per_torrent[/b], total deduct: [b]:deduct_total[/b]', 'confirm_give_up' => 'Are you sure you want to give up claiming this torrent?', 'add_claim' => 'Claim', diff --git a/resources/lang/en/label.php b/resources/lang/en/label.php index 8e8e4321..aeeb9846 100644 --- a/resources/lang/en/label.php +++ b/resources/lang/en/label.php @@ -34,7 +34,7 @@ return [ 'cancel' => 'Cancel', 'reset' => 'Reset', 'anonymous' => 'Anonymous', - 'infinite' => 'Infinite', + 'infinite' => 'Inf.', 'save' => 'Save', 'country' => 'Country', 'city' => 'City', diff --git a/resources/lang/en/oauth.php b/resources/lang/en/oauth.php index 47c60cd9..42824ff0 100644 --- a/resources/lang/en/oauth.php +++ b/resources/lang/en/oauth.php @@ -18,4 +18,12 @@ return [ 'id_claim' => 'ID claim', 'username_claim' => 'username claim', 'email_claim' => 'email claim', + 'level_claim' => 'Level field name', + 'level_limit' => 'Level limit', + 'level_limit_help' => 'Allow only users not below this level to log in', + 'get_access_token_error' => 'Getting access token error: :error', + 'get _provider_user_id_error' => 'Unable to get user ID via field :id_claim', + 'get_provider_level_error' => 'Unable to get user level via field :level_claim', + 'provider_level_not_ allowed' => 'Only users with level :level_limit or above are allowed to log in', + 'provider_email_already_exists' => 'Email: :email is already in use', ]; diff --git a/resources/lang/zh_CN/claim.php b/resources/lang/zh_CN/claim.php index a5f0d3ec..65895ff0 100644 --- a/resources/lang/zh_CN/claim.php +++ b/resources/lang/zh_CN/claim.php @@ -17,12 +17,12 @@ return [ 'msg_title' => '上个月(:month)认领结算如下:', 'msg_subject' => ':month 认领结算', - 'claim_total' => '认领种子数::total', - 'claim_reached_counts' => '达标数::counts', - 'claim_reached_summary' => '达标种子数每小时魔力::bonus_per_hour, 平均做种小时数::hours, 获得魔力::bonus_total', - 'claim_unreached_remain_counts' => '未达标保留数::counts', - 'claim_unreached_remove_counts' => '未达标删除数::counts', - 'claim_unreached_summary' => '未达标每个种子扣除魔力::deduct_per_torrent,总扣除魔力::deduct_total', + 'claim_total' => '认领种子数:[b]:total[/b]', + 'claim_reached_counts' => '达标数:[b]:counts[/b]', + 'claim_reached_summary' => '达标种子数每小时魔力:[b]:bonus_per_hour[/b], 平均做种小时数:[b]:hours[/b], 获得魔力:[b]:bonus_total[/b]', + 'claim_unreached_remain_counts' => '未达标保留数:[b]:counts[/b]', + 'claim_unreached_remove_counts' => '未达标删除数:[b]:counts[/b]', + 'claim_unreached_summary' => '未达标每个种子扣除魔力:[b]:deduct_per_torrent[/b],总扣除魔力:[b]:deduct_total[/b]', 'confirm_give_up' => '确定要放弃认领此种子吗?', 'add_claim' => '认领', diff --git a/resources/lang/zh_CN/oauth.php b/resources/lang/zh_CN/oauth.php index ce632f6e..fa4c6231 100644 --- a/resources/lang/zh_CN/oauth.php +++ b/resources/lang/zh_CN/oauth.php @@ -18,4 +18,12 @@ return [ 'id_claim' => 'ID 字段名', 'username_claim' => '用户名字段名', 'email_claim' => '邮箱字段名', + 'level_claim' => '等级字段名', + 'level_limit' => '等级限制', + 'level_limit_help' => '只允许不低于此等级的用户登录', + 'get_access_token_error' => '获取访问令牌错误::error', + 'get_provider_user_id_error' => '无法通过字段 :id_claim 获取用户 ID', + 'get_provider_level_error' => '无法通过字段 :level_claim 获取用户等级', + 'provider_level_not_allowed' => '仅允许 :level_limit 或以上等级的用户登录', + 'provider_email_already_exists' => '邮箱::email 已经被使用', ]; diff --git a/resources/lang/zh_TW/claim.php b/resources/lang/zh_TW/claim.php index bb2cfd07..1375767f 100644 --- a/resources/lang/zh_TW/claim.php +++ b/resources/lang/zh_TW/claim.php @@ -16,12 +16,12 @@ return [ 'msg_title' => '上個月(:month)認領結算如下:', 'msg_subject' => ':month 認領結算', - 'claim_total' => '認領種子數::total', - 'claim_reached_counts' => '達標數::counts', - 'claim_reached_summary' => '達標種子數每小時魔力::bonus_per_hour, 平均做種小時數::hours, 獲得魔力::bonus_total', - 'claim_unreached_remain_counts' => '未達標保留數::counts', - 'claim_unreached_remove_counts' => '未達標刪除數::counts', - 'claim_unreached_summary' => '未達標每個種子扣除魔力::deduct_per_torrent,總扣除魔力::deduct_total', + 'claim_total' => '認領種子數:[b]:total[/b]', + 'claim_reached_counts' => '達標數:[b]:counts[/b]', + 'claim_reached_summary' => '達標種子數每小時魔力:[b]:bonus_per_hour[/b], 平均做種小時數:[b]:hours[/b], 獲得魔力:[b]:bonus_total[/b]', + 'claim_unreached_remain_counts' => '未達標保留數:[b]:counts[/b]', + 'claim_unreached_remove_counts' => '未達標刪除數:[b]:counts[/b]', + 'claim_unreached_summary' => '未達標每個種子扣除魔力:[b]:deduct_per_torrent[/b],總扣除魔力:[b]:deduct_total[/b]', 'confirm_give_up' => '確定要放棄認領此種子嗎?', 'add_claim' => '認領', diff --git a/resources/lang/zh_TW/oauth.php b/resources/lang/zh_TW/oauth.php index 11cc07d0..048919d7 100644 --- a/resources/lang/zh_TW/oauth.php +++ b/resources/lang/zh_TW/oauth.php @@ -18,4 +18,12 @@ return [ 'id_claim' => 'ID 字段名', 'username_claim' => '用戶名字段名', 'email_claim' => '郵箱字段名', + 'level_claim' => '等級字段名', + 'level_limit' => '等級限製', + 'level_limit_help' => '只允許不低於此等級的用戶登錄', + 'get_access_token_error' => '獲取訪問令牌錯誤::error', + 'get_provider_user_id_error' => '無法通過字段 :id_claim 獲取用戶 ID', + 'get_provider_level_error' => '無法通過字段 :level_claim 獲取用戶等級', + 'provider_level_not_allowed' => '僅允許 :level_limit 或以上等級的用戶登錄', + 'provider_email_already_exists' => '郵箱::email 已經被使用', ]; diff --git a/resources/views/error.blade.php b/resources/views/error.blade.php new file mode 100644 index 00000000..5d829dd0 --- /dev/null +++ b/resources/views/error.blade.php @@ -0,0 +1,190 @@ + + + + + + Error + + + + +
+
+
+ +
+
+ +
+

Error

+

+ {{ $error }} +

+ +
+
+ + diff --git a/routes/web.php b/routes/web.php index 35df3f8a..811323b5 100644 --- a/routes/web.php +++ b/routes/web.php @@ -17,6 +17,8 @@ Route::get('/', function () { return redirect('index.php'); }); +Route::get("/error", [\App\Http\Controllers\ToolController::class, "error"]); + Route::group(['prefix' => 'web', 'middleware' => ['auth.nexus:nexus-web']], function () { Route::get('torrent-approval-page', [\App\Http\Controllers\TorrentController::class, 'approvalPage']); Route::get('torrent-approval-logs', [\App\Http\Controllers\TorrentController::class, 'approvalLogs']);