Laravel 11 exposes MariaDB as a dedicated 'mariadb' driver, so
config('database.default') === 'mysql' checks silently misclassified
MariaDB as the non-mysql (postgres) branch.
- Add App\Util\Database\DatabaseDriver with isMysqlLike()/isPgsql()
plus db_is_mysql_like()/db_is_pgsql() global helpers.
- Route all database.default driver checks through the helpers so
MySQL and MariaDB are treated as one group.
- Use '' (not null) for share/compose caption+rendered, valid whether
the column is nullable or NOT NULL (it is NOT NULL on MySQL/MariaDB).
- Guard pgsql strtolower() in registration against missing fields.
- Scope CustomEmoji::duplicateShortcodes to the grouped column for
Postgres GROUP BY validity.
- Remove stale Postgres guard in status:dedup; use havingRaw for
cross-driver HAVING.
Aligns with the app's dominant convention (413 now()/today() call
sites vs 12 Carbon::now()). Carbon::parse() calls are untouched since
they parse arbitrary date strings, not current-time access.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
users.storage_used only ever grew: uploads incremented it but no deletion
path decremented it, so users hit the account size limit even when their
real media usage was well below it.
- Decrement storage_used in MediaDeletePipeline when media is removed
- Add UserStorageService::increaseStorageUsed / decrementStorageUsed as the
fast, symmetric hot-path counter updates (floor-based, clamped at zero)
- Refactor the 6 upload call sites to use increaseStorageUsed instead of
duplicated inline writes (also fixes ceil/floor drift vs the reconciler)
- Add (user_id, size) covering index so per-user SUM(size) is not a full
table scan (INPLACE/LOCK=NONE, skipped on sqlite)
- Add user:storage:recalculate command to repair affected accounts, with a
daily --stale=168 scheduled reconciler to correct any drift
- Add regression tests for the pipeline and UserStorageService
The Cache::remember('profile:following:'.$pid, ...) block that plucks
following_id and appends the caller's own id was copy-pasted across four
call sites, with inconsistent TTLs (1440 minutes vs 1209600 seconds).
Add FollowerService::getFollowingIds($pid), which owns the cache key that
add()/remove() already invalidate, and use it from InternalApiController,
PublicApiController, ApiV1Controller and HashtagUnfollowPipeline. Removes
the now-unused Follower/Cache imports left behind.
Adds a test covering the followed-ids-plus-self result and the
follows-nobody case.
AvatarController@store and BaseApiController@avatarUpdate wrapped the
upload flow in an empty catch(\Exception) block and returned a success
response even when the upload or save failed.
Log the exception and return a real error response (500 JSON for the
API endpoint, a redirect with validation errors for the web endpoint).
Adds regression tests covering the failure path, the success path, and
non-image rejection.
Pure rename of the App\Rules\PixelfedUsername validation rule to
App\Rules\ValidUsername for a clearer, more idiomatic name. Updates
the class, filename, test, and all 8 controller call sites. No
behavior change.
Replace 7 duplicated inline username validation closures across 6
controllers (ApiV1Dot1, RemoteAuth, CuratedRegister, AdminInvite x2,
AppRegister, Auth/Register) with the existing PixelfedUsername rule.
Add the 'must contain at least one alphabetical character' check to
the rule so all call sites share consistent, stricter validation.
Add PixelfedUsernameTest covering all validation branches.
Move all Eloquent models from the app/ root directory to app/Models/
for consistency with modern Laravel conventions. The project already had
54 models in App\Models; this migrates the remaining 52 legacy models.
Changes:
- Move 52 model files from app/ to app/Models/
- Update namespace declarations in each model
- Update all ~1000 import references across the codebase
- Add Relation::morphMap() in AppServiceProvider for backward
compatibility with existing polymorphic database records
- Add missing HasSnowflakePrimary imports for models that relied
on same-namespace resolution
Adds explicit return type declarations to 498 controller methods
across 88 files. Types inferred from return statements:
- JsonResponse for response()->json() returns
- RedirectResponse for redirect()/back() returns
- View (contract) for view() returns
- Response for response() returns
- void for methods with no return value
- array for array returns
- string/int/bool for scalar returns
Also fixes 3 methods with incorrect bare returns:
- AvatarController::deleteAvatar - bare return → json response
- ImportPostController::checkPermissions - bare return → true
- RemoteAuthController::accountToId - bare return → empty array
Symfony 8.0 removes Request::get(). Laravel 13 will support Symfony 8,
so these 11 usages would break on upgrade. Using $request->input()
which checks both query string and request body (same behavior as the
old get() method).
Replace Auth::user() with $request->user() and Auth::check() with
$request->user() !== null (or ! $request->user()) across all
controllers and middleware that have access to the request object.
This resolves 99 larastan.noAuthFacadeInRequestScope errors and
improves Octane compatibility.
For protected helper methods without $request in scope, uses the
request() helper instead.
Methods that previously lacked a Request parameter but used Auth
facade now accept Request $request via Laravel's auto-injection.
Replace Auth::user() with $request->user() and Auth::check() with
$request->user() !== null (or ! $request->user()) across all
controllers and middleware that have access to the request object.
This resolves 99 larastan.noAuthFacadeInRequestScope errors and
improves Octane compatibility.
For protected helper methods without $request in scope, uses the
request() helper instead.
Methods that previously lacked a Request parameter but used Auth
facade now accept Request $request via Laravel's auto-injection.