. // }}} namespace Component\Attachment; use App\Core\Cache; use App\Core\DB; use App\Core\Event; use App\Core\Modules\Component; use App\Core\Router; use App\Entity\Actor; use App\Entity\Note; use App\Util\Formatting; use Component\Attachment\Controller as C; use Component\Attachment\Entity as E; use Doctrine\Common\Collections\ExpressionBuilder; use Doctrine\ORM\Query\Expr; use Doctrine\ORM\QueryBuilder; use EventResult; class Attachment extends Component { public function onAddRoute(Router $r): EventResult { $r->connect('note_attachment_show', '/object/note/{note_id<\d+>}/attachment/{attachment_id<\d+>}', [C\Attachment::class, 'attachmentShowWithNote']); $r->connect('note_attachment_view', '/object/note/{note_id<\d+>}/attachment/{attachment_id<\d+>}/view', [C\Attachment::class, 'attachmentViewWithNote']); $r->connect('note_attachment_download', '/object/note/{note_id<\d+>}/attachment/{attachment_id<\d+>}/download', [C\Attachment::class, 'attachmentDownloadWithNote']); $r->connect('note_attachment_thumbnail', '/object/note/{note_id<\d+>}/attachment/{attachment_id<\d+>}/thumbnail/{size}', [C\Attachment::class, 'attachmentThumbnailWithNote']); return Event::next; } /** * Get a unique representation of a file on disk * * This can be used in the future to deduplicate images by visual content */ public function onHashFile(string $filename, ?string &$out_hash): EventResult { $out_hash = hash_file(E\Attachment::FILEHASH_ALGO, $filename); return Event::stop; } public function onNoteDeleteRelated(Note &$note, Actor $actor): EventResult { Cache::delete("note-attachments-{$note->getId()}"); foreach ($note->getAttachments() as $attachment) { $attachment->kill(); } DB::wrapInTransaction(fn () => E\AttachmentToNote::removeWhereNoteId($note->getId())); Cache::delete("note-attachments-{$note->getId()}"); return Event::next; } public function onCollectionQueryAddJoins(QueryBuilder &$note_qb, QueryBuilder &$actor_qb): EventResult { if (!\in_array('attachment_to_note', $note_qb->getAllAliases())) { $note_qb->leftJoin( join: E\AttachmentToNote::class, alias: 'attachment_to_note', conditionType: Expr\Join::WITH, condition: 'note.id = attachment_to_note.note_id', ); } return Event::next; } /** * Populate $note_expr with the criteria for looking for notes with attachments */ public function onCollectionQueryCreateExpression(ExpressionBuilder $eb, string $term, ?string $locale, ?Actor $actor, &$note_expr, &$actor_expr): EventResult { $include_term = str_contains($term, ':') ? explode(':', $term)[1] : $term; if (Formatting::startsWith($term, ['note-types:', 'notes-incude:', 'note-filter:'])) { if (\is_null($note_expr)) { $note_expr = []; } if (array_intersect(explode(',', $include_term), ['media', 'image', 'images', 'attachment']) !== []) { $note_expr[] = $eb->neq('attachment_to_note.note_id', null); } else { $note_expr[] = $eb->eq('attachment_to_note.note_id', null); } } return Event::next; } }