From 9e8efbbe05cbd6cd30c6736b194203bc4c608301 Mon Sep 17 00:00:00 2001 From: w33b Date: Wed, 7 Jan 2026 12:02:02 +0100 Subject: [PATCH 01/19] Remove jakyeru/larascord --- app/Override/Discord/DiscordController.php | 155 ---------- .../Discord/Services/DiscordService.php | 273 ------------------ composer.json | 5 - composer.lock | 116 +------- config/larascord.php | 247 ---------------- .../views/auth/confirm-password.blade.php | 20 -- 6 files changed, 1 insertion(+), 815 deletions(-) delete mode 100644 app/Override/Discord/DiscordController.php delete mode 100644 app/Override/Discord/Services/DiscordService.php delete mode 100644 config/larascord.php delete mode 100644 resources/views/auth/confirm-password.blade.php diff --git a/app/Override/Discord/DiscordController.php b/app/Override/Discord/DiscordController.php deleted file mode 100644 index a946413..0000000 --- a/app/Override/Discord/DiscordController.php +++ /dev/null @@ -1,155 +0,0 @@ -throwError('missing_guilds_scope'); - } - } - - // Getting the accessToken from the Discord API. - try { - $accessToken = (new DiscordService())->getAccessTokenFromCode($request->get('code')); - } catch (\Exception $e) { - return $this->throwError('invalid_code', $e); - } - - // Get the user from the Discord API. - try { - $user = (new DiscordService())->getCurrentUser($accessToken); - $user->setAccessToken($accessToken); - } catch (\Exception $e) { - return $this->throwError('authorization_failed', $e); - } - - // Making sure the user has an email if the email scope is set. - if (in_array('email', explode('&', config('larascord.scopes')))) { - if (empty($user->email)) { - return $this->throwError('missing_email'); - } - } - - if (auth()->check()) { - // Making sure the current logged-in user's ID is matching the ID retrieved from the Discord API. - if (auth()->id() !== (int)$user->id) { - auth()->logout(); - return $this->throwError('invalid_user'); - } - - // Confirming the session in case the user was redirected from the password.confirm middleware. - $request->session()->put('auth.password_confirmed_at', time()); - } - - // Trying to create or update the user in the database. - // Initiating a database transaction in case something goes wrong. - DB::beginTransaction(); - try { - $user = (new DiscordService())->createOrUpdateUser($user); - $user->accessToken()->updateOrCreate([], $accessToken->toArray()); - } catch (\Exception $e) { - DB::rollBack(); - return $this->throwError('database_error', $e); - } - - // Verifying if the user is soft-deleted. - if (Schema::hasColumn('users', 'deleted_at')) { - if ($user->trashed()) { - DB::rollBack(); - return $this->throwError('user_deleted'); - } - } - - // Patreon check - try { - if (!$accessToken->hasScopes(['guilds', 'guilds.members.read'])) { - DB::rollBack(); - return $this->throwError('missing_guilds_members_read_scope'); - } - $guildMember = (new DiscordService())->getGuildMember($accessToken, config('discord.guild_id')); - $patreonroles = config('discord.patreon_roles'); - $user->is_patreon = false; - if ((new DiscordService())->hasRoleInGuild($guildMember, $patreonroles)) { - $user->is_patreon = true; - } - $user->save(); - } catch (\Exception $e) { - // Clearly not a patreon - $user->is_patreon = false; - $user->save(); - } - - // Committing the database transaction. - DB::commit(); - - // Authenticating the user if the user is not logged in. - if (!auth()->check()) { - auth()->login($user, config('larascord.remember_me', false)); - } - - // Redirecting the user to the intended page or to the home page. - return redirect()->intended(RouteServiceProvider::HOME); - } - - /** - * Handles the throwing of an error. - */ - private function throwError(string $message, \Exception $exception = NULL): RedirectResponse | JsonResponse - { - if (app()->hasDebugModeEnabled()) { - return response()->json([ - 'larascord_message' => config('larascord.error_messages.' . $message), - 'message' => $exception?->getMessage(), - 'code' => $exception?->getCode() - ]); - } else { - if (config('larascord.error_messages.' . $message . '.redirect')) { - Alert::error('Error', config('larascord.error_messages.' . $message . '.message', 'An error occurred while trying to log you in.')); - return redirect(config('larascord.error_messages.' . $message . '.redirect'))->with('error', config('larascord.error_messages.' . $message . '.message', 'An error occurred while trying to log you in.')); - } else { - return redirect('/')->with('error', config('larascord.error_messages.' . $message, 'An error occurred while trying to log you in.')); - } - } - } - - /** - * Handles the deletion of the user. - */ - public function destroy(): RedirectResponse | JsonResponse - { - // Revoking the OAuth2 access token. - try { - (new DiscordService())->revokeAccessToken(auth()->user()->accessToken()->first()->refresh_token); - } catch (\Exception $e) { - return $this->throwError('revoke_token_failed', $e); - } - - // Deleting the user from the database. - auth()->user()->delete(); - - // Showing the success message. - if (config('larascord.success_messages.user_deleted.redirect')) { - return redirect(config('larascord.success_messages.user_deleted.redirect'))->with('success', config('larascord.success_messages.user_deleted.message', 'Your account has been deleted.')); - } else { - return redirect('/')->with('success', config('larascord.success_messages.user_deleted', 'Your account has been deleted.')); - } - } -} diff --git a/app/Override/Discord/Services/DiscordService.php b/app/Override/Discord/Services/DiscordService.php deleted file mode 100644 index 599d969..0000000 --- a/app/Override/Discord/Services/DiscordService.php +++ /dev/null @@ -1,273 +0,0 @@ - NULL, - "client_secret" => NULL, - "grant_type" => "authorization_code", - "code" => NULL, - "redirect_uri" => NULL, - "scope" => null - ]; - - /** - * UserService constructor. - */ - public function __construct() - { - $this->tokenData['client_id'] = config('larascord.client_id'); - $this->tokenData['client_secret'] = config('larascord.client_secret'); - $this->tokenData['grant_type'] = config('larascord.grant_type'); - $this->tokenData['redirect_uri'] = config('larascord.redirect_uri'); - $this->tokenData['scope'] = config('larascord.scopes'); - } - - /** - * Handles the Discord OAuth2 callback and returns the access token. - * - * @throws RequestException - */ - public function getAccessTokenFromCode(string $code): AccessToken - { - $this->tokenData['code'] = $code; - - $response = Http::asForm()->post($this->tokenURL, $this->tokenData); - - $response->throw(); - - return new AccessToken(json_decode($response->body())); - } - - /** - * Get access token from refresh token. - * - * @throws RequestException - */ - public function refreshAccessToken(string $refreshToken): AccessToken - { - $response = Http::asForm()->post($this->tokenURL, [ - 'client_id' => config('larascord.client_id'), - 'client_secret' => config('larascord.client_secret'), - 'grant_type' => 'refresh_token', - 'refresh_token' => $refreshToken, - ]); - - $response->throw(); - - return new AccessToken(json_decode($response->body())); - } - - /** - * Authenticates the user with the access token and returns the user data. - * - * @throws RequestException - */ - public function getCurrentUser(AccessToken $accessToken): \Jakyeru\Larascord\Types\User - { - $response = Http::withToken($accessToken->access_token)->get($this->baseApi . '/users/@me'); - - $response->throw(); - - return new \Jakyeru\Larascord\Types\User(json_decode($response->body())); - } - - /** - * Get the user's guilds. - * - * @throws RequestException - * @throws Exception - */ - public function getCurrentUserGuilds(AccessToken $accessToken, bool $withCounts = false): array - { - if (!$accessToken->hasScope('guilds')) throw new Exception(config('larascord.error_messages.missing_guilds_scope.message')); - - $endpoint = '/users/@me/guilds'; - - if ($withCounts) { - $endpoint .= '?with_counts=true'; - } - - $response = Http::withToken($accessToken->access_token, $accessToken->token_type)->get($this->baseApi . $endpoint); - - $response->throw(); - - return array_map(function ($guild) { - return new \Jakyeru\Larascord\Types\Guild($guild); - }, json_decode($response->body())); - } - - /** - * Get the Guild Member object for a user. - * - * @throws RequestException - * @throws Exception - */ - public function getGuildMember(AccessToken $accessToken, string $guildId): GuildMember - { - if (!$accessToken->hasScopes(['guilds', 'guilds.members.read'])) throw new Exception(config('larascord.error_messages.missing_guilds_members_read_scope.message')); - - $response = Http::withToken($accessToken->access_token, $accessToken->token_type)->get($this->baseApi . '/users/@me/guilds/' . $guildId . '/member'); - - $response->throw(); - - return new GuildMember(json_decode($response->body())); - } - - /** - * Get the User's connections. - * - * @throws RequestException - * @throws Exception - */ - public function getCurrentUserConnections(AccessToken $accessToken): array - { - if (!$accessToken->hasScope('connections')) throw new Exception('The "connections" scope is required.'); - - $response = Http::withToken($accessToken->access_token, $accessToken->token_type)->get($this->baseApi . '/users/@me/connections'); - - $response->throw(); - - return array_map(function ($connection) { - return new \Jakyeru\Larascord\Types\Connection($connection); - }, json_decode($response->body())); - } - - /** - * Join a guild. - * - * @throws RequestException - * @throws Exception - */ - public function joinGuild(AccessToken $accessToken, User $user, string $guildId, array $options = []): GuildMember - { - if (!config('larascord.access_token')) throw new Exception(config('larascord.error_messages.missing_access_token.message')); - if (!$accessToken->hasScope('guilds.join')) throw new Exception('The "guilds" and "guilds.join" scopes are required.'); - - $response = Http::withToken(config('larascord.access_token'), 'Bot')->put($this->baseApi . '/guilds/' . $guildId . '/members/' . $user->id, array_merge([ - 'access_token' => $accessToken->access_token, - ], $options)); - - $response->throw(); - - if ($response->status() === 204) return throw new Exception('User is already in the guild.'); - - return new GuildMember(json_decode($response->body())); - } - - /** - * Create or update a user in the database. - * - * @throws Exception - */ - public function createOrUpdateUser(\Jakyeru\Larascord\Types\User $user): User - { - if (!$user->getAccessToken()) { - throw new Exception('User access token is missing.'); - } - - $forgottenUser = User::where('email', '=', $user->email)->where('id', '!=', $user->id)->first(); - if ($forgottenUser) { - // This case should never happen (TM) - The discord id changed - // The user probably re-created their discord account with the same email - - // Delete Playlist - $playlists = Playlist::where('user_id', $forgottenUser->id)->get(); - foreach($playlists as $playlist) { - PlaylistEpisode::where('playlist_id', $playlist->id)->forceDelete(); - $playlist->forceDelete(); - } - - // Update comments to deleted user - DB::table('comments')->where('commenter_id', '=', $forgottenUser->id)->update(['commenter_id' => 1]); - - $forgottenUser->forceDelete(); - } - - return User::updateOrCreate( - [ - 'id' => $user->id, - ], - $user->toArray(), - ); - } - - /** - * Verify if the user is in the specified guild(s). - */ - public function isUserInGuilds(array $guilds): bool - { - // Verify if the user is in all the specified guilds if strict mode is enabled. - if (config('larascord.guilds_strict')) { - return empty(array_diff(config('larascord.guilds'), array_column($guilds, 'id'))); - } - - // Verify if the user is in any of the specified guilds if strict mode is disabled. - return !empty(array_intersect(config('larascord.guilds'), array_column($guilds, 'id'))); - } - - /** - * Verify if the user has the specified role(s) in the specified guild. - */ - public function hasRoleInGuild(GuildMember $guildMember, array $roles): bool - { - // Verify if the user has any of the specified roles. - return !empty(array_intersect($roles, $guildMember->roles)); - } - - /** - * Updates the user's roles in the database. - */ - public function updateUserRoles(User $user, GuildMember $guildMember, int $guildId): void - { - // Updating the user's roles in the database. - $updatedRoles = $user->roles; - $updatedRoles[$guildId] = $guildMember->roles; - $user->roles = $updatedRoles; - $user->save(); - } - - /** - * Revoke the user's access token. - * - * @throws RequestException - */ - public function revokeAccessToken(string $accessToken): object - { - $response = Http::asForm()->post($this->tokenURL . '/revoke', [ - 'token' => $accessToken, - 'client_id' => config('larascord.client_id'), - 'client_secret' => config('larascord.client_secret'), - ]); - - $response->throw(); - - return json_decode($response->body()); - } -} diff --git a/composer.json b/composer.json index 0bd9806..2d5c06b 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,6 @@ "http-interop/http-factory-guzzle": "^1.2", "intervention/image": "^3.9", "intervention/image-laravel": "^1.3", - "jakyeru/larascord": "^6.0", "laravel/framework": "^11.0", "laravel/sanctum": "^4.0", "laravel/scout": "^10.20", @@ -49,8 +48,6 @@ ], "autoload": { "exclude-from-classmap": [ - "vendor/jakyeru/larascord/src/Http/Services/DiscordService.php", - "vendor/jakyeru/larascord/src/Http/Controllers/DiscordController.php", "vendor/laravelista/comments/src/CommentPolicy.php", "vendor/laravelista/comments/src/CommentService.php" ], @@ -60,8 +57,6 @@ "Database\\Seeders\\": "database/seeders/" }, "files": [ - "app/Override/Discord/Services/DiscordService.php", - "app/Override/Discord/DiscordController.php", "app/Override/Comments/CommentPolicy.php", "app/Override/Comments/CommentService.php" ] diff --git a/composer.lock b/composer.lock index dc35e8f..e1d775a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "484d21a7c10b1609a22d642e71a71cc3", + "content-hash": "1759692ca41f87ed3c80648a187d595b", "packages": [ { "name": "brick/math", @@ -1533,59 +1533,6 @@ ], "time": "2025-04-04T15:09:55+00:00" }, - { - "name": "jakyeru/larascord", - "version": "v6.0.3", - "source": { - "type": "git", - "url": "https://github.com/JakyeRU/Larascord.git", - "reference": "d1099d1418022eda970fec4f13634ee5fbee93b3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/JakyeRU/Larascord/zipball/d1099d1418022eda970fec4f13634ee5fbee93b3", - "reference": "d1099d1418022eda970fec4f13634ee5fbee93b3", - "shasum": "" - }, - "require": { - "guzzlehttp/guzzle": "^7.5", - "laravel/breeze": "^v2.0", - "laravel/framework": "^11", - "php": "^8.2|^8.3" - }, - "require-dev": { - "orchestra/testbench": "^9" - }, - "type": "library", - "extra": { - "laravel": { - "providers": [ - "Jakyeru\\Larascord\\LarascordServiceProvider" - ] - } - }, - "autoload": { - "psr-4": { - "Jakyeru\\Larascord\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jakye", - "email": "jakyeru@gmail.com" - } - ], - "description": "Larascord is a package that allows you to authenticate users in your Laravel application using Discord.", - "support": { - "issues": "https://github.com/JakyeRU/Larascord/issues", - "source": "https://github.com/JakyeRU/Larascord/tree/v6.0.3" - }, - "time": "2025-06-18T18:41:42+00:00" - }, { "name": "jaybizzle/crawler-detect", "version": "v1.3.6", @@ -1638,67 +1585,6 @@ }, "time": "2025-09-30T16:22:43+00:00" }, - { - "name": "laravel/breeze", - "version": "v2.3.8", - "source": { - "type": "git", - "url": "https://github.com/laravel/breeze.git", - "reference": "1a29c5792818bd4cddf70b5f743a227e02fbcfcd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/laravel/breeze/zipball/1a29c5792818bd4cddf70b5f743a227e02fbcfcd", - "reference": "1a29c5792818bd4cddf70b5f743a227e02fbcfcd", - "shasum": "" - }, - "require": { - "illuminate/console": "^11.0|^12.0", - "illuminate/filesystem": "^11.0|^12.0", - "illuminate/support": "^11.0|^12.0", - "illuminate/validation": "^11.0|^12.0", - "php": "^8.2.0", - "symfony/console": "^7.0" - }, - "require-dev": { - "laravel/framework": "^11.0|^12.0", - "orchestra/testbench-core": "^9.0|^10.0", - "phpstan/phpstan": "^2.0" - }, - "type": "library", - "extra": { - "laravel": { - "providers": [ - "Laravel\\Breeze\\BreezeServiceProvider" - ] - } - }, - "autoload": { - "psr-4": { - "Laravel\\Breeze\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Taylor Otwell", - "email": "taylor@laravel.com" - } - ], - "description": "Minimal Laravel authentication scaffolding with Blade and Tailwind.", - "keywords": [ - "auth", - "laravel" - ], - "support": { - "issues": "https://github.com/laravel/breeze/issues", - "source": "https://github.com/laravel/breeze" - }, - "time": "2025-07-18T18:49:59+00:00" - }, { "name": "laravel/framework", "version": "v11.46.1", diff --git a/config/larascord.php b/config/larascord.php deleted file mode 100644 index dd94be1..0000000 --- a/config/larascord.php +++ /dev/null @@ -1,247 +0,0 @@ - env('LARASCORD_CLIENT_ID', null), - - /* - |-------------------------------------------------------------------------- - | Application Secret - |-------------------------------------------------------------------------- - | - | This is the secret of your Discord application. - | - */ - - 'client_secret' => env('LARASCORD_CLIENT_SECRET', null), - - /* - |-------------------------------------------------------------------------- - | Application Access Token - |-------------------------------------------------------------------------- - | - | This is the access token of your Discord application. - | - */ - - 'access_token' => env('LARASCORD_ACCESS_TOKEN', null), - - /* - |-------------------------------------------------------------------------- - | Grant Type - |-------------------------------------------------------------------------- - | - | This is the grant type of your Discord application. It must be set to - | "authorization_code". - | - */ - - 'grant_type' => env('LARASCORD_GRANT_TYPE', 'authorization_code'), - - /* - |-------------------------------------------------------------------------- - | Redirect URI - |-------------------------------------------------------------------------- - | - | This is the URI that Discord will redirect to after the user authorizes - | your application. - | - */ - - 'redirect_uri' => env('APP_URL', 'http://localhost:8000') . '/' . env('LARASCORD_PREFIX', 'larascord') . '/callback', - - /* - |-------------------------------------------------------------------------- - | Scopes - |-------------------------------------------------------------------------- - | - | These are the OAuth2 scopes of your Discord application. - | - */ - - 'scopes' => env('LARASCORD_SCOPE', 'identify&email&guilds&guilds.members.read'), - - /* - |-------------------------------------------------------------------------- - | Route Prefix - |-------------------------------------------------------------------------- - | - | This is the prefix that Larascord will use for its routes. For example, - | the prefix "larascord" will result in the route - | "https://domain.com/larascord/login". - | - */ - - 'route_prefix' => env('LARASCORD_PREFIX', 'larascord'), - - /* - |-------------------------------------------------------------------------- - | OAuth2 Prompt - "none" or "consent" - |-------------------------------------------------------------------------- - | - | The prompt controls how the authorization flow handles existing authorizations. - | If a user has previously authorized your application with the requested scopes - | and prompt is set to consent,it will request them to re-approve their - | authorization. If set to none, it will skip the authorization screen - | and redirect them back to your redirect URI without requesting - | their authorization. - | - */ - - 'prompt' => 'none', - - /* - |-------------------------------------------------------------------------- - | Restrict Access to Specific Guilds - |-------------------------------------------------------------------------- - | - | This option restricts access to the application to users who are members - | of specific Discord guilds. Users who are not members of the specified - | guilds will not be able to use the application. - | - */ - - 'guilds' => [], - - /* - |-------------------------------------------------------------------------- - | Restrict Access to Specific Guilds - Strict Mode - |-------------------------------------------------------------------------- - | - | Enabling this option will require the user to be a member of ALL the - | aforementioned guilds. If this option is disabled, the user will - | only need to be a member of at least ONE of the guilds. - | - */ - - 'guilds_strict' => false, - - /* - |-------------------------------------------------------------------------- - | Restrict Access to Specific Roles - |-------------------------------------------------------------------------- - | - | When this option is enabled, the user will only be able to use the - | application if they have at least one of the specified roles. - | - */ - - // WARNING: This feature makes one request to the Discord API for each guild you specify. (Because you need to fetch the roles for each guild) - // At the moment the database is not checked for roles when the user logs in. It will always fetch the roles from the Discord API. - // Currently, the roles are only updated in the database when the user logs in. The roles from the database can be used in a middleware. - // I'm working on a better way to do this, but for now, this will work. - - 'guild_roles' => [ - // 'guild_id' => [ - // 'role_id', - // 'role_id', - // ], - ], - - /* - |-------------------------------------------------------------------------- - | Remember Me - |-------------------------------------------------------------------------- - | - | Whether or not to remember the user after they log in. - | - */ - - 'remember_me' => true, - - /* - |-------------------------------------------------------------------------- - | Error Messages - |-------------------------------------------------------------------------- - | - | These are the error messages that will be displayed to the user if there - | is an error. - | - */ - - 'error_messages' => [ - 'missing_code' => [ - 'message' => 'The authorization code is missing.', - 'redirect' => '/' - ], - 'invalid_code' => [ - 'message' => 'The authorization code is invalid.', - 'redirect' => '/' - ], - 'authorization_failed' => [ - 'message' => 'The authorization failed.', - 'redirect' => '/' - ], - 'missing_email' => [ - 'message' => 'Couldn\'t get your e-mail address. Please add an e-mail address to your Discord account!', - 'redirect' => '/' - ], - 'invalid_user' => [ - 'message' => 'The user ID doesn\'t match the logged-in user.', - 'redirect' => '/' - ], - 'database_error' => [ - 'message' => 'There was an error with the database. Please try again later.', - 'redirect' => '/' - ], - 'missing_guilds_scope' => [ - 'message' => 'The "guilds" scope is required.', - 'redirect' => '/' - ], - 'missing_guilds_members_read_scope' => [ - 'message' => 'The "guilds" and "guilds.members.read" scopes are required.', - 'redirect' => '/' - ], - 'authorization_failed_guilds' => [ - 'message' => 'Couldn\'t get the servers you\'re in.', - 'redirect' => '/' - ], - 'not_member_guild_only' => [ - 'message' => 'You are not a member of the required guilds.', - 'redirect' => '/' - ], - 'missing_access_token' => [ - 'message' => 'The access token is missing.', - 'redirect' => '/' - ], - 'authorization_failed_roles' => [ - 'message' => 'Couldn\'t get the roles you have.', - 'redirect' => '/' - ], - 'missing_role' => [ - 'message' => 'You don\'t have the required roles.', - 'redirect' => '/' - ], - 'revoke_token_failed' => [ - 'message' => 'An error occurred while trying to revoke your access token.', - 'redirect' => '/' - ], - ], - - /* - |-------------------------------------------------------------------------- - | Success Messages - |-------------------------------------------------------------------------- - | - | These are the success messages that will be displayed to the user if there - | is no error. - | - */ - - 'success_messages' => [ - 'user_deleted' => [ - 'message' => 'Your account has been deleted.', - 'redirect' => '/' - ], - ], - -]; diff --git a/resources/views/auth/confirm-password.blade.php b/resources/views/auth/confirm-password.blade.php deleted file mode 100644 index 6969370..0000000 --- a/resources/views/auth/confirm-password.blade.php +++ /dev/null @@ -1,20 +0,0 @@ - -
- {{ __('This is a secure area of the application. Please confirm your session before continuing.') }} -
- -
- @csrf - -
- - - - - - - {{ __('Confirm') }} - -
-
-
\ No newline at end of file -- 2.49.1 From 7eea8285cacd3147bc42dae9b15b07390771d4d3 Mon Sep 17 00:00:00 2001 From: w33b Date: Wed, 7 Jan 2026 12:10:49 +0100 Subject: [PATCH 02/19] Remove old breeze auth controllers --- .../Auth/AuthenticatedSessionController.php | 48 --------------- .../Auth/ConfirmablePasswordController.php | 41 ------------- ...mailVerificationNotificationController.php | 25 -------- .../EmailVerificationPromptController.php | 22 ------- .../Auth/NewPasswordController.php | 61 ------------------- .../Controllers/Auth/PasswordController.php | 29 --------- .../Auth/PasswordResetLinkController.php | 44 ------------- .../Auth/RegisteredUserController.php | 51 ---------------- .../Auth/VerifyEmailController.php | 28 --------- 9 files changed, 349 deletions(-) delete mode 100644 app/Http/Controllers/Auth/AuthenticatedSessionController.php delete mode 100644 app/Http/Controllers/Auth/ConfirmablePasswordController.php delete mode 100644 app/Http/Controllers/Auth/EmailVerificationNotificationController.php delete mode 100644 app/Http/Controllers/Auth/EmailVerificationPromptController.php delete mode 100644 app/Http/Controllers/Auth/NewPasswordController.php delete mode 100644 app/Http/Controllers/Auth/PasswordController.php delete mode 100644 app/Http/Controllers/Auth/PasswordResetLinkController.php delete mode 100644 app/Http/Controllers/Auth/RegisteredUserController.php delete mode 100644 app/Http/Controllers/Auth/VerifyEmailController.php diff --git a/app/Http/Controllers/Auth/AuthenticatedSessionController.php b/app/Http/Controllers/Auth/AuthenticatedSessionController.php deleted file mode 100644 index 494a106..0000000 --- a/app/Http/Controllers/Auth/AuthenticatedSessionController.php +++ /dev/null @@ -1,48 +0,0 @@ -authenticate(); - - $request->session()->regenerate(); - - return redirect()->intended(RouteServiceProvider::HOME); - } - - /** - * Destroy an authenticated session. - */ - public function destroy(Request $request): RedirectResponse - { - Auth::guard('web')->logout(); - - $request->session()->invalidate(); - - $request->session()->regenerateToken(); - - return redirect('/'); - } -} diff --git a/app/Http/Controllers/Auth/ConfirmablePasswordController.php b/app/Http/Controllers/Auth/ConfirmablePasswordController.php deleted file mode 100644 index 523ddda..0000000 --- a/app/Http/Controllers/Auth/ConfirmablePasswordController.php +++ /dev/null @@ -1,41 +0,0 @@ -validate([ - 'email' => $request->user()->email, - 'password' => $request->password, - ])) { - throw ValidationException::withMessages([ - 'password' => __('auth.password'), - ]); - } - - $request->session()->put('auth.password_confirmed_at', time()); - - return redirect()->intended(RouteServiceProvider::HOME); - } -} diff --git a/app/Http/Controllers/Auth/EmailVerificationNotificationController.php b/app/Http/Controllers/Auth/EmailVerificationNotificationController.php deleted file mode 100644 index 96ba772..0000000 --- a/app/Http/Controllers/Auth/EmailVerificationNotificationController.php +++ /dev/null @@ -1,25 +0,0 @@ -user()->hasVerifiedEmail()) { - return redirect()->intended(RouteServiceProvider::HOME); - } - - $request->user()->sendEmailVerificationNotification(); - - return back()->with('status', 'verification-link-sent'); - } -} diff --git a/app/Http/Controllers/Auth/EmailVerificationPromptController.php b/app/Http/Controllers/Auth/EmailVerificationPromptController.php deleted file mode 100644 index 186eb97..0000000 --- a/app/Http/Controllers/Auth/EmailVerificationPromptController.php +++ /dev/null @@ -1,22 +0,0 @@ -user()->hasVerifiedEmail() - ? redirect()->intended(RouteServiceProvider::HOME) - : view('auth.verify-email'); - } -} diff --git a/app/Http/Controllers/Auth/NewPasswordController.php b/app/Http/Controllers/Auth/NewPasswordController.php deleted file mode 100644 index f1e2814..0000000 --- a/app/Http/Controllers/Auth/NewPasswordController.php +++ /dev/null @@ -1,61 +0,0 @@ - $request]); - } - - /** - * Handle an incoming new password request. - * - * @throws \Illuminate\Validation\ValidationException - */ - public function store(Request $request): RedirectResponse - { - $request->validate([ - 'token' => ['required'], - 'email' => ['required', 'email'], - 'password' => ['required', 'confirmed', Rules\Password::defaults()], - ]); - - // Here we will attempt to reset the user's password. If it is successful we - // will update the password on an actual user model and persist it to the - // database. Otherwise we will parse the error and return the response. - $status = Password::reset( - $request->only('email', 'password', 'password_confirmation', 'token'), - function ($user) use ($request) { - $user->forceFill([ - 'password' => Hash::make($request->password), - 'remember_token' => Str::random(60), - ])->save(); - - event(new PasswordReset($user)); - } - ); - - // If the password was successfully reset, we will redirect the user back to - // the application's home authenticated view. If there is an error we can - // redirect them back to where they came from with their error message. - return $status == Password::PASSWORD_RESET - ? redirect()->route('login')->with('status', __($status)) - : back()->withInput($request->only('email')) - ->withErrors(['email' => __($status)]); - } -} diff --git a/app/Http/Controllers/Auth/PasswordController.php b/app/Http/Controllers/Auth/PasswordController.php deleted file mode 100644 index 6916409..0000000 --- a/app/Http/Controllers/Auth/PasswordController.php +++ /dev/null @@ -1,29 +0,0 @@ -validateWithBag('updatePassword', [ - 'current_password' => ['required', 'current_password'], - 'password' => ['required', Password::defaults(), 'confirmed'], - ]); - - $request->user()->update([ - 'password' => Hash::make($validated['password']), - ]); - - return back()->with('status', 'password-updated'); - } -} diff --git a/app/Http/Controllers/Auth/PasswordResetLinkController.php b/app/Http/Controllers/Auth/PasswordResetLinkController.php deleted file mode 100644 index ce813a6..0000000 --- a/app/Http/Controllers/Auth/PasswordResetLinkController.php +++ /dev/null @@ -1,44 +0,0 @@ -validate([ - 'email' => ['required', 'email'], - ]); - - // We will send the password reset link to this user. Once we have attempted - // to send the link, we will examine the response then see the message we - // need to show to the user. Finally, we'll send out a proper response. - $status = Password::sendResetLink( - $request->only('email') - ); - - return $status == Password::RESET_LINK_SENT - ? back()->with('status', __($status)) - : back()->withInput($request->only('email')) - ->withErrors(['email' => __($status)]); - } -} diff --git a/app/Http/Controllers/Auth/RegisteredUserController.php b/app/Http/Controllers/Auth/RegisteredUserController.php deleted file mode 100644 index 5313f35..0000000 --- a/app/Http/Controllers/Auth/RegisteredUserController.php +++ /dev/null @@ -1,51 +0,0 @@ -validate([ - 'name' => ['required', 'string', 'max:255'], - 'email' => ['required', 'string', 'email', 'max:255', 'unique:'.User::class], - 'password' => ['required', 'confirmed', Rules\Password::defaults()], - ]); - - $user = User::create([ - 'name' => $request->name, - 'email' => $request->email, - 'password' => Hash::make($request->password), - ]); - - event(new Registered($user)); - - Auth::login($user); - - return redirect(RouteServiceProvider::HOME); - } -} diff --git a/app/Http/Controllers/Auth/VerifyEmailController.php b/app/Http/Controllers/Auth/VerifyEmailController.php deleted file mode 100644 index ea87940..0000000 --- a/app/Http/Controllers/Auth/VerifyEmailController.php +++ /dev/null @@ -1,28 +0,0 @@ -user()->hasVerifiedEmail()) { - return redirect()->intended(RouteServiceProvider::HOME.'?verified=1'); - } - - if ($request->user()->markEmailAsVerified()) { - event(new Verified($request->user())); - } - - return redirect()->intended(RouteServiceProvider::HOME.'?verified=1'); - } -} -- 2.49.1 From 98d36d6018ecf9b80e10e9d3bb18cc9a31bc0508 Mon Sep 17 00:00:00 2001 From: w33b Date: Wed, 7 Jan 2026 12:41:11 +0100 Subject: [PATCH 03/19] Fix database structure --- ...d_unique_constraint_to_downloads_table.php | 1 + .../2025_12_03_193018_fix_user_ids.php | 154 ++++++++++++++++++ ..._01_06_161620_fix_discord_oauth_system.php | 46 ++++++ 3 files changed, 201 insertions(+) create mode 100644 database/migrations/2025_12_03_193018_fix_user_ids.php create mode 100644 database/migrations/2026_01_06_161620_fix_discord_oauth_system.php diff --git a/database/migrations/2025_09_21_215923_add_unique_constraint_to_downloads_table.php b/database/migrations/2025_09_21_215923_add_unique_constraint_to_downloads_table.php index 2dab96b..9d7eac1 100644 --- a/database/migrations/2025_09_21_215923_add_unique_constraint_to_downloads_table.php +++ b/database/migrations/2025_09_21_215923_add_unique_constraint_to_downloads_table.php @@ -5,6 +5,7 @@ use App\Models\Downloads; use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; +use Illuminate\Support\Facades\DB; return new class extends Migration { diff --git a/database/migrations/2025_12_03_193018_fix_user_ids.php b/database/migrations/2025_12_03_193018_fix_user_ids.php new file mode 100644 index 0000000..fb5a340 --- /dev/null +++ b/database/migrations/2025_12_03_193018_fix_user_ids.php @@ -0,0 +1,154 @@ +unsignedBigInteger('discord_id')->nullable()->after('id'); + }); + + // 2. Migrate Discord Users IDs + DB::table('users') + ->where('id', '>', 10000) + ->update(['discord_id' => DB::raw('id')]); + + // 3. Temporary new auto increment column + Schema::table('users', function (Blueprint $table) { + $table->unsignedBigInteger('new_id')->first(); + }); + + // 3.5 Manually count (cursed) + $counter = 1; + foreach(User::orderBy('id')->get() as $user) { + $user->new_id = $counter; + $user->save(); + $counter++; + } + + // 4. Drop foreign keys + $this->dropForeignKeys(); + + // 5. Fix ID's in other tables + $this->updateUserIDsInOtherTables(); + + // 6. Remove old ID + Schema::table('users', function (Blueprint $table) { + $table->bigInteger('id')->unsigned()->change(); + $table->dropPrimary('id'); + $table->dropColumn('id'); + }); + + // 7. Rename new_id to id + Schema::table('users', function (Blueprint $table) { + $table->renameColumn('new_id', 'id'); + $table->unsignedBigInteger('id')->autoIncrement()->primary()->change(); + }); + + // 8. Recreate foreign key constraints + $this->addForeignKeys(); + } + + /** + * Drop Foreign Keys referencing the user id + */ + private function dropForeignKeys(): void + { + Schema::table('markable_likes', function (Blueprint $table) { + $table->dropForeign(['user_id']); + }); + + Schema::table('watched', function (Blueprint $table) { + $table->dropForeign(['user_id']); + }); + + Schema::table('discord_access_tokens', function (Blueprint $table) { + $table->dropForeign(['user_id']); + }); + + // Our Schema does include a foreign key, for whatever reason it doesn't exist in the first palce + // Schema::table('user_downloads', function (Blueprint $table) { + // $table->dropForeign(['user_id']); + // }); + } + + /** + * Tables to fix the IDs: + * - comments ['commenter_id'] + * - discord_access_tokens ['user_id'] + * - markable_likes ['user_id'] + * - notifications ['notifiable_id'] + * - playlists ['user_id'] + * - user_downloads ['user_id'] + * - watched ['user_id'] + */ + private function updateUserIDsInOtherTables(): void + { + + DB::table('users')->orderBy('id')->chunk(100, function (Collection $users) { + foreach ($users as $user) { + DB::table('comments') + ->where('commenter_id', $user->id) + ->update(['commenter_id' => $user->new_id]); + + DB::table('discord_access_tokens') + ->where('user_id', $user->id) + ->update(['user_id' => $user->new_id]); + + DB::table('markable_likes') + ->where('user_id', $user->id) + ->update(['user_id' => $user->new_id]); + + DB::table('notifications') + ->where('notifiable_id', $user->id) + ->update(['notifiable_id' => $user->new_id]); + + DB::table('playlists') + ->where('user_id', $user->id) + ->update(['user_id' => $user->new_id]); + + DB::table('user_downloads') + ->where('user_id', $user->id) + ->update(['user_id' => $user->new_id]); + + DB::table('watched') + ->where('user_id', $user->id) + ->update(['user_id' => $user->new_id]); + } + }); + } + + /** + * Re-Add Foreign Keys to tables which we dropped previously + */ + private function addForeignKeys(): void + { + Schema::table('markable_likes', function (Blueprint $table) { + $table->unsignedBigInteger('user_id')->references('id')->on('users')->onDelete('cascade')->change(); + }); + + Schema::table('watched', function (Blueprint $table) { + $table->unsignedBigInteger('user_id')->references('id')->on('users')->onDelete('cascade')->change(); + }); + + Schema::table('discord_access_tokens', function (Blueprint $table) { + $table->unsignedBigInteger('user_id')->references('id')->on('users')->onDelete('cascade')->change(); + }); + + Schema::table('user_downloads', function (Blueprint $table) { + $table->unsignedBigInteger('user_id')->references('id')->on('users')->onDelete('cascade')->change(); + }); + } +}; diff --git a/database/migrations/2026_01_06_161620_fix_discord_oauth_system.php b/database/migrations/2026_01_06_161620_fix_discord_oauth_system.php new file mode 100644 index 0000000..4d69195 --- /dev/null +++ b/database/migrations/2026_01_06_161620_fix_discord_oauth_system.php @@ -0,0 +1,46 @@ +dropColumn('discriminator'); + $table->dropColumn('remember_token'); + $table->dropColumn('banner'); + $table->dropColumn('banner_color'); + $table->dropColumn('accent_color'); + $table->dropColumn('premium_type'); + $table->dropColumn('public_flags'); + $table->dropColumn('verified'); + $table->dropColumn('mfa_enabled'); + }); + + // Change & Add Columns + Schema::table('users', function (Blueprint $table) { + // Rename + $table->renameColumn('username', 'name'); + $table->renameColumn('global_name', 'discord_name'); + $table->renameColumn('avatar', 'discord_avatar'); + + // Re-Add Email verification + $table->timestamp('email_verified_at')->nullable()->after('email'); + + // Re-Add Password Auth + $table->string('password')->nullable()->after('email_verified_at'); + $table->rememberToken()->after('password'); + }); + } +}; -- 2.49.1 From e972f8db4112c00fecd9a72e24274079bc0400eb Mon Sep 17 00:00:00 2001 From: w33b Date: Wed, 7 Jan 2026 12:54:10 +0100 Subject: [PATCH 04/19] Rename column names --- app/Http/Controllers/UserController.php | 4 +- app/Livewire/AdminCommentSearch.php | 4 +- app/Livewire/AdminUserSearch.php | 4 +- app/Models/User.php | 45 +++++++------------ app/Override/Comments/CommentService.php | 2 +- resources/views/layouts/navigation.blade.php | 10 ++--- .../livewire/admin-comment-search.blade.php | 2 +- .../livewire/admin-user-search.blade.php | 2 +- .../livewire/playlist-overview.blade.php | 8 ++-- resources/views/partials/comment.blade.php | 14 +++--- resources/views/profile/edit.blade.php | 6 +-- .../update-profile-information-form.blade.php | 22 +++------ .../views/stream/partials/playlist.blade.php | 2 +- .../views/user/partials/profile.blade.php | 6 +-- .../views/vendor/comments/_comment.blade.php | 14 +++--- 15 files changed, 63 insertions(+), 82 deletions(-) diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index 1836c3e..5e24903 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -17,8 +17,8 @@ class UserController extends Controller */ public function index(string $username): \Illuminate\View\View { - $user = User::where('username', $username) - ->select('id', 'username', 'global_name', 'avatar', 'created_at', 'is_patreon') + $user = User::where('name', $username) + ->select('id', 'name', 'discord_name', 'avatar', 'created_at', 'is_patreon') ->firstOrFail(); return view('user.index', [ diff --git a/app/Livewire/AdminCommentSearch.php b/app/Livewire/AdminCommentSearch.php index 0fe21fe..aa49241 100644 --- a/app/Livewire/AdminCommentSearch.php +++ b/app/Livewire/AdminCommentSearch.php @@ -28,9 +28,9 @@ class AdminCommentSearch extends Component { $comments = DB::table('comments') ->join('users', 'comments.commenter_id', '=', 'users.id') - ->select('comments.*', 'users.username') + ->select('comments.*', 'users.name') ->when($this->search !== '', fn ($query) => $query->where('comment', 'LIKE', "%$this->search%")) - ->when($this->userSearch !== '', fn ($query) => $query->where('username', 'LIKE', "%$this->userSearch%")) + ->when($this->userSearch !== '', fn ($query) => $query->where('name', 'LIKE', "%$this->userSearch%")) ->paginate(12); return view('livewire.admin-comment-search', [ diff --git a/app/Livewire/AdminUserSearch.php b/app/Livewire/AdminUserSearch.php index 8680b44..36e18e9 100644 --- a/app/Livewire/AdminUserSearch.php +++ b/app/Livewire/AdminUserSearch.php @@ -44,8 +44,8 @@ class AdminUserSearch extends Component ->when($this->patreon !== [], fn ($query) => $query->where('is_patreon', 1)) ->when($this->banned !== [], fn ($query) => $query->where('is_banned', 1)) ->when($this->search !== '', fn ($query) => $query->where(function($query) { - $query->where('username', 'like', '%'.$this->search.'%') - ->orWhere('global_name', 'like', '%'.$this->search.'%'); + $query->where('name', 'like', '%'.$this->search.'%') + ->orWhere('discord_name', 'like', '%'.$this->search.'%'); })) ->paginate(20); diff --git a/app/Models/User.php b/app/Models/User.php index 77d4f84..97fa370 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -7,15 +7,13 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; -use Jakyeru\Larascord\Traits\InteractsWithDiscord; use Laravelista\Comments\Commenter; -use Laravel\Sanctum\HasApiTokens; use Illuminate\Support\Facades\DB; class User extends Authenticatable { - use HasApiTokens, HasFactory, Notifiable, InteractsWithDiscord, Commenter; + use HasFactory, Notifiable, Commenter; /** * The attributes that are mass assignable. @@ -23,22 +21,15 @@ class User extends Authenticatable * @var string[] */ protected $fillable = [ - 'id', - 'username', - 'global_name', - 'discriminator', + 'name', 'email', - 'avatar', - 'verified', - 'banner', - 'banner_color', - 'accent_color', + 'password', 'locale', - 'mfa_enabled', - 'premium_type', - 'public_flags', - 'roles', 'is_banned', + // Discord + 'discord_id', + 'discord_name', + 'discord_avatar', ]; /** @@ -47,6 +38,7 @@ class User extends Authenticatable * @var array */ protected $hidden = [ + 'password', 'remember_token', ]; @@ -56,22 +48,19 @@ class User extends Authenticatable * @var array */ protected $casts = [ - 'id' => 'integer', - 'username' => 'string', - 'global_name' => 'string', - 'discriminator' => 'string', + // Laravel defaults + 'email_verified_at' => 'datetime', + 'password' => 'hashed', + // Other + 'name' => 'string', 'email' => 'string', - 'avatar' => 'string', - 'verified' => 'boolean', - 'banner' => 'string', - 'banner_color' => 'string', - 'accent_color' => 'string', 'locale' => 'string', - 'mfa_enabled' => 'boolean', - 'premium_type' => 'integer', - 'public_flags' => 'integer', 'roles' => 'json', 'tag_blacklist' => 'array', + // Discord + 'discord_id' => 'integer', + 'discord_name' => 'string', + 'discord_avatar' => 'string', ]; /** diff --git a/app/Override/Comments/CommentService.php b/app/Override/Comments/CommentService.php index e4406b0..3b47f3c 100644 --- a/app/Override/Comments/CommentService.php +++ b/app/Override/Comments/CommentService.php @@ -122,7 +122,7 @@ class CommentService $url = '/hentai/' . $episode->slug . '#comment-' . $reply->id; $user = Auth::user(); - $username = $user->global_name ?? $user->username; + $username = $user->discord_name ?? $user->name; $parentCommentUser = User::where('id', $comment->commenter_id)->firstOrFail(); $parentCommentUser->notify( diff --git a/resources/views/layouts/navigation.blade.php b/resources/views/layouts/navigation.blade.php index 86fee6c..a766ec4 100644 --- a/resources/views/layouts/navigation.blade.php +++ b/resources/views/layouts/navigation.blade.php @@ -94,9 +94,9 @@ + + + diff --git a/resources/views/components/dropdown-link.blade.php b/resources/views/components/dropdown-link.blade.php index 083548e..20b8f36 100644 --- a/resources/views/components/dropdown-link.blade.php +++ b/resources/views/components/dropdown-link.blade.php @@ -1 +1 @@ -merge(['class' => 'block w-full px-4 py-2 text-left text-sm leading-5 text-gray-700 dark:text-gray-300 hover:bg-neutral-100 dark:hover:bg-neutral-900 focus:outline-none focus:bg-neutral-100 dark:focus:bg-neutral-800 transition duration-150 ease-in-out']) }}>{{ $slot }} +merge(['class' => 'block w-full px-4 py-2 text-start text-sm leading-5 text-gray-700 dark:text-gray-300 hover:bg-neutral-100 dark:hover:bg-neutral-900 focus:outline-none focus:bg-neutral-100 dark:focus:bg-neutral-800 transition duration-150 ease-in-out']) }}>{{ $slot }} diff --git a/resources/views/components/dropdown.blade.php b/resources/views/components/dropdown.blade.php index 4a68c9e..bbb5d63 100644 --- a/resources/views/components/dropdown.blade.php +++ b/resources/views/components/dropdown.blade.php @@ -1,24 +1,16 @@ @props(['align' => 'right', 'width' => '48', 'contentClasses' => 'py-1 bg-white dark:bg-neutral-800']) @php -switch ($align) { - case 'left': - $alignmentClasses = 'origin-top-left left-0'; - break; - case 'top': - $alignmentClasses = 'origin-top'; - break; - case 'right': - default: - $alignmentClasses = 'origin-top-right right-0'; - break; -} +$alignmentClasses = match ($align) { + 'left' => 'ltr:origin-top-left rtl:origin-top-right start-0', + 'top' => 'origin-top', + default => 'ltr:origin-top-right rtl:origin-top-left end-0', +}; -switch ($width) { - case '48': - $width = 'w-48'; - break; -} +$width = match ($width) { + '48' => 'w-48', + default => $width, +}; @endphp
@@ -28,11 +20,11 @@ switch ($width) {