From 2a9c28b81e0f2f758beff53ead1e4d77d9b7d04b Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Wed, 16 Jul 2025 02:53:47 -0600 Subject: [PATCH 1/4] Update ComposeController, fix user tagging endpoint --- app/Http/Controllers/ComposeController.php | 35 +++++++++++++++------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/app/Http/Controllers/ComposeController.php b/app/Http/Controllers/ComposeController.php index 884d2882c..deb8c0c35 100644 --- a/app/Http/Controllers/ComposeController.php +++ b/app/Http/Controllers/ComposeController.php @@ -246,20 +246,19 @@ class ComposeController extends Controller 'string', 'min:1', 'max:300', - new \App\Rules\WebFinger, ], ]); $q = $request->input('q'); - if (Str::of($q)->startsWith('@')) { - if (strlen($q) < 3) { - return []; - } - $q = mb_substr($q, 1); + $cleanQuery = Str::of($q)->startsWith('@') ? Str::substr($q, 1) : $q; + + if (strlen($cleanQuery) < 2) { + return []; } $user = $request->user(); + $currentUserId = $request->user()->profile_id; abort_if($user->has_roles && ! UserRoleService::can('can-post', $user->id), 403, 'Invalid permissions for this action'); @@ -271,10 +270,26 @@ class ComposeController extends Controller $blocked->push($request->user()->profile_id); $operator = config('database.default') === 'pgsql' ? 'ilike' : 'like'; - $results = Profile::select('id', 'domain', 'username') - ->whereNotIn('id', $blocked) - ->whereNull('domain') - ->where('username', $operator, '%'.$q.'%') + $results = Profile::select([ + 'profiles.id', + 'profiles.domain', + 'profiles.username', + 'profiles.followers_count', + ]) + ->selectRaw('MAX(CASE WHEN followers.following_id IS NOT NULL THEN 1 ELSE 0 END) as is_followed') + ->leftJoin('followers', function ($join) use ($currentUserId) { + $join->on('followers.following_id', '=', 'profiles.id') + ->where('followers.profile_id', '=', $currentUserId); + }) + ->whereNotIn('profiles.id', $blocked) + ->where(function ($query) use ($cleanQuery, $operator) { + $query->where('profiles.username', $operator, $cleanQuery.'%') + ->orWhere('profiles.username', $operator, '%'.$cleanQuery.'%'); + }) + ->groupBy('profiles.id', 'profiles.domain', 'profiles.username', 'profiles.followers_count') + ->orderByDesc('is_followed') + ->orderByDesc('profiles.followers_count') + ->orderBy('profiles.username') ->limit(15) ->get() ->map(function ($r) { From 4ab85248e99c855729036afa69d4b6e5736cd432 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Wed, 16 Jul 2025 02:54:58 -0600 Subject: [PATCH 2/4] Update RemoteStatusDelete, fix decrement logic --- .../StatusPipeline/RemoteStatusDelete.php | 96 +++++++++---------- 1 file changed, 45 insertions(+), 51 deletions(-) diff --git a/app/Jobs/StatusPipeline/RemoteStatusDelete.php b/app/Jobs/StatusPipeline/RemoteStatusDelete.php index 65b72c104..2c3f70777 100644 --- a/app/Jobs/StatusPipeline/RemoteStatusDelete.php +++ b/app/Jobs/StatusPipeline/RemoteStatusDelete.php @@ -2,47 +2,35 @@ namespace App\Jobs\StatusPipeline; -use DB, Cache, Storage; -use App\{ - AccountInterstitial, - Bookmark, - CollectionItem, - DirectMessage, - Like, - Media, - MediaTag, - Mention, - Notification, - Report, - Status, - StatusArchived, - StatusHashtag, - StatusView -}; +use App\AccountInterstitial; +use App\Bookmark; +use App\CollectionItem; +use App\DirectMessage; +use App\Jobs\MediaPipeline\MediaDeletePipeline; +use App\Like; +use App\Media; +use App\MediaTag; +use App\Mention; +use App\Notification; +use App\Report; +use App\Services\Account\AccountStatService; +use App\Services\AccountService; +use App\Services\CollectionService; +use App\Services\NotificationService; +use App\Services\StatusService; +use App\Status; +use App\StatusArchived; +use App\StatusHashtag; +use App\StatusView; use Illuminate\Bus\Queueable; -use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldBeUniqueUntilProcessing; +use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; -use Illuminate\Queue\SerializesModels; use Illuminate\Queue\Middleware\WithoutOverlapping; -use League\Fractal; -use Illuminate\Support\Str; -use League\Fractal\Serializer\ArraySerializer; -use App\Transformer\ActivityPub\Verb\DeleteNote; -use App\Util\ActivityPub\Helpers; -use GuzzleHttp\Pool; -use GuzzleHttp\Client; -use GuzzleHttp\Promise; -use App\Util\ActivityPub\HttpSignature; -use App\Services\AccountService; -use App\Services\CollectionService; -use App\Services\StatusService; -use App\Jobs\MediaPipeline\MediaDeletePipeline; -use App\Services\NotificationService; -use App\Services\Account\AccountStatService; +use Illuminate\Queue\SerializesModels; -class RemoteStatusDelete implements ShouldQueue, ShouldBeUniqueUntilProcessing +class RemoteStatusDelete implements ShouldBeUniqueUntilProcessing, ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; @@ -56,8 +44,11 @@ class RemoteStatusDelete implements ShouldQueue, ShouldBeUniqueUntilProcessing public $deleteWhenMissingModels = true; public $tries = 3; + public $maxExceptions = 3; + public $timeout = 180; + public $failOnTimeout = true; /** @@ -72,7 +63,7 @@ class RemoteStatusDelete implements ShouldQueue, ShouldBeUniqueUntilProcessing */ public function uniqueId(): string { - return 'status:remote:delete:' . $this->status->id; + return 'status:remote:delete:'.$this->status->id; } /** @@ -104,11 +95,12 @@ class RemoteStatusDelete implements ShouldQueue, ShouldBeUniqueUntilProcessing { $status = $this->status; - if($status->deleted_at) { + if ($status->deleted_at) { return; } StatusService::del($status->id, true); + // AccountStatService::decrementPostCount($status->profile_id); return $this->unlinkRemoveMedia($status); } @@ -116,11 +108,13 @@ class RemoteStatusDelete implements ShouldQueue, ShouldBeUniqueUntilProcessing public function unlinkRemoveMedia($status) { - if($status->in_reply_to_id) { + if ($status->in_reply_to_id) { $parent = Status::find($status->in_reply_to_id); - if($parent) { - --$parent->reply_count; - $parent->save(); + if ($parent) { + if ($parent->reply_count) { + $parent->reply_count = $parent->reply_count - 1; + $parent->save(); + } StatusService::del($parent->id); } } @@ -132,16 +126,16 @@ class RemoteStatusDelete implements ShouldQueue, ShouldBeUniqueUntilProcessing CollectionItem::whereObjectType('App\Status') ->whereObjectId($status->id) ->get() - ->each(function($col) { + ->each(function ($col) { CollectionService::removeItem($col->collection_id, $col->object_id); $col->delete(); - }); + }); $dms = DirectMessage::whereStatusId($status->id)->get(); - foreach($dms as $dm) { + foreach ($dms as $dm) { $not = Notification::whereItemType('App\DirectMessage') ->whereItemId($dm->id) ->first(); - if($not) { + if ($not) { NotificationService::del($not->profile_id, $not->id); $not->forceDeleteQuietly(); } @@ -149,16 +143,16 @@ class RemoteStatusDelete implements ShouldQueue, ShouldBeUniqueUntilProcessing } Like::whereStatusId($status->id)->forceDelete(); Media::whereStatusId($status->id) - ->get() - ->each(function($media) { - MediaDeletePipeline::dispatch($media)->onQueue('mmo'); - }); + ->get() + ->each(function ($media) { + MediaDeletePipeline::dispatch($media)->onQueue('mmo'); + }); $mediaTags = MediaTag::where('status_id', $status->id)->get(); - foreach($mediaTags as $mtag) { + foreach ($mediaTags as $mtag) { $not = Notification::whereItemType('App\MediaTag') ->whereItemId($mtag->id) ->first(); - if($not) { + if ($not) { NotificationService::del($not->profile_id, $not->id); $not->forceDeleteQuietly(); } From b0a2b9510237571f93bf39a94ca82f7873372d86 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Wed, 16 Jul 2025 02:55:51 -0600 Subject: [PATCH 3/4] Update changelog --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53a89ed45..f7d0646b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,14 @@ - Update Groups ImageResizePipeline with intervention/image v3 support ([616e37066](https://github.com/pixelfed/pixelfed/commit/616e37066)) - Update app config, add Str alias ([5539dd0e1](https://github.com/pixelfed/pixelfed/commit/5539dd0e1)) - Update PlaceController, fix show method ([f81a4acdc](https://github.com/pixelfed/pixelfed/commit/f81a4acdc)) +- Update Places, improve cache invalidation/ttl ([ece23d751](https://github.com/pixelfed/pixelfed/commit/ece23d751)) +- Update ComposeController, add addl compose settings data ([9048ab52c](https://github.com/pixelfed/pixelfed/commit/9048ab52c)) +- Update Admin Users dashboard ([b6bc1e50e](https://github.com/pixelfed/pixelfed/commit/b6bc1e50e)) +- Update TransformImports command, fix IG import bug ([c692c7655](https://github.com/pixelfed/pixelfed/commit/c692c7655)) +- Update ImportService and TransformImports to fix race condition bug ([a8d1d0f2e](https://github.com/pixelfed/pixelfed/commit/a8d1d0f2e)) +- Update ComposeController, prioritize followed users and follower_count first ([10eb1a8ac](https://github.com/pixelfed/pixelfed/commit/10eb1a8ac)) +- Update ComposeController, fix user tagging endpoint ([2a9c28b81](https://github.com/pixelfed/pixelfed/commit/2a9c28b81)) +- Update RemoteStatusDelete, fix decrement logic ([4ab85248e](https://github.com/pixelfed/pixelfed/commit/4ab85248e)) - ([](https://github.com/pixelfed/pixelfed/commit/)) ## [v0.12.5 (2025-03-23)](https://github.com/pixelfed/pixelfed/compare/v0.12.5...dev) From e56bcf3853a52ba1fdd95e4d1245fc0d0ae2df78 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Wed, 16 Jul 2025 02:58:29 -0600 Subject: [PATCH 4/4] Update ComposeController, fix postgres operator --- app/Http/Controllers/ComposeController.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/Http/Controllers/ComposeController.php b/app/Http/Controllers/ComposeController.php index deb8c0c35..37be15824 100644 --- a/app/Http/Controllers/ComposeController.php +++ b/app/Http/Controllers/ComposeController.php @@ -449,6 +449,7 @@ class ComposeController extends Controller ->push($request->user()->profile_id); $currentUserId = $request->user()->profile_id; + $operator = config('database.default') === 'pgsql' ? 'ilike' : 'like'; $results = Profile::select([ 'profiles.id', @@ -462,9 +463,9 @@ class ComposeController extends Controller ->where('followers.profile_id', '=', $currentUserId); }) ->whereNotIn('profiles.id', $blocked) - ->where(function ($query) use ($cleanQuery) { - $query->where('profiles.username', 'like', $cleanQuery.'%') - ->orWhere('profiles.username', 'like', '%'.$cleanQuery.'%'); + ->where(function ($query) use ($cleanQuery, $operator) { + $query->where('profiles.username', $operator, $cleanQuery.'%') + ->orWhere('profiles.username', $operator, '%'.$cleanQuery.'%'); }) ->groupBy('profiles.id', 'profiles.domain', 'profiles.username', 'profiles.followers_count') ->orderByDesc('is_followed')