diff --git a/components/Media/Controller/Avatar.php b/components/Media/Controller/Media.php similarity index 68% rename from components/Media/Controller/Avatar.php rename to components/Media/Controller/Media.php index b5055e4ace..368720fda6 100644 --- a/components/Media/Controller/Avatar.php +++ b/components/Media/Controller/Media.php @@ -22,20 +22,26 @@ namespace Component\Media\Controller; use App\Core\Controller; -use Component\Media\Media; +use Component\Media\Media as M; use Exception; use Symfony\Component\HttpFoundation\Request; -class Avatar extends Controller +class Media extends Controller { - public function send(Request $request, string $nickname, string $size) + public function avatar(Request $request, string $nickname, string $size) { switch ($size) { case 'full': - $res = Media::getAvatarFileInfo($nickname); - return Media::sendFile($res['file_path'], $res['mimetype'], $res['title']); + $res = M::getAvatarFileInfo($nickname); + return M::sendFile($res['file_path'], $res['mimetype'], $res['title']); default: throw new Exception('Not implemented'); } } + + public function attachment_inline(Request $request, int $id) + { + $res = M::getAttachmentFileInfo($id); + return M::sendFile($res['file_path'], $res['mimetype'], $res['title']); + } } diff --git a/components/Media/Media.php b/components/Media/Media.php index 7b055c626f..d1938b78e2 100644 --- a/components/Media/Media.php +++ b/components/Media/Media.php @@ -34,7 +34,8 @@ class Media extends Module public function onAddRoute($r) { - $r->connect('avatar', '/{nickname<' . Nickname::DISPLAY_FMT . '>}/avatar/{size?full}', [Controller\Avatar::class, 'send']); + $r->connect('avatar', '/{nickname<' . Nickname::DISPLAY_FMT . '>}/avatar/{size?full}', [Controller\Media::class, 'avatar']); + $r->connect('attachment_inline', '/attachment/{id<\d+>}', [Controller\Media::class, 'attachment_inline']); return Event::next; } diff --git a/components/Media/Utils.php b/components/Media/Utils.php index 425f8e4c40..48e3cf109e 100644 --- a/components/Media/Utils.php +++ b/components/Media/Utils.php @@ -86,48 +86,66 @@ abstract class Utils return $response; } - public static function error($res, string $nickname) + public static function error($except, $id, array $res) { switch (count($res)) { case 0: - throw new NoAvatarException(); + throw new $except(); case 1: return $res[0]; default: - Log::error('Avatar query returned more than one result for nickname ' . $nickname); + Log::error('Media query returned more than one result for identifier: \"' . $id . '\"'); throw new Exception(_m('Internal server error')); } } public static function getAvatar(string $nickname) { - return self::error( - Cache::get('avatar-' . $nickname, - function () use ($nickname) { - return DB::dql('select a from App\\Entity\\Avatar a ' . - 'join App\Entity\GSActor g with a.gsactor_id = g.id ' . - 'where g.nickname = :nickname', - ['nickname' => $nickname]); - }), - $nickname - ); + return self::error(NoAvatarException::class, + $nickname, + Cache::get("avatar-{$nickname}", + function () use ($nickname) { + return DB::dql('select a from App\\Entity\\Avatar a ' . + 'join App\Entity\GSActor g with a.gsactor_id = g.id ' . + 'where g.nickname = :nickname', + ['nickname' => $nickname]); + })); + } + + public static function getFileInfo(int $id) + { + return self::error(NoSuchFileException::class, + $id, + Cache::get("file-info-{$id}", + function () use ($id) { + return DB::dql('select f.file_hash, f.mimetype, f.title ' . + 'from App\\Entity\\File f ' . + 'where f.id = :id', + ['id' => $id]); + })); + } + + public static function getAttachmentFileInfo(int $id) + { + $res = self::getFileInfo($id); + $res['file_path'] = Common::config('attachments', 'dir') . $res['file_hash']; + return $res; } public static function getAvatarFileInfo(string $nickname) { try { - $res = self::error( - Cache::get('avatar-file-info-' . $nickname, - function () use ($nickname) { - return DB::dql('select f.file_hash, f.mimetype, f.title ' . - 'from App\\Entity\\File f ' . - 'join App\\Entity\\Avatar a with f.id = a.file_id ' . - 'join App\\Entity\\GSActor g with g.id = a.gsactor_id ' . - 'where g.nickname = :nickname', - ['nickname' => $nickname]); - }), - $nickname - ); + $res = self::error(NoAvatarException::class, + $nickname, + Cache::get("avatar-file-info-{$nickname}", + function () use ($nickname) { + return DB::dql('select f.file_hash, f.mimetype, f.title ' . + 'from App\\Entity\\File f ' . + 'join App\\Entity\\Avatar a with f.id = a.file_id ' . + 'join App\\Entity\\GSActor g with g.id = a.gsactor_id ' . + 'where g.nickname = :nickname', + ['nickname' => $nickname]); + })); $res['file_path'] = Avatar::getFilePathStatic($res['file_hash']); return $res; } catch (Exception $e) { @@ -146,7 +164,7 @@ abstract class Utils throw new Exception('No user is logged in and no avatar provided to `getAvatarUrl`'); } } - return Cache::get('avatar-url-' . $nickname, function () use ($nickname) { + return Cache::get("avatar-url-{$nickname}", function () use ($nickname) { try { return self::getAvatar($nickname)->getUrl(); } catch (NoAvatarException $e) { diff --git a/src/Util/Exception/NoSuchFileException.php b/src/Util/Exception/NoSuchFileException.php new file mode 100644 index 0000000000..d62f3a9bb7 --- /dev/null +++ b/src/Util/Exception/NoSuchFileException.php @@ -0,0 +1,30 @@ +. +// }}} + +namespace App\Util\Exception; + +use function App\Core\I18n\_m; + +class NoSuchFileException extends ClientException +{ + public function __construct() + { + parent::__construct(_m('No such file found')); + } +} diff --git a/templates/note/view.html.twig b/templates/note/view.html.twig index fa2495194c..11ce95837a 100644 --- a/templates/note/view.html.twig +++ b/templates/note/view.html.twig @@ -7,11 +7,17 @@
{{ note.getContent() }} - {% for attachment in note.getAttachments() %} -
- {{ attachment.getTitle() }} -
- {% endfor %} +
+ {% for attachment in note.getAttachments() %} + {% if attachment.mimetype starts with 'image/' %} + {{ attachment.getTitle() }} + {% elseif attachment.mimetype starts with 'video/' %} +
{% for act in get_note_actions(note) %}