From cc6b78c43615cf73fa894edd1bad64c43d6109e7 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Mon, 18 Apr 2022 01:59:27 -0600 Subject: [PATCH 1/4] Update StatusService --- app/Http/Controllers/Api/ApiV1Controller.php | 8 ++++---- app/Services/StatusLabelService.php | 5 +++++ app/Services/StatusService.php | 2 +- app/Transformer/Api/AccountTransformer.php | 2 +- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/app/Http/Controllers/Api/ApiV1Controller.php b/app/Http/Controllers/Api/ApiV1Controller.php index 7beb251a..0bdf1221 100644 --- a/app/Http/Controllers/Api/ApiV1Controller.php +++ b/app/Http/Controllers/Api/ApiV1Controller.php @@ -1867,17 +1867,17 @@ class ApiV1Controller extends Controller if(config('database.default') == 'pgsql') { $dms = DirectMessage::when($scope === 'inbox', function($q, $scope) use($pid) { - return $q->whereIsHidden(false)->whereToId($pid)->orWhere('from_id', $pid); + return $q->whereIsHidden(false)->where('to_id', $pid)->orWhere('from_id', $pid); }) ->when($scope === 'sent', function($q, $scope) use($pid) { - return $q->whereFromId($pid); + return $q->whereFromId($pid)->groupBy(['to_id', 'id']); }) ->when($scope === 'requests', function($q, $scope) use($pid) { return $q->whereToId($pid)->whereIsHidden(true); }); } else { $dms = DirectMessage::when($scope === 'inbox', function($q, $scope) use($pid) { - return $q->whereIsHidden(false)->whereToId($pid)->orWhere('from_id', $pid)->groupBy('to_id'); + return $q->whereIsHidden(false)->where('to_id', $pid)->orWhere('from_id', $pid); }) ->when($scope === 'sent', function($q, $scope) use($pid) { return $q->whereFromId($pid)->groupBy('to_id'); @@ -1887,7 +1887,7 @@ class ApiV1Controller extends Controller }); } - $dms = $dms->latest() + $dms = $dms->orderByDesc('created_at') ->simplePaginate($limit) ->map(function($dm) use($pid) { $from = $pid == $dm->to_id ? $dm->from_id : $dm->to_id; diff --git a/app/Services/StatusLabelService.php b/app/Services/StatusLabelService.php index 2c1a3a7f..30c3533c 100644 --- a/app/Services/StatusLabelService.php +++ b/app/Services/StatusLabelService.php @@ -19,6 +19,11 @@ class StatusLabelService } return Cache::remember(self::CACHE_KEY . $status->id, now()->addDays(7), function() use($status) { + if(!$status->caption) { + return [ + 'covid' => false + ]; + } return [ 'covid' => Str::of(strtolower($status->caption))->contains(['covid','corona', 'coronavirus', 'vaccine', 'vaxx', 'vaccination', 'plandemic']) ]; diff --git a/app/Services/StatusService.php b/app/Services/StatusService.php index f3b4b353..9f8188ce 100644 --- a/app/Services/StatusService.php +++ b/app/Services/StatusService.php @@ -131,7 +131,7 @@ class StatusService $fractal = new Fractal\Manager(); $fractal->setSerializer(new ArraySerializer()); - $resource = new Fractal\Resource\Item($status, new StatusTransformer()); + $resource = new Fractal\Resource\Item($status, new StatusStatelessTransformer()); return $fractal->createData($resource)->toArray(); } diff --git a/app/Transformer/Api/AccountTransformer.php b/app/Transformer/Api/AccountTransformer.php index e8ac8419..1e8ab095 100644 --- a/app/Transformer/Api/AccountTransformer.php +++ b/app/Transformer/Api/AccountTransformer.php @@ -30,7 +30,7 @@ class AccountTransformer extends Fractal\TransformerAbstract 'following_count' => (int) $profile->followingCount(), 'statuses_count' => (int) $profile->statusCount(), 'note' => $profile->bio ?? '', - 'note_text' => strip_tags($profile->bio), + 'note_text' => $profile->bio ? strip_tags($profile->bio) : null, 'url' => $profile->url(), 'avatar' => $profile->avatarUrl(), 'website' => $profile->website, From f34a1e9d8e2d72c1fb9401a811dcc76e107a92a6 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Wed, 20 Apr 2022 05:07:20 -0600 Subject: [PATCH 2/4] Add Conversations model --- app/Http/Controllers/Api/ApiV1Controller.php | 25 +++++--- .../Controllers/DirectMessageController.php | 27 ++++++++ .../Controllers/StoryComposeController.php | 27 ++++++++ app/Models/Conversation.php | 11 ++++ app/Util/ActivityPub/Inbox.php | 39 ++++++++++++ ...4_20_061915_create_conversations_table.php | 62 +++++++++++++++++++ 6 files changed, 181 insertions(+), 10 deletions(-) create mode 100644 app/Models/Conversation.php create mode 100644 database/migrations/2022_04_20_061915_create_conversations_table.php diff --git a/app/Http/Controllers/Api/ApiV1Controller.php b/app/Http/Controllers/Api/ApiV1Controller.php index 0bdf1221..f2c2007a 100644 --- a/app/Http/Controllers/Api/ApiV1Controller.php +++ b/app/Http/Controllers/Api/ApiV1Controller.php @@ -81,6 +81,7 @@ use App\Jobs\MediaPipeline\MediaSyncLicensePipeline; use App\Services\DiscoverService; use App\Services\CustomEmojiService; use App\Services\MarkerService; +use App\Models\Conversation; class ApiV1Controller extends Controller { @@ -1876,18 +1877,22 @@ class ApiV1Controller extends Controller return $q->whereToId($pid)->whereIsHidden(true); }); } else { - $dms = DirectMessage::when($scope === 'inbox', function($q, $scope) use($pid) { - return $q->whereIsHidden(false)->where('to_id', $pid)->orWhere('from_id', $pid); - }) - ->when($scope === 'sent', function($q, $scope) use($pid) { - return $q->whereFromId($pid)->groupBy('to_id'); - }) - ->when($scope === 'requests', function($q, $scope) use($pid) { - return $q->whereToId($pid)->whereIsHidden(true); - }); + $dms = Conversation::when($scope === 'inbox', function($q, $scope) use($pid) { + return $q->whereIsHidden(false) + ->where('to_id', $pid) + ->orWhere('from_id', $pid) + ->orderByDesc('status_id') + ->groupBy(['to_id', 'from_id']); + }) + ->when($scope === 'sent', function($q, $scope) use($pid) { + return $q->whereFromId($pid)->groupBy('to_id'); + }) + ->when($scope === 'requests', function($q, $scope) use($pid) { + return $q->whereToId($pid)->whereIsHidden(true); + }); } - $dms = $dms->orderByDesc('created_at') + $dms = $dms->orderByDesc('status_id') ->simplePaginate($limit) ->map(function($dm) use($pid) { $from = $pid == $dm->to_id ? $dm->from_id : $dm->to_id; diff --git a/app/Http/Controllers/DirectMessageController.php b/app/Http/Controllers/DirectMessageController.php index d59abc0e..8b48f0ec 100644 --- a/app/Http/Controllers/DirectMessageController.php +++ b/app/Http/Controllers/DirectMessageController.php @@ -20,6 +20,7 @@ use App\Jobs\StatusPipeline\NewStatusPipeline; use Illuminate\Support\Str; use App\Util\ActivityPub\Helpers; use App\Services\WebfingerService; +use App\Models\Conversation; class DirectMessageController extends Controller { @@ -329,6 +330,19 @@ class DirectMessageController extends Controller $dm->type = $request->input('type'); $dm->save(); + Conversation::updateOrInsert( + [ + 'to_id' => $recipient->id, + 'from_id' => $profile->id + ], + [ + 'type' => $dm->type, + 'status_id' => $status->id, + 'dm_id' => $dm->id, + 'is_hidden' => $hidden + ] + ); + if(filter_var($msg, FILTER_VALIDATE_URL)) { if(Helpers::validateUrl($msg)) { $dm->type = 'link'; @@ -573,6 +587,19 @@ class DirectMessageController extends Controller $dm->is_hidden = $hidden; $dm->save(); + Conversation::updateOrInsert( + [ + 'to_id' => $recipient->id, + 'from_id' => $profile->id + ], + [ + 'type' => $dm->type, + 'status_id' => $status->id, + 'dm_id' => $dm->id, + 'is_hidden' => $hidden + ] + ); + if($recipient->domain) { $this->remoteDeliver($dm); } diff --git a/app/Http/Controllers/StoryComposeController.php b/app/Http/Controllers/StoryComposeController.php index ec2ebfcf..93486a48 100644 --- a/app/Http/Controllers/StoryComposeController.php +++ b/app/Http/Controllers/StoryComposeController.php @@ -28,6 +28,7 @@ use App\Jobs\StoryPipeline\StoryReplyDeliver; use App\Jobs\StoryPipeline\StoryFanout; use App\Jobs\StoryPipeline\StoryDelete; use ImageOptimizer; +use App\Models\Conversation; class StoryComposeController extends Controller { @@ -420,6 +421,19 @@ class StoryComposeController extends Controller ]); $dm->save(); + Conversation::updateOrInsert( + [ + 'to_id' => $story->profile_id, + 'from_id' => $pid + ], + [ + 'type' => 'story:react', + 'status_id' => $status->id, + 'dm_id' => $dm->id, + 'is_hidden' => false + ] + ); + if($story->local) { // generate notification $n = new Notification; @@ -481,6 +495,19 @@ class StoryComposeController extends Controller ]); $dm->save(); + Conversation::updateOrInsert( + [ + 'to_id' => $story->profile_id, + 'from_id' => $pid + ], + [ + 'type' => 'story:comment', + 'status_id' => $status->id, + 'dm_id' => $dm->id, + 'is_hidden' => false + ] + ); + if($story->local) { // generate notification $n = new Notification; diff --git a/app/Models/Conversation.php b/app/Models/Conversation.php new file mode 100644 index 00000000..4f541a09 --- /dev/null +++ b/app/Models/Conversation.php @@ -0,0 +1,11 @@ +type = 'text'; $dm->save(); + Conversation::updateOrInsert( + [ + 'to_id' => $profile->id, + 'from_id' => $actor->id + ], + [ + 'type' => 'text', + 'status_id' => $status->id, + 'dm_id' => $dm->id, + 'is_hidden' => $hidden + ] + ); + if(count($activity['attachment'])) { $photos = 0; $videos = 0; @@ -911,6 +924,19 @@ class Inbox ]); $dm->save(); + Conversation::updateOrInsert( + [ + 'to_id' => $story->profile_id, + 'from_id' => $actorProfile->id + ], + [ + 'type' => 'story:react', + 'status_id' => $status->id, + 'dm_id' => $dm->id, + 'is_hidden' => false + ] + ); + $n = new Notification; $n->profile_id = $dm->to_id; $n->actor_id = $dm->from_id; @@ -1007,6 +1033,19 @@ class Inbox ]); $dm->save(); + Conversation::updateOrInsert( + [ + 'to_id' => $story->profile_id, + 'from_id' => $actorProfile->id + ], + [ + 'type' => 'story:comment', + 'status_id' => $status->id, + 'dm_id' => $dm->id, + 'is_hidden' => false + ] + ); + $n = new Notification; $n->profile_id = $dm->to_id; $n->actor_id = $dm->from_id; diff --git a/database/migrations/2022_04_20_061915_create_conversations_table.php b/database/migrations/2022_04_20_061915_create_conversations_table.php new file mode 100644 index 00000000..e94b6fdc --- /dev/null +++ b/database/migrations/2022_04_20_061915_create_conversations_table.php @@ -0,0 +1,62 @@ +bigIncrements('id'); + $table->bigInteger('to_id')->unsigned()->index(); + $table->bigInteger('from_id')->unsigned()->index(); + $table->bigInteger('dm_id')->unsigned()->nullable(); + $table->bigInteger('status_id')->unsigned()->nullable(); + $table->string('type')->nullable(); + $table->boolean('is_hidden')->default(false)->index(); + $table->boolean('has_seen')->default(false)->index(); + $table->json('metadata')->nullable(); + $table->unique(['to_id', 'from_id']); + $table->timestamps(); + }); + + sleep(10); + + if(DirectMessage::count()) { + + foreach(DirectMessage::lazy() as $msg) { + Conversation::updateOrInsert([ + 'to_id' => $msg->to_id, + 'from_id' => $msg->from_id, + ], + [ + 'dm_id' => $msg->id, + 'status_id' => $msg->status_id, + 'type' => $msg->type, + 'created_at' => $msg->created_at, + 'updated_at' => $msg->updated_at + ]); + } + } + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('conversations'); + } +} From 3172cb59cd41e12dcc2829d670539576850958ab Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Wed, 20 Apr 2022 05:08:49 -0600 Subject: [PATCH 3/4] Add Conversations to Inbox --- app/Util/ActivityPub/Inbox.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Util/ActivityPub/Inbox.php b/app/Util/ActivityPub/Inbox.php index 8d5c4571..25e3f186 100644 --- a/app/Util/ActivityPub/Inbox.php +++ b/app/Util/ActivityPub/Inbox.php @@ -36,6 +36,7 @@ use App\Util\ActivityPub\Validator\UndoFollow as UndoFollowValidator; use App\Services\PollService; use App\Services\FollowerService; +use App\Models\Conversation; class Inbox { From cb2392f35177c2c2043b984b381580cc78a6ef52 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Tue, 26 Apr 2022 20:36:08 -0600 Subject: [PATCH 4/4] Update FederationController --- app/Http/Controllers/FederationController.php | 34 +++++++++++++++++++ app/Jobs/InboxPipeline/DeleteWorker.php | 9 ----- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/app/Http/Controllers/FederationController.php b/app/Http/Controllers/FederationController.php index 297c9a46..0a8254cb 100644 --- a/app/Http/Controllers/FederationController.php +++ b/app/Http/Controllers/FederationController.php @@ -121,6 +121,23 @@ class FederationController extends Controller $obj = json_decode($payload, true, 8); if(isset($obj['type']) && $obj['type'] === 'Delete') { + if(!isset($obj['id'])) { + return; + } + $lockKey = 'pf:ap:del-lock:' . hash('sha256', $obj['id']); + if( isset($obj['actor']) && + isset($obj['object']) && + isset($obj['id']) && + is_string($obj['id']) && + is_string($obj['actor']) && + is_string($obj['object']) && + $obj['actor'] == $obj['object'] + ) { + if(Cache::get($lockKey) !== null) { + return; + } + } + Cache::put($lockKey, 1, 3600); dispatch(new DeleteWorker($headers, $payload))->onQueue('delete'); } else { dispatch(new InboxValidator($username, $headers, $payload))->onQueue('high'); @@ -138,6 +155,23 @@ class FederationController extends Controller $obj = json_decode($payload, true, 8); if(isset($obj['type']) && $obj['type'] === 'Delete') { + if(!isset($obj['id'])) { + return; + } + $lockKey = 'pf:ap:del-lock:' . hash('sha256', $obj['id']); + if( isset($obj['actor']) && + isset($obj['object']) && + isset($obj['id']) && + is_string($obj['id']) && + is_string($obj['actor']) && + is_string($obj['object']) && + $obj['actor'] == $obj['object'] + ) { + if(Cache::get($lockKey) !== null) { + return; + } + } + Cache::put($lockKey, 1, 3600); dispatch(new DeleteWorker($headers, $payload))->onQueue('delete'); } else { dispatch(new InboxWorker($headers, $payload))->onQueue('high'); diff --git a/app/Jobs/InboxPipeline/DeleteWorker.php b/app/Jobs/InboxPipeline/DeleteWorker.php index 5ec79130..f40edc3f 100644 --- a/app/Jobs/InboxPipeline/DeleteWorker.php +++ b/app/Jobs/InboxPipeline/DeleteWorker.php @@ -49,15 +49,6 @@ class DeleteWorker implements ShouldQueue $headers = $this->headers; $payload = json_decode($this->payload, true, 8); - if(isset($payload['id'])) { - $lockKey = 'pf:ap:del-lock:' . hash('sha256', $payload['id']); - if(Cache::get($lockKey) !== null) { - // Job processed already - return 1; - } - Cache::put($lockKey, 1, 300); - } - if(!isset($headers['signature']) || !isset($headers['date'])) { return; }