From: Philipp Date: Sun, 27 Nov 2022 00:25:59 +0000 (+0100) Subject: Move Browser & Upload to own namespace X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=50316bbb803eaff6a28b1395202e33c9f4c6fd51;p=friendica.git Move Browser & Upload to own namespace --- diff --git a/src/Module/Media/Attachment/Browser.php b/src/Module/Media/Attachment/Browser.php new file mode 100644 index 0000000000..021859c021 --- /dev/null +++ b/src/Module/Media/Attachment/Browser.php @@ -0,0 +1,101 @@ +. + * + */ + +namespace Friendica\Module\Media\Attachment; + +use Friendica\App; +use Friendica\BaseModule; +use Friendica\Core\L10n; +use Friendica\Core\Renderer; +use Friendica\Core\Session\Capability\IHandleUserSessions; +use Friendica\Core\System; +use Friendica\Model\Attach; +use Friendica\Module\Response; +use Friendica\Network\HTTPException\UnauthorizedException; +use Friendica\Util\Profiler; +use Friendica\Util\Strings; +use Psr\Log\LoggerInterface; + +/** + * Browser for Attachments + */ +class Browser extends BaseModule +{ + /** @var IHandleUserSessions */ + protected $session; + /** @var App */ + protected $app; + + public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, IHandleUserSessions $session, App $app, array $server, array $parameters = []) + { + parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); + + $this->session = $session; + $this->app = $app; + } + + protected function content(array $request = []): string + { + if (!$this->session->getLocalUserId()) { + throw new UnauthorizedException($this->t('Permission denied.')); + } + + // Needed to match the correct template in a module that uses a different theme than the user/site/default + $theme = Strings::sanitizeFilePathItem($request['theme'] ?? ''); + if ($theme && is_file("view/theme/$theme/config.php")) { + $this->app->setCurrentTheme($theme); + } + + $files = Attach::selectToArray(['id', 'filename', 'filetype'], ['uid' => $this->session->getLocalUserId()]); + + + $fileArray = array_map([$this, 'map_files'], $files); + + $tpl = Renderer::getMarkupTemplate('media/filebrowser.tpl'); + $output = Renderer::replaceMacros($tpl, [ + '$type' => 'attachment', + '$path' => ['' => $this->t('Files')], + '$folders' => false, + '$files' => $fileArray, + '$cancel' => $this->t('Cancel'), + '$nickname' => $this->app->getLoggedInUserNickname(), + '$upload' => $this->t('Upload'), + ]); + + if (empty($request['mode'])) { + System::httpExit($output); + } + + return $output; + } + + protected function map_files(array $record): array + { + [$m1, $m2] = explode('/', $record['filetype']); + $filetype = file_exists(sprintf('images/icons/%s.png', $m1) ? $m1 : 'text'); + + return [ + sprintf('%s/attach/%s', $this->baseUrl, $record['id']), + $record['filename'], + sprintf('%s/images/icon/16/%s.png', $this->baseUrl, $filetype), + ]; + } +} diff --git a/src/Module/Media/Attachment/Upload.php b/src/Module/Media/Attachment/Upload.php new file mode 100644 index 0000000000..b11469f5af --- /dev/null +++ b/src/Module/Media/Attachment/Upload.php @@ -0,0 +1,152 @@ +. + * + */ + +namespace Friendica\Module\Media\Attachment; + +use Friendica\App; +use Friendica\Core\Config\Capability\IManageConfigValues; +use Friendica\Core\L10n; +use Friendica\Core\Session\Capability\IHandleUserSessions; +use Friendica\Database\Database; +use Friendica\Model\Attach; +use Friendica\Model\User; +use Friendica\Module\Response; +use Friendica\Navigation\SystemMessages; +use Friendica\Network\HTTPException\InternalServerErrorException; +use Friendica\Util\Profiler; +use Friendica\Util\Strings; +use Psr\Log\LoggerInterface; + +/** + * Asynchronous attachment upload module + * + * Only used as the target action of the AjaxUpload Javascript library + */ +class Upload extends \Friendica\BaseModule +{ + /** @var Database */ + private $database; + + /** @var IHandleUserSessions */ + private $userSession; + + /** @var IManageConfigValues */ + private $config; + + /** @var SystemMessages */ + private $systemMessages; + + /** @var bool */ + private $isJson; + + public function __construct(SystemMessages $systemMessages, IManageConfigValues $config, IHandleUserSessions $userSession, Database $database, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) + { + parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); + + $this->database = $database; + $this->userSession = $userSession; + $this->config = $config; + $this->systemMessages = $systemMessages; + } + + protected function post(array $request = []) + { + if ($this->isJson = !empty($request['response']) && $request['response'] == 'json') { + $this->response->setType(Response::TYPE_JSON, 'application/json'); + } + + $owner = User::getOwnerDataById($this->userSession->getLocalUserId()); + + if (!$owner) { + $this->logger->warning('Owner not found.', ['uid' => $this->userSession->getLocalUserId()]); + return $this->return(401, $this->t('Invalid request.')); + } + + if (empty($_FILES['userfile'])) { + $this->logger->warning('No file uploaded (empty userfile)'); + return $this->return(401, $this->t('Invalid request.'), true); + } + + $tempFileName = $_FILES['userfile']['tmp_name']; + $fileName = basename($_FILES['userfile']['name']); + $fileSize = intval($_FILES['userfile']['size']); + $maxFileSize = $this->config->get('system', 'maxfilesize'); + + /* + * Found html code written in text field of form, when trying to upload a + * file with filesize greater than upload_max_filesize. Cause is unknown. + * Then Filesize gets <= 0. + */ + if ($fileSize <= 0) { + @unlink($tempFileName); + $msg = $this->t('Sorry, maybe your upload is bigger than the PHP configuration allows') . '
' . $this->t('Or - did you try to upload an empty file?'); + $this->logger->warning($msg, ['fileSize' => $fileSize]); + return $this->return(401, $msg, true); + } + + if ($maxFileSize && $fileSize > $maxFileSize) { + @unlink($tempFileName); + $msg = $this->t('File exceeds size limit of %s', Strings::formatBytes($maxFileSize)); + $this->logger->warning($msg, ['fileSize' => $fileSize]); + return $this->return(401, $msg); + } + + $newid = Attach::storeFile($tempFileName, $owner['uid'], $fileName, '<' . $owner['id'] . '>'); + + @unlink($tempFileName); + + if ($newid === false) { + $msg = $this->t('File upload failed.'); + $this->logger->warning($msg); + return $this->return(500, $msg); + } + + if ($this->isJson) { + $content = json_encode(['ok' => true, 'id' => $newid], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); + } else { + $content = "\n\n" . '[attachment]' . $newid . '[/attachment]' . "\n"; + } + + return $this->response->addContent($content); + } + + /** + * @param int $httpCode + * @param string $message + * @param bool $systemMessage + * @return void + * @throws InternalServerErrorException + */ + private function return(int $httpCode, string $message, bool $systemMessage = false): void + { + $this->response->setStatus($httpCode, $message); + + if ($this->isJson) { + $this->response->addContent(json_encode(['error' => $message], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)); + } else { + if ($systemMessage) { + $this->systemMessages->addNotice($message); + } + + $this->response->addContent($message); + } + } +} diff --git a/src/Module/Media/AttachmentBrowser.php b/src/Module/Media/AttachmentBrowser.php deleted file mode 100644 index c0ec1c5d9b..0000000000 --- a/src/Module/Media/AttachmentBrowser.php +++ /dev/null @@ -1,101 +0,0 @@ -. - * - */ - -namespace Friendica\Module\Media; - -use Friendica\App; -use Friendica\BaseModule; -use Friendica\Core\L10n; -use Friendica\Core\Renderer; -use Friendica\Core\Session\Capability\IHandleUserSessions; -use Friendica\Core\System; -use Friendica\Model\Attach; -use Friendica\Module\Response; -use Friendica\Network\HTTPException\UnauthorizedException; -use Friendica\Util\Profiler; -use Friendica\Util\Strings; -use Psr\Log\LoggerInterface; - -/** - * Browser for Attachments - */ -class AttachmentBrowser extends BaseModule -{ - /** @var IHandleUserSessions */ - protected $session; - /** @var App */ - protected $app; - - public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, IHandleUserSessions $session, App $app, array $server, array $parameters = []) - { - parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); - - $this->session = $session; - $this->app = $app; - } - - protected function content(array $request = []): string - { - if (!$this->session->getLocalUserId()) { - throw new UnauthorizedException($this->t('Permission denied.')); - } - - // Needed to match the correct template in a module that uses a different theme than the user/site/default - $theme = Strings::sanitizeFilePathItem($request['theme'] ?? ''); - if ($theme && is_file("view/theme/$theme/config.php")) { - $this->app->setCurrentTheme($theme); - } - - $files = Attach::selectToArray(['id', 'filename', 'filetype'], ['uid' => $this->session->getLocalUserId()]); - - - $fileArray = array_map([$this, 'map_files'], $files); - - $tpl = Renderer::getMarkupTemplate('media/filebrowser.tpl'); - $output = Renderer::replaceMacros($tpl, [ - '$type' => 'attachment', - '$path' => ['' => $this->t('Files')], - '$folders' => false, - '$files' => $fileArray, - '$cancel' => $this->t('Cancel'), - '$nickname' => $this->app->getLoggedInUserNickname(), - '$upload' => $this->t('Upload'), - ]); - - if (empty($request['mode'])) { - System::httpExit($output); - } - - return $output; - } - - protected function map_files(array $record): array - { - [$m1, $m2] = explode('/', $record['filetype']); - $filetype = file_exists(sprintf('images/icons/%s.png', $m1) ? $m1 : 'text'); - - return [ - sprintf('%s/attach/%s', $this->baseUrl, $record['id']), - $record['filename'], - sprintf('%s/images/icon/16/%s.png', $this->baseUrl, $filetype), - ]; - } -} diff --git a/src/Module/Media/Photo/Browser.php b/src/Module/Media/Photo/Browser.php new file mode 100644 index 0000000000..48f4b3a96b --- /dev/null +++ b/src/Module/Media/Photo/Browser.php @@ -0,0 +1,125 @@ +. + * + */ + +namespace Friendica\Module\Media\Photo; + +use Friendica\App; +use Friendica\BaseModule; +use Friendica\Core\L10n; +use Friendica\Core\Renderer; +use Friendica\Core\Session\Capability\IHandleUserSessions; +use Friendica\Core\System; +use Friendica\Model\Photo; +use Friendica\Module\Response; +use Friendica\Network\HTTPException\UnauthorizedException; +use Friendica\Util\Images; +use Friendica\Util\Profiler; +use Friendica\Util\Strings; +use Psr\Log\LoggerInterface; + +/** + * Browser for Photos + */ +class Browser extends BaseModule +{ + /** @var IHandleUserSessions */ + protected $session; + /** @var App */ + protected $app; + + public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, IHandleUserSessions $session, App $app, array $server, array $parameters = []) + { + parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); + + $this->session = $session; + $this->app = $app; + } + + protected function content(array $request = []): string + { + if (!$this->session->getLocalUserId()) { + throw new UnauthorizedException($this->t('Permission denied.')); + } + + // Needed to match the correct template in a module that uses a different theme than the user/site/default + $theme = Strings::sanitizeFilePathItem($request['theme'] ?? ''); + if ($theme && is_file("view/theme/$theme/config.php")) { + $this->app->setCurrentTheme($theme); + } + + $album = $this->parameters['album'] ?? null; + + $photos = Photo::getBrowsablePhotosForUser($this->session->getLocalUserId(), $album); + $albums = $album ? false : Photo::getBrowsableAlbumsForUser($this->session->getLocalUserId()); + + $path = [ + '' => $this->t('Photos'), + ]; + if (!empty($album)) { + $path[$album] = $album; + } + + $photosArray = array_map([$this, 'map_files'], $photos); + + $tpl = Renderer::getMarkupTemplate('media/filebrowser.tpl'); + $output = Renderer::replaceMacros($tpl, [ + '$type' => 'photo', + '$path' => $path, + '$folders' => $albums, + '$files' => $photosArray, + '$cancel' => $this->t('Cancel'), + '$nickname' => $this->app->getLoggedInUserNickname(), + '$upload' => $this->t('Upload'), + ]); + + if (empty($request['mode'])) { + System::httpExit($output); + } + + return $output; + } + + protected function map_files(array $record): array + { + $types = Images::supportedTypes(); + $ext = $types[$record['type']]; + $filename_e = $record['filename']; + + // Take the largest picture that is smaller or equal 640 pixels + $photo = Photo::selectFirst( + ['scale'], + [ + "`resource-id` = ? AND `height` <= ? AND `width` <= ?", + $record['resource-id'], + 640, + 640 + ], + ['order' => ['scale']]); + $scale = $photo['scale'] ?? $record['loq']; + + return [ + sprintf('%s/photos/%s/image/%s', $this->baseUrl, $this->app->getLoggedInUserNickname(), $record['resource-id']), + $filename_e, + sprintf('%s/photo/%s-%s.%s', $this->baseUrl, $record['resource-id'], $scale, $ext), + $record['desc'], + ]; + } +} diff --git a/src/Module/Media/Photo/Upload.php b/src/Module/Media/Photo/Upload.php new file mode 100644 index 0000000000..c07249c902 --- /dev/null +++ b/src/Module/Media/Photo/Upload.php @@ -0,0 +1,254 @@ +. + * + */ + +namespace Friendica\Module\Media\Photo; + +use Friendica\App; +use Friendica\Core\Config\Capability\IManageConfigValues; +use Friendica\Core\L10n; +use Friendica\Core\Session\Capability\IHandleUserSessions; +use Friendica\Database\Database; +use Friendica\Model\Photo; +use Friendica\Model\User; +use Friendica\Module\BaseApi; +use Friendica\Module\Response; +use Friendica\Navigation\SystemMessages; +use Friendica\Network\HTTPException\InternalServerErrorException; +use Friendica\Object\Image; +use Friendica\Util\Images; +use Friendica\Util\Profiler; +use Friendica\Util\Strings; +use Psr\Log\LoggerInterface; + +/** + * Asynchronous photo upload module + * + * Only used as the target action of the AjaxUpload Javascript library + */ +class Upload extends \Friendica\BaseModule +{ + /** @var Database */ + private $database; + + /** @var IHandleUserSessions */ + private $userSession; + + /** @var SystemMessages */ + private $systemMessages; + + /** @var IManageConfigValues */ + private $config; + + /** @var bool */ + private $isJson = false; + + public function __construct(IManageConfigValues $config, SystemMessages $systemMessages, IHandleUserSessions $userSession, Database $database, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) + { + parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); + + $this->database = $database; + $this->userSession = $userSession; + $this->systemMessages = $systemMessages; + $this->config = $config; + } + + protected function post(array $request = []) + { + $this->isJson = !empty($request['response']) && $request['response'] == 'json'; + + $album = trim($request['album'] ?? ''); + + $owner = User::getOwnerDataById($this->userSession->getLocalUserId()); + + if (!$owner) { + $this->logger->warning('Owner not found.', ['uid' => $this->userSession->getLocalUserId()]); + return $this->return(401, $this->t('Invalid request.')); + } + + if (empty($_FILES['userfile']) && empty($_FILES['media'])) { + $this->logger->warning('Empty "userfile" and "media" field'); + return $this->return(401, $this->t('Invalid request.')); + } + + $src = ''; + $filename = ''; + $filesize = 0; + $filetype = ''; + + if (!empty($_FILES['userfile'])) { + $src = $_FILES['userfile']['tmp_name']; + $filename = basename($_FILES['userfile']['name']); + $filesize = intval($_FILES['userfile']['size']); + $filetype = $_FILES['userfile']['type']; + } elseif (!empty($_FILES['media'])) { + if (!empty($_FILES['media']['tmp_name'])) { + if (is_array($_FILES['media']['tmp_name'])) { + $src = $_FILES['media']['tmp_name'][0]; + } else { + $src = $_FILES['media']['tmp_name']; + } + } + + if (!empty($_FILES['media']['name'])) { + if (is_array($_FILES['media']['name'])) { + $filename = basename($_FILES['media']['name'][0]); + } else { + $filename = basename($_FILES['media']['name']); + } + } + + if (!empty($_FILES['media']['size'])) { + if (is_array($_FILES['media']['size'])) { + $filesize = intval($_FILES['media']['size'][0]); + } else { + $filesize = intval($_FILES['media']['size']); + } + } + + if (!empty($_FILES['media']['type'])) { + if (is_array($_FILES['media']['type'])) { + $filetype = $_FILES['media']['type'][0]; + } else { + $filetype = $_FILES['media']['type']; + } + } + } + + if ($src == '') { + $this->logger->warning('File source (temporary file) cannot be determined', ['$_FILES' => $_FILES]); + return $this->return(401, $this->t('Invalid request.'), true); + } + + $filetype = Images::getMimeTypeBySource($src, $filename, $filetype); + + $this->logger->info('File upload:', [ + 'src' => $src, + 'filename' => $filename, + 'filesize' => $filesize, + 'filetype' => $filetype, + ]); + + $imagedata = @file_get_contents($src); + $image = new Image($imagedata, $filetype); + + if (!$image->isValid()) { + @unlink($src); + $this->logger->warning($this->t('Unable to process image.'), ['imagedata[]' => gettype($imagedata), 'filetype' => $filetype]); + return $this->return(401, $this->t('Unable to process image.')); + } + + $image->orient($src); + @unlink($src); + + $max_length = $this->config->get('system', 'max_image_length'); + if ($max_length > 0) { + $image->scaleDown($max_length); + $filesize = strlen($image->asString()); + $this->logger->info('File upload: Scaling picture to new size', ['max_length' => $max_length]); + } + + $width = $image->getWidth(); + $height = $image->getHeight(); + + $maximagesize = $this->config->get('system', 'maximagesize'); + + if (!empty($maximagesize) && $filesize > $maximagesize) { + // Scale down to multiples of 640 until the maximum size isn't exceeded anymore + foreach ([5120, 2560, 1280, 640] as $pixels) { + if ($filesize > $maximagesize && max($width, $height) > $pixels) { + $this->logger->info('Resize', ['size' => $filesize, 'width' => $width, 'height' => $height, 'max' => $maximagesize, 'pixels' => $pixels]); + $image->scaleDown($pixels); + $filesize = strlen($image->asString()); + $width = $image->getWidth(); + $height = $image->getHeight(); + } + } + + if ($filesize > $maximagesize) { + @unlink($src); + $this->logger->notice('Image size is too big', ['size' => $filesize, 'max' => $maximagesize]); + return $this->return(401, $this->t('Image exceeds size limit of %s', Strings::formatBytes($maximagesize))); + } + } + + $resource_id = Photo::newResource(); + + $smallest = 0; + + // If we don't have an album name use the Wall Photos album + if (!strlen($album)) { + $album = $this->t('Wall Photos'); + } + + $allow_cid = '<' . $owner['id'] . '>'; + + $result = Photo::store($image, $owner['uid'], 0, $resource_id, $filename, $album, 0, Photo::DEFAULT, $allow_cid); + if (!$result) { + $this->logger->warning('Photo::store() failed', ['result' => $result]); + return $this->return(401, $this->t('Image upload failed.')); + } + + if ($width > 640 || $height > 640) { + $image->scaleDown(640); + $result = Photo::store($image, $owner['uid'], 0, $resource_id, $filename, $album, 1, Photo::DEFAULT, $allow_cid); + if ($result) { + $smallest = 1; + } + } + + if ($width > 320 || $height > 320) { + $image->scaleDown(320); + $result = Photo::store($image, $owner['uid'], 0, $resource_id, $filename, $album, 2, Photo::DEFAULT, $allow_cid); + if ($result && ($smallest == 0)) { + $smallest = 2; + } + } + + $this->logger->info('upload done'); + return $this->return(200, "\n\n" . '[url=' . $this->baseUrl . '/photos/' . $owner['nickname'] . '/image/' . $resource_id . '][img]' . $this->baseUrl . "/photo/$resource_id-$smallest." . $image->getExt() . "[/img][/url]\n\n"); + } + + /** + * @param int $httpCode + * @param string $message + * @param bool $systemMessage + * @return void + * @throws InternalServerErrorException + */ + private function return(int $httpCode, string $message, bool $systemMessage = false): void + { + if ($this->isJson) { + $message = $httpCode >= 400 ? ['error' => $message] : ['ok' => true]; + $this->response->setType(Response::TYPE_JSON, 'application/json'); + $this->response->addContent(json_encode($message, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)); + } else { + if ($systemMessage) { + $this->systemMessages->addNotice($message); + } + + if ($httpCode >= 400) { + $this->response->setStatus($httpCode, $message); + } + + $this->response->addContent($message); + } + } +} diff --git a/src/Module/Media/PhotosBrowser.php b/src/Module/Media/PhotosBrowser.php deleted file mode 100644 index 4c9803fc60..0000000000 --- a/src/Module/Media/PhotosBrowser.php +++ /dev/null @@ -1,125 +0,0 @@ -. - * - */ - -namespace Friendica\Module\Media; - -use Friendica\App; -use Friendica\BaseModule; -use Friendica\Core\L10n; -use Friendica\Core\Renderer; -use Friendica\Core\Session\Capability\IHandleUserSessions; -use Friendica\Core\System; -use Friendica\Model\Photo; -use Friendica\Module\Response; -use Friendica\Network\HTTPException\UnauthorizedException; -use Friendica\Util\Images; -use Friendica\Util\Profiler; -use Friendica\Util\Strings; -use Psr\Log\LoggerInterface; - -/** - * Browser for Photos - */ -class PhotosBrowser extends BaseModule -{ - /** @var IHandleUserSessions */ - protected $session; - /** @var App */ - protected $app; - - public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, IHandleUserSessions $session, App $app, array $server, array $parameters = []) - { - parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); - - $this->session = $session; - $this->app = $app; - } - - protected function content(array $request = []): string - { - if (!$this->session->getLocalUserId()) { - throw new UnauthorizedException($this->t('Permission denied.')); - } - - // Needed to match the correct template in a module that uses a different theme than the user/site/default - $theme = Strings::sanitizeFilePathItem($request['theme'] ?? ''); - if ($theme && is_file("view/theme/$theme/config.php")) { - $this->app->setCurrentTheme($theme); - } - - $album = $this->parameters['album'] ?? null; - - $photos = Photo::getBrowsablePhotosForUser($this->session->getLocalUserId(), $album); - $albums = $album ? false : Photo::getBrowsableAlbumsForUser($this->session->getLocalUserId()); - - $path = [ - '' => $this->t('Photos'), - ]; - if (!empty($album)) { - $path[$album] = $album; - } - - $photosArray = array_map([$this, 'map_files'], $photos); - - $tpl = Renderer::getMarkupTemplate('media/filebrowser.tpl'); - $output = Renderer::replaceMacros($tpl, [ - '$type' => 'photos', - '$path' => $path, - '$folders' => $albums, - '$files' => $photosArray, - '$cancel' => $this->t('Cancel'), - '$nickname' => $this->app->getLoggedInUserNickname(), - '$upload' => $this->t('Upload'), - ]); - - if (empty($request['mode'])) { - System::httpExit($output); - } - - return $output; - } - - protected function map_files(array $record): array - { - $types = Images::supportedTypes(); - $ext = $types[$record['type']]; - $filename_e = $record['filename']; - - // Take the largest picture that is smaller or equal 640 pixels - $photo = Photo::selectFirst( - ['scale'], - [ - "`resource-id` = ? AND `height` <= ? AND `width` <= ?", - $record['resource-id'], - 640, - 640 - ], - ['order' => ['scale']]); - $scale = $photo['scale'] ?? $record['loq']; - - return [ - sprintf('%s/photos/%s/image/%s', $this->baseUrl, $this->app->getLoggedInUserNickname(), $record['resource-id']), - $filename_e, - sprintf('%s/photo/%s-%s.%s', $this->baseUrl, $record['resource-id'], $scale, $ext), - $record['desc'], - ]; - } -} diff --git a/src/Module/Profile/Attachment/Upload.php b/src/Module/Profile/Attachment/Upload.php deleted file mode 100644 index 0624ea5a3f..0000000000 --- a/src/Module/Profile/Attachment/Upload.php +++ /dev/null @@ -1,169 +0,0 @@ -. - * - */ - -namespace Friendica\Module\Profile\Attachment; - -use Friendica\App; -use Friendica\Core\Config\Capability\IManageConfigValues; -use Friendica\Core\L10n; -use Friendica\Core\Session\Capability\IHandleUserSessions; -use Friendica\Database\Database; -use Friendica\Model\Attach; -use Friendica\Model\User; -use Friendica\Module\Response; -use Friendica\Navigation\SystemMessages; -use Friendica\Network\HTTPException\InternalServerErrorException; -use Friendica\Util\Profiler; -use Friendica\Util\Strings; -use Psr\Log\LoggerInterface; - -/** - * Asynchronous attachment upload module - * - * Only used as the target action of the AjaxUpload Javascript library - */ -class Upload extends \Friendica\BaseModule -{ - /** @var Database */ - private $database; - - /** @var IHandleUserSessions */ - private $userSession; - - /** @var IManageConfigValues */ - private $config; - - /** @var SystemMessages */ - private $systemMessages; - - /** @var bool */ - private $isJson; - - public function __construct(SystemMessages $systemMessages, IManageConfigValues $config, IHandleUserSessions $userSession, Database $database, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) - { - parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); - - $this->database = $database; - $this->userSession = $userSession; - $this->config = $config; - $this->systemMessages = $systemMessages; - } - - protected function post(array $request = []) - { - if ($this->isJson = !empty($request['response']) && $request['response'] == 'json') { - $this->response->setType(Response::TYPE_JSON, 'application/json'); - } - - $nick = $this->parameters['nickname']; - $owner = User::getOwnerDataByNick($nick); - if (!$owner) { - $this->logger->warning('owner is not a valid record:', ['owner' => $owner, 'nick' => $nick]); - return $this->return(401, $this->t('Invalid request.')); - } - - $can_post = false; - $contact_id = 0; - $page_owner_uid = $owner['uid']; - $community_page = $owner['page-flags'] == User::PAGE_FLAGS_COMMUNITY; - - if ($this->userSession->getLocalUserId() && $this->userSession->getLocalUserId() == $page_owner_uid) { - $can_post = true; - } elseif ($community_page && !empty($this->userSession->getRemoteContactID($page_owner_uid))) { - $contact_id = $this->userSession->getRemoteContactID($page_owner_uid); - $can_post = $this->database->exists('contact', ['blocked' => false, 'pending' => false, 'id' => $contact_id, 'uid' => $page_owner_uid]); - } - - if (!$can_post) { - $this->logger->warning('User does not have required permissions', ['contact_id' => $contact_id, 'page_owner_uid' => $page_owner_uid]); - return $this->return(403, $this->t('Permission denied.'), true); - } - - if (empty($_FILES['userfile'])) { - $this->logger->warning('No file uploaded (empty userfile)'); - return $this->return(401, $this->t('Invalid request.'), true); - } - - $tempFileName = $_FILES['userfile']['tmp_name']; - $fileName = basename($_FILES['userfile']['name']); - $fileSize = intval($_FILES['userfile']['size']); - $maxFileSize = $this->config->get('system', 'maxfilesize'); - - /* - * Found html code written in text field of form, when trying to upload a - * file with filesize greater than upload_max_filesize. Cause is unknown. - * Then Filesize gets <= 0. - */ - if ($fileSize <= 0) { - @unlink($tempFileName); - $msg = $this->t('Sorry, maybe your upload is bigger than the PHP configuration allows') . '
' . $this->t('Or - did you try to upload an empty file?'); - $this->logger->warning($msg, ['fileSize' => $fileSize]); - return $this->return(401, $msg, true); - } - - if ($maxFileSize && $fileSize > $maxFileSize) { - @unlink($tempFileName); - $msg = $this->t('File exceeds size limit of %s', Strings::formatBytes($maxFileSize)); - $this->logger->warning($msg, ['fileSize' => $fileSize]); - return $this->return(401, $msg); - } - - $newid = Attach::storeFile($tempFileName, $page_owner_uid, $fileName, '<' . $owner['id'] . '>'); - - @unlink($tempFileName); - - if ($newid === false) { - $msg = $this->t('File upload failed.'); - $this->logger->warning($msg); - return $this->return(500, $msg); - } - - if ($this->isJson) { - $content = json_encode(['ok' => true, 'id' => $newid], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); - } else { - $content = "\n\n" . '[attachment]' . $newid . '[/attachment]' . "\n"; - } - - return $this->response->addContent($content); - } - - /** - * @param int $httpCode - * @param string $message - * @param bool $systemMessage - * @return void - * @throws InternalServerErrorException - */ - private function return(int $httpCode, string $message, bool $systemMessage = false): void - { - $this->response->setStatus($httpCode, $message); - - if ($this->isJson) { - $this->response->addContent(json_encode(['error' => $message], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)); - } else { - if ($systemMessage) { - $this->systemMessages->addNotice($message); - } - - $this->response->addContent($message); - } - } -} diff --git a/src/Module/Profile/Photos.php b/src/Module/Profile/Photos.php new file mode 100644 index 0000000000..50af6f0e96 --- /dev/null +++ b/src/Module/Profile/Photos.php @@ -0,0 +1,196 @@ +. + * + */ + +namespace Friendica\Module\Profile; + +use Friendica\App; +use Friendica\Content\Pager; +use Friendica\Content\Widget; +use Friendica\Core\Config\Capability\IManageConfigValues; +use Friendica\Core\L10n; +use Friendica\Core\Renderer; +use Friendica\Core\Session\Capability\IHandleUserSessions; +use Friendica\Database\Database; +use Friendica\Model\Contact; +use Friendica\Model\Photo; +use Friendica\Model\Profile; +use Friendica\Model\User; +use Friendica\Module\Response; +use Friendica\Network\HTTPException; +use Friendica\Security\Security; +use Friendica\Util\Images; +use Friendica\Util\Profiler; +use Psr\Log\LoggerInterface; + +class Photos extends \Friendica\Module\BaseProfile +{ + /** @var IHandleUserSessions */ + private $session; + /** @var App\Page */ + private $page; + /** @var IManageConfigValues */ + private $config; + /** @var App */ + private $app; + /** @var Database */ + private $database; + + public function __construct(Database $database, App $app, IManageConfigValues $config, App\Page $page, IHandleUserSessions $session, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) + { + parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); + + $this->session = $session; + $this->page = $page; + $this->config = $config; + $this->app = $app; + $this->database = $database; + } + + protected function content(array $request = []): string + { + parent::content($request); + + if ($this->config->get('system', 'block_public') && !$this->session->isAuthenticated()) { + throw new HttpException\ForbiddenException($this->t('Public access denied.')); + } + + $owner = User::getOwnerDataByNick($this->parameters['nickname']); + if (!isset($owner['account_removed']) || $owner['account_removed']) { + throw new HTTPException\NotFoundException($this->t('User not found.')); + } + + $owner_uid = $owner['uid']; + $is_owner = $this->session->getLocalUserId() && ($this->session->getLocalUserId() == $owner_uid); + + $remote_contact = false; + if ($this->session->getRemoteContactID($owner_uid)) { + $contact_id = $this->session->getRemoteContactID($owner_uid); + + $contact = Contact::getContactForUser($contact_id, $owner_uid, ['blocked', 'pending']); + $remote_contact = $contact && !$contact['blocked'] && !$contact['pending']; + } + + if ($owner['hidewall'] && !$is_owner && !$remote_contact) { + throw new HttpException\ForbiddenException($this->t('Access to this item is restricted.')); + } + + $this->session->set('photo_return', $this->args->getCommand()); + + $sql_extra = Security::getPermissionsSQLByUserId($owner_uid); + + $photo = $this->database->toArray($this->database->p( + "SELECT COUNT(DISTINCT `resource-id`) AS `count` + FROM `photo` + WHERE `uid` = ? + AND `photo-type` = ? + $sql_extra", + $owner['uid'], + Photo::DEFAULT, + )); + $total = $photo[0]['count']; + + $pager = new Pager($this->l10n, $this->args->getQueryString(), 20); + + $photos = $this->database->toArray($this->database->p( + "SELECT + `resource-id`, + ANY_VALUE(`id`) AS `id`, + ANY_VALUE(`filename`) AS `filename`, + ANY_VALUE(`type`) AS `type`, + ANY_VALUE(`album`) AS `album`, + max(`scale`) AS `scale`, + ANY_VALUE(`created`) AS `created` + FROM `photo` + WHERE `uid` = ? + AND `photo-type` = ? + $sql_extra + GROUP BY `resource-id` + ORDER BY `created` DESC + LIMIT ? , ?", + $owner['uid'], + Photo::DEFAULT, + $pager->getStart(), + $pager->getItemsPerPage() + )); + + $phototypes = Images::supportedTypes(); + + $photos = array_map(function ($photo) use ($owner, $phototypes) { + return [ + 'id' => $photo['id'], + 'link' => 'photos/' . $owner['nickname'] . '/image/' . $photo['resource-id'], + 'title' => $this->t('View Photo'), + 'src' => 'photo/' . $photo['resource-id'] . '-' . ((($photo['scale']) == 6) ? 4 : $photo['scale']) . '.' . $phototypes[$photo['type']], + 'alt' => $photo['filename'], + 'album' => [ + 'link' => 'photos/' . $owner['nickname'] . '/album/' . bin2hex($photo['album']), + 'name' => $photo['album'], + 'alt' => $this->t('View Album'), + ], + ]; + }, $photos); + + $tpl = Renderer::getMarkupTemplate('photos_head.tpl'); + $this->page['htmlhead'] .= Renderer::replaceMacros($tpl, [ + '$ispublic' => $this->t('everybody') + ]); + + if ($albums = Photo::getAlbums($owner['uid'])) { + $albums = array_map(function ($album) use ($owner) { + return [ + 'text' => $album['album'], + 'total' => $album['total'], + 'url' => 'photos/' . $owner['nickname'] . '/album/' . bin2hex($album['album']), + 'urlencode' => urlencode($album['album']), + 'bin2hex' => bin2hex($album['album']) + ]; + }, $albums); + + $photo_albums_widget = Renderer::replaceMacros(Renderer::getMarkupTemplate('photo_albums.tpl'), [ + '$nick' => $owner['nickname'], + '$title' => $this->t('Photo Albums'), + '$recent' => $this->t('Recent Photos'), + '$albums' => $albums, + '$upload' => [$this->t('Upload New Photos'), 'photos/' . $owner['nickname'] . '/upload'], + '$can_post' => $this->session->getLocalUserId() && $owner['uid'] == $this->session->getLocalUserId(), + ]); + } + + $this->page['aside'] .= Widget\VCard::getHTML($owner); + + if (!empty($photo_albums_widget)) { + $this->page['aside'] .= $photo_albums_widget; + } + + $o = self::getTabsHTML($this->app, 'photos', $is_owner, $owner['nickname'], Profile::getByUID($owner['uid'])['hide-friends'] ?? false); + + $tpl = Renderer::getMarkupTemplate('photos_recent.tpl'); + $o .= Renderer::replaceMacros($tpl, [ + '$title' => $this->t('Recent Photos'), + '$can_post' => $is_owner || $remote_contact && $owner['page-flags'] == User::PAGE_FLAGS_COMMUNITY, + '$upload' => [$this->t('Upload New Photos'), 'photos/' . $owner['nickname'] . '/upload'], + '$photos' => $photos, + '$paginate' => $pager->renderFull($total), + ]); + + return $o; + } +} diff --git a/src/Module/Profile/Photos/Index.php b/src/Module/Profile/Photos/Index.php deleted file mode 100644 index 82803ac570..0000000000 --- a/src/Module/Profile/Photos/Index.php +++ /dev/null @@ -1,196 +0,0 @@ -. - * - */ - -namespace Friendica\Module\Profile\Photos; - -use Friendica\App; -use Friendica\Content\Pager; -use Friendica\Content\Widget; -use Friendica\Core\Config\Capability\IManageConfigValues; -use Friendica\Core\L10n; -use Friendica\Core\Renderer; -use Friendica\Core\Session\Capability\IHandleUserSessions; -use Friendica\Database\Database; -use Friendica\Model\Contact; -use Friendica\Model\Photo; -use Friendica\Model\Profile; -use Friendica\Model\User; -use Friendica\Module\Response; -use Friendica\Network\HTTPException; -use Friendica\Security\Security; -use Friendica\Util\Images; -use Friendica\Util\Profiler; -use Psr\Log\LoggerInterface; - -class Index extends \Friendica\Module\BaseProfile -{ - /** @var IHandleUserSessions */ - private $session; - /** @var App\Page */ - private $page; - /** @var IManageConfigValues */ - private $config; - /** @var App */ - private $app; - /** @var Database */ - private $database; - - public function __construct(Database $database, App $app, IManageConfigValues $config, App\Page $page, IHandleUserSessions $session, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) - { - parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); - - $this->session = $session; - $this->page = $page; - $this->config = $config; - $this->app = $app; - $this->database = $database; - } - - protected function content(array $request = []): string - { - parent::content($request); - - if ($this->config->get('system', 'block_public') && !$this->session->isAuthenticated()) { - throw new HttpException\ForbiddenException($this->t('Public access denied.')); - } - - $owner = User::getOwnerDataByNick($this->parameters['nickname']); - if (!isset($owner['account_removed']) || $owner['account_removed']) { - throw new HTTPException\NotFoundException($this->t('User not found.')); - } - - $owner_uid = $owner['uid']; - $is_owner = $this->session->getLocalUserId() && ($this->session->getLocalUserId() == $owner_uid); - - $remote_contact = false; - if ($this->session->getRemoteContactID($owner_uid)) { - $contact_id = $this->session->getRemoteContactID($owner_uid); - - $contact = Contact::getContactForUser($contact_id, $owner_uid, ['blocked', 'pending']); - $remote_contact = $contact && !$contact['blocked'] && !$contact['pending']; - } - - if ($owner['hidewall'] && !$is_owner && !$remote_contact) { - throw new HttpException\ForbiddenException($this->t('Access to this item is restricted.')); - } - - $this->session->set('photo_return', $this->args->getCommand()); - - $sql_extra = Security::getPermissionsSQLByUserId($owner_uid); - - $photo = $this->database->toArray($this->database->p( - "SELECT COUNT(DISTINCT `resource-id`) AS `count` - FROM `photo` - WHERE `uid` = ? - AND `photo-type` = ? - $sql_extra", - $owner['uid'], - Photo::DEFAULT, - )); - $total = $photo[0]['count']; - - $pager = new Pager($this->l10n, $this->args->getQueryString(), 20); - - $photos = $this->database->toArray($this->database->p( - "SELECT - `resource-id`, - ANY_VALUE(`id`) AS `id`, - ANY_VALUE(`filename`) AS `filename`, - ANY_VALUE(`type`) AS `type`, - ANY_VALUE(`album`) AS `album`, - max(`scale`) AS `scale`, - ANY_VALUE(`created`) AS `created` - FROM `photo` - WHERE `uid` = ? - AND `photo-type` = ? - $sql_extra - GROUP BY `resource-id` - ORDER BY `created` DESC - LIMIT ? , ?", - $owner['uid'], - Photo::DEFAULT, - $pager->getStart(), - $pager->getItemsPerPage() - )); - - $phototypes = Images::supportedTypes(); - - $photos = array_map(function ($photo) use ($owner, $phototypes) { - return [ - 'id' => $photo['id'], - 'link' => 'photos/' . $owner['nickname'] . '/image/' . $photo['resource-id'], - 'title' => $this->t('View Photo'), - 'src' => 'photo/' . $photo['resource-id'] . '-' . ((($photo['scale']) == 6) ? 4 : $photo['scale']) . '.' . $phototypes[$photo['type']], - 'alt' => $photo['filename'], - 'album' => [ - 'link' => 'photos/' . $owner['nickname'] . '/album/' . bin2hex($photo['album']), - 'name' => $photo['album'], - 'alt' => $this->t('View Album'), - ], - ]; - }, $photos); - - $tpl = Renderer::getMarkupTemplate('photos_head.tpl'); - $this->page['htmlhead'] .= Renderer::replaceMacros($tpl, [ - '$ispublic' => $this->t('everybody') - ]); - - if ($albums = Photo::getAlbums($owner['uid'])) { - $albums = array_map(function ($album) use ($owner) { - return [ - 'text' => $album['album'], - 'total' => $album['total'], - 'url' => 'photos/' . $owner['nickname'] . '/album/' . bin2hex($album['album']), - 'urlencode' => urlencode($album['album']), - 'bin2hex' => bin2hex($album['album']) - ]; - }, $albums); - - $photo_albums_widget = Renderer::replaceMacros(Renderer::getMarkupTemplate('photo_albums.tpl'), [ - '$nick' => $owner['nickname'], - '$title' => $this->t('Photo Albums'), - '$recent' => $this->t('Recent Photos'), - '$albums' => $albums, - '$upload' => [$this->t('Upload New Photos'), 'photos/' . $owner['nickname'] . '/upload'], - '$can_post' => $this->session->getLocalUserId() && $owner['uid'] == $this->session->getLocalUserId(), - ]); - } - - $this->page['aside'] .= Widget\VCard::getHTML($owner); - - if (!empty($photo_albums_widget)) { - $this->page['aside'] .= $photo_albums_widget; - } - - $o = self::getTabsHTML($this->app, 'photos', $is_owner, $owner['nickname'], Profile::getByUID($owner['uid'])['hide-friends'] ?? false); - - $tpl = Renderer::getMarkupTemplate('photos_recent.tpl'); - $o .= Renderer::replaceMacros($tpl, [ - '$title' => $this->t('Recent Photos'), - '$can_post' => $is_owner || $remote_contact && $owner['page-flags'] == User::PAGE_FLAGS_COMMUNITY, - '$upload' => [$this->t('Upload New Photos'), 'photos/' . $owner['nickname'] . '/upload'], - '$photos' => $photos, - '$paginate' => $pager->renderFull($total), - ]); - - return $o; - } -} diff --git a/src/Module/Profile/Photos/Upload.php b/src/Module/Profile/Photos/Upload.php deleted file mode 100644 index e99d7e1083..0000000000 --- a/src/Module/Profile/Photos/Upload.php +++ /dev/null @@ -1,279 +0,0 @@ -. - * - */ - -namespace Friendica\Module\Profile\Photos; - -use Friendica\App; -use Friendica\Core\Config\Capability\IManageConfigValues; -use Friendica\Core\L10n; -use Friendica\Core\Session\Capability\IHandleUserSessions; -use Friendica\Database\Database; -use Friendica\Model\Photo; -use Friendica\Model\User; -use Friendica\Module\BaseApi; -use Friendica\Module\Response; -use Friendica\Navigation\SystemMessages; -use Friendica\Network\HTTPException\InternalServerErrorException; -use Friendica\Object\Image; -use Friendica\Util\Images; -use Friendica\Util\Profiler; -use Friendica\Util\Strings; -use Psr\Log\LoggerInterface; - -/** - * Asynchronous photo upload module - * - * Only used as the target action of the AjaxUpload Javascript library - */ -class Upload extends \Friendica\BaseModule -{ - /** @var Database */ - private $database; - - /** @var IHandleUserSessions */ - private $userSession; - - /** @var SystemMessages */ - private $systemMessages; - - /** @var IManageConfigValues */ - private $config; - - /** @var bool */ - private $isJson = false; - - public function __construct(IManageConfigValues $config, SystemMessages $systemMessages, IHandleUserSessions $userSession, Database $database, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) - { - parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); - - $this->database = $database; - $this->userSession = $userSession; - $this->systemMessages = $systemMessages; - $this->config = $config; - } - - protected function post(array $request = []) - { - $this->isJson = !empty($request['response']) && $request['response'] == 'json'; - - $album = trim($request['album'] ?? ''); - - if (empty($_FILES['media'])) { - $user = $this->database->selectFirst('owner-view', ['id', 'uid', 'nickname', 'page-flags'], ['nickname' => $this->parameters['nickname'], 'blocked' => false]); - } else { - $user = $this->database->selectFirst('owner-view', ['id', 'uid', 'nickname', 'page-flags'], ['uid' => BaseApi::getCurrentUserID() ?: null, 'blocked' => false]); - } - - if (!$this->database->isResult($user)) { - $this->logger->warning('User is not valid', ['nickname' => $this->parameters['nickname'], 'user' => $user]); - return $this->return(404, $this->t('User not found.')); - } - - /* - * Setup permissions structures - */ - $can_post = false; - $visitor = 0; - $contact_id = 0; - $page_owner_uid = $user['uid']; - - if ($this->userSession->getLocalUserId() && $this->userSession->getLocalUserId() == $page_owner_uid) { - $can_post = true; - } elseif ($user['page-flags'] == User::PAGE_FLAGS_COMMUNITY && !$this->userSession->getRemoteContactID($page_owner_uid)) { - $contact_id = $this->userSession->getRemoteContactID($page_owner_uid); - $can_post = $this->database->exists('contact', ['blocked' => false, 'pending' => false, 'id' => $contact_id, 'uid' => $page_owner_uid]); - $visitor = $contact_id; - } - - if (!$can_post) { - $this->logger->warning('No permission to upload files', ['contact_id' => $contact_id, 'page_owner_uid' => $page_owner_uid]); - return $this->return(403, $this->t('Permission denied.'), true); - } - - if (empty($_FILES['userfile']) && empty($_FILES['media'])) { - $this->logger->warning('Empty "userfile" and "media" field'); - return $this->return(401, $this->t('Invalid request.')); - } - - $src = ''; - $filename = ''; - $filesize = 0; - $filetype = ''; - - if (!empty($_FILES['userfile'])) { - $src = $_FILES['userfile']['tmp_name']; - $filename = basename($_FILES['userfile']['name']); - $filesize = intval($_FILES['userfile']['size']); - $filetype = $_FILES['userfile']['type']; - } elseif (!empty($_FILES['media'])) { - if (!empty($_FILES['media']['tmp_name'])) { - if (is_array($_FILES['media']['tmp_name'])) { - $src = $_FILES['media']['tmp_name'][0]; - } else { - $src = $_FILES['media']['tmp_name']; - } - } - - if (!empty($_FILES['media']['name'])) { - if (is_array($_FILES['media']['name'])) { - $filename = basename($_FILES['media']['name'][0]); - } else { - $filename = basename($_FILES['media']['name']); - } - } - - if (!empty($_FILES['media']['size'])) { - if (is_array($_FILES['media']['size'])) { - $filesize = intval($_FILES['media']['size'][0]); - } else { - $filesize = intval($_FILES['media']['size']); - } - } - - if (!empty($_FILES['media']['type'])) { - if (is_array($_FILES['media']['type'])) { - $filetype = $_FILES['media']['type'][0]; - } else { - $filetype = $_FILES['media']['type']; - } - } - } - - if ($src == '') { - $this->logger->warning('File source (temporary file) cannot be determined', ['$_FILES' => $_FILES]); - return $this->return(401, $this->t('Invalid request.'), true); - } - - $filetype = Images::getMimeTypeBySource($src, $filename, $filetype); - - $this->logger->info('File upload:', [ - 'src' => $src, - 'filename' => $filename, - 'filesize' => $filesize, - 'filetype' => $filetype, - ]); - - $imagedata = @file_get_contents($src); - $image = new Image($imagedata, $filetype); - - if (!$image->isValid()) { - @unlink($src); - $this->logger->warning($this->t('Unable to process image.'), ['imagedata[]' => gettype($imagedata), 'filetype' => $filetype]); - return $this->return(401, $this->t('Unable to process image.')); - } - - $image->orient($src); - @unlink($src); - - $max_length = $this->config->get('system', 'max_image_length'); - if ($max_length > 0) { - $image->scaleDown($max_length); - $filesize = strlen($image->asString()); - $this->logger->info('File upload: Scaling picture to new size', ['max_length' => $max_length]); - } - - $width = $image->getWidth(); - $height = $image->getHeight(); - - $maximagesize = $this->config->get('system', 'maximagesize'); - - if (!empty($maximagesize) && $filesize > $maximagesize) { - // Scale down to multiples of 640 until the maximum size isn't exceeded anymore - foreach ([5120, 2560, 1280, 640] as $pixels) { - if ($filesize > $maximagesize && max($width, $height) > $pixels) { - $this->logger->info('Resize', ['size' => $filesize, 'width' => $width, 'height' => $height, 'max' => $maximagesize, 'pixels' => $pixels]); - $image->scaleDown($pixels); - $filesize = strlen($image->asString()); - $width = $image->getWidth(); - $height = $image->getHeight(); - } - } - - if ($filesize > $maximagesize) { - @unlink($src); - $this->logger->notice('Image size is too big', ['size' => $filesize, 'max' => $maximagesize]); - return $this->return(401, $this->t('Image exceeds size limit of %s', Strings::formatBytes($maximagesize))); - } - } - - $resource_id = Photo::newResource(); - - $smallest = 0; - - // If we don't have an album name use the Wall Photos album - if (!strlen($album)) { - $album = $this->t('Wall Photos'); - } - - $allow_cid = '<' . $user['id'] . '>'; - - $result = Photo::store($image, $page_owner_uid, $visitor, $resource_id, $filename, $album, 0, Photo::DEFAULT, $allow_cid); - if (!$result) { - $this->logger->warning('Photo::store() failed', ['result' => $result]); - return $this->return(401, $this->t('Image upload failed.')); - } - - if ($width > 640 || $height > 640) { - $image->scaleDown(640); - $result = Photo::store($image, $page_owner_uid, $visitor, $resource_id, $filename, $album, 1, Photo::DEFAULT, $allow_cid); - if ($result) { - $smallest = 1; - } - } - - if ($width > 320 || $height > 320) { - $image->scaleDown(320); - $result = Photo::store($image, $page_owner_uid, $visitor, $resource_id, $filename, $album, 2, Photo::DEFAULT, $allow_cid); - if ($result && ($smallest == 0)) { - $smallest = 2; - } - } - - $this->logger->info('upload done'); - return $this->return(200, "\n\n" . '[url=' . $this->baseUrl . '/photos/' . $user['nickname'] . '/image/' . $resource_id . '][img]' . $this->baseUrl . "/photo/$resource_id-$smallest." . $image->getExt() . "[/img][/url]\n\n"); - } - - /** - * @param int $httpCode - * @param string $message - * @param bool $systemMessage - * @return void - * @throws InternalServerErrorException - */ - private function return(int $httpCode, string $message, bool $systemMessage = false): void - { - if ($this->isJson) { - $message = $httpCode >= 400 ? ['error' => $message] : ['ok' => true]; - $this->response->setType(Response::TYPE_JSON, 'application/json'); - $this->response->addContent(json_encode($message, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)); - } else { - if ($systemMessage) { - $this->systemMessages->addNotice($message); - } - - if ($httpCode >= 400) { - $this->response->setStatus($httpCode, $message); - } - - $this->response->addContent($message); - } - } -} diff --git a/static/routes.config.php b/static/routes.config.php index 542e31679b..d9e61c63fc 100644 --- a/static/routes.config.php +++ b/static/routes.config.php @@ -31,18 +31,16 @@ use Friendica\App\Router as R; use Friendica\Module; $profileRoutes = [ - '' => [Module\Profile\Index::class, [R::GET]], - '/attachment/upload' => [Module\Profile\Attachment\Upload::class, [ R::POST]], - '/contacts/common' => [Module\Profile\Common::class, [R::GET]], - '/contacts[/{type}]' => [Module\Profile\Contacts::class, [R::GET]], - '/media' => [Module\Profile\Media::class, [R::GET]], - '/photos' => [Module\Profile\Photos\Index::class, [R::GET ]], - '/photos/upload' => [Module\Profile\Photos\Upload::class, [ R::POST]], - '/profile' => [Module\Profile\Profile::class, [R::GET]], - '/remote_follow' => [Module\Profile\RemoteFollow::class, [R::GET, R::POST]], - '/schedule' => [Module\Profile\Schedule::class, [R::GET, R::POST]], - '/status[/{category}[/{date1}[/{date2}]]]' => [Module\Profile\Status::class, [R::GET]], - '/unkmail' => [Module\Profile\UnkMail::class, [R::GET, R::POST]], + '' => [Module\Profile\Index::class, [R::GET]], + '/contacts/common' => [Module\Profile\Common::class, [R::GET]], + '/contacts[/{type}]' => [Module\Profile\Contacts::class, [R::GET]], + '/media' => [Module\Profile\Media::class, [R::GET]], + '/photos' => [Module\Profile\Photos::class, [R::GET ]], + '/profile' => [Module\Profile\Profile::class, [R::GET]], + '/remote_follow' => [Module\Profile\RemoteFollow::class, [R::GET, R::POST]], + '/schedule' => [Module\Profile\Schedule::class, [R::GET, R::POST]], + '/status[/{category}[/{date1}[/{date2}]]]' => [Module\Profile\Status::class, [R::GET]], + '/unkmail' => [Module\Profile\UnkMail::class, [R::GET, R::POST]], ]; $apiRoutes = [ @@ -471,8 +469,10 @@ return [ '/friendica.webmanifest' => [Module\Manifest::class, [R::GET]], '/media' => [ - '/attachment/browser' => [Module\Media\AttachmentBrowser::class, [R::GET]], - '/photos/browser[/{album}]' => [Module\Media\PhotosBrowser::class, [R::GET]], + '/attachment/browser' => [Module\Media\Attachment\Browser::class, [R::GET]], + '/attachment/upload' => [Module\Media\Attachment\Upload::class, [ R::POST]], + '/photo/browser[/{album}]' => [Module\Media\Photo\Browser::class, [R::GET]], + '/photo/upload' => [Module\Media\Photo\Upload::class, [ R::POST]], ], '/moderation' => [ @@ -562,7 +562,7 @@ return [ // Kept for backwards-compatibility // @TODO remove by version 2023.12 - '/photos/{nickname}' => [Module\Profile\Photos\Index::class, [R::GET]], + '/photos/{nickname}' => [Module\Profile\Photos::class, [R::GET]], '/ping' => [Module\Notifications\Ping::class, [R::GET]], diff --git a/view/global.css b/view/global.css index f09d959391..7c0798c21f 100644 --- a/view/global.css +++ b/view/global.css @@ -345,9 +345,9 @@ img.acpopup-img { .fbrowser .path a:before, .fbrowser .path .btn-link:before { content: "/"; padding-right: 5px;} .fbrowser .folders ul { list-style-type: none; padding-left: 10px;} .fbrowser .list { height: auto; overflow-y: hidden; margin: 10px 0px; } -.fbrowser.photos .photo-album-image-wrapper { float: left; } -.fbrowser.photos a img, .fbrowser.photos .btn-link img { height: 48px; } -.fbrowser.photos a p, .fbrowser.photos .btn-link p { display: none;} +.fbrowser.photo .photo-album-image-wrapper { float: left; } +.fbrowser.photo a img, .fbrowser.photo .btn-link img { height: 48px; } +.fbrowser.photo a p, .fbrowser.photo .btn-link p { display: none;} .fbrowser.attachment .photo-album-image-wrapper { float:none; white-space: nowrap; } .fbrowser.attachment img { display: inline; } .fbrowser.attachment p { display: inline; white-space: nowrap; } diff --git a/view/js/main.js b/view/js/main.js index deaa450603..a1446bca5b 100644 --- a/view/js/main.js +++ b/view/js/main.js @@ -166,7 +166,7 @@ $(function() { /* event from comment textarea button popups */ /* insert returned bbcode at cursor position or replace selected text */ - $('body').on('fbrowser.photos.comment', function(e, filename, bbcode, id) { + $('body').on('fbrowser.photo.comment', function(e, filename, bbcode, id) { $.colorbox.close(); var textarea = document.getElementById("comment-edit-text-" +id); var start = textarea.selectionStart; @@ -1069,7 +1069,7 @@ var Dialog = { * to the event handler */ doImageBrowser : function (name, id) { - var url = Dialog._get_url('photos', name, id); + var url = Dialog._get_url('photo', name, id); return Dialog.show(url); }, diff --git a/view/js/media/filebrowser.js b/view/js/media/filebrowser.js index 2239de4f64..5055b1d8e6 100644 --- a/view/js/media/filebrowser.js +++ b/view/js/media/filebrowser.js @@ -84,7 +84,7 @@ const FileBrowser = { e.preventDefault(); let embed = ''; - if (FileBrowser.type === "photos") { + if (FileBrowser.type === "photo") { embed = '[url=' + this.dataset.link + '][img=' + this.dataset.img + ']' + this.dataset.alt + '[/img][/url]'; } if (FileBrowser.type === "attachment") { @@ -99,12 +99,11 @@ const FileBrowser = { }); - if ($('#upload-photos').length) - { + if ($('#upload-photo').length) { new window.AjaxUpload( - 'upload-photos', + 'upload-photo', { - action: 'profile/' + FileBrowser.nickname + '/photos/upload?response=json', + action: 'media/photo/upload?response=json', name: 'userfile', responseType: 'json', onSubmit: function (file, ext) { @@ -125,12 +124,11 @@ const FileBrowser = { ); } - if ($('#upload-attachment').length) - { + if ($('#upload-attachment').length) { new window.AjaxUpload( 'upload-attachment', { - action: 'profile/' + FileBrowser.nickname + '/attachment/upload?response=json', + action: 'media/attachment/upload?response=json', name: 'userfile', responseType: 'json', onSubmit: function (file, ext) { @@ -148,8 +146,8 @@ const FileBrowser = { location.reload(); } } - ); - } + ); + } }, _getUrl: function (mode, hash, folder) { diff --git a/view/templates/jot-header.tpl b/view/templates/jot-header.tpl index 2a81db6dd1..808d511262 100644 --- a/view/templates/jot-header.tpl +++ b/view/templates/jot-header.tpl @@ -61,11 +61,11 @@ function enableOnUser(){ **/ /* callback */ - $('body').on('fbrowser.photos.main', function(e, filename, embedcode, id) { + $('body').on('fbrowser.photo.main', function(e, filename, embedcode, id) { $.colorbox.close(); addeditortext(embedcode); }); - $('body').on('fbrowser.photos.main', function(e, filename, embedcode, id) { + $('body').on('fbrowser.attachment.main', function(e, filename, embedcode, id) { $.colorbox.close(); addeditortext(embedcode); }); diff --git a/view/theme/frio/css/style.css b/view/theme/frio/css/style.css index 0e54d1cf97..eecb0b242d 100644 --- a/view/theme/frio/css/style.css +++ b/view/theme/frio/css/style.css @@ -1563,10 +1563,10 @@ textarea.comment-edit-text:focus + .comment-edit-form .preview { max-height: calc(100vh - 220px); } } -.fbrowser.photos .photo-album-image-wrapper { +.fbrowser.photo .photo-album-image-wrapper { box-shadow: 2px 2px 5px 0px rgba(0, 0, 0, 0.2); } -.fbrowser.photos .photo-album-image-wrapper .caption { +.fbrowser.photo .photo-album-image-wrapper .caption { pointer-events: none; } .fbrowser .profile-rotator-wrapper { diff --git a/view/theme/frio/js/modal.js b/view/theme/frio/js/modal.js index d54a33e188..ed256450cc 100644 --- a/view/theme/frio/js/modal.js +++ b/view/theme/frio/js/modal.js @@ -82,7 +82,7 @@ $(document).ready(function () { }); // Insert filebrowser images into the input field (field_fileinput.tpl). - $("body").on("fbrowser.photos.input", function (e, filename, embedcode, id, img) { + $("body").on("fbrowser.photo.input", function (e, filename, embedcode, id, img) { // Select the clicked button by it's attribute. var elm = $("[image-input='select']"); // Select the input field which belongs to this button. @@ -137,7 +137,7 @@ Dialog._get_url = function (type, name, id) { // Does load the filebrowser into the jot modal. Dialog.showJot = function () { - var type = "photos"; + var type = "photo"; var name = "main"; var url = Dialog._get_url(type, name); diff --git a/view/theme/frio/js/module/media/filebrowser.js b/view/theme/frio/js/module/media/filebrowser.js index 123861c4da..802c440989 100644 --- a/view/theme/frio/js/module/media/filebrowser.js +++ b/view/theme/frio/js/module/media/filebrowser.js @@ -109,7 +109,7 @@ var FileBrowser = { e.preventDefault(); let embed = ''; - if (FileBrowser.type === 'photos') { + if (FileBrowser.type === 'photo') { embed = '[url=' + this.dataset.link + '][img=' + this.dataset.img + ']' + this.dataset.alt + '[/img][/url]'; } if (FileBrowser.type === 'attachment') { @@ -155,12 +155,12 @@ var FileBrowser = { // Initialize the AjaxUpload for the upload buttons uploadButtons: function () { - if ($('#upload-photos').length) { + if ($('#upload-photo').length) { //AjaxUpload for photos new window.AjaxUpload( - 'upload-photos', + 'upload-photo', { - action: 'profile/' + FileBrowser.nickname + '/photos/upload?response=json&album=' + encodeURIComponent(FileBrowser.folder), + action: 'media/photo/upload?response=json&album=' + encodeURIComponent(FileBrowser.folder), name: 'userfile', responseType: 'json', onSubmit: function (file, ext) { @@ -187,7 +187,7 @@ var FileBrowser = { new window.AjaxUpload( 'upload-attachment', { - action: 'profile/' + FileBrowser.nickname + '/attachment/upload?response=json', + action: 'media/attachment/upload?response=json', name: 'userfile', responseType: 'json', onSubmit: function (file, ext) { @@ -236,7 +236,7 @@ var FileBrowser = { // Initialize justified Gallery initGallery: function () { - $('.fbrowser.photos .fbrowser-content-container').justifiedGallery({ + $('.fbrowser.photo .fbrowser-content-container').justifiedGallery({ rowHeight: 80, margins: 4, border: 0, diff --git a/view/theme/frio/templates/jot-header.tpl b/view/theme/frio/templates/jot-header.tpl index 61f92ff73c..9ac56d27d5 100644 --- a/view/theme/frio/templates/jot-header.tpl +++ b/view/theme/frio/templates/jot-header.tpl @@ -61,7 +61,7 @@ **/ /* callback */ - $('body').on('fbrowser.photos.main', function(e, filename, embedcode, id) { + $('body').on('fbrowser.photo.main', function(e, filename, embedcode, id) { ///@todo this part isn't ideal and need to be done in a better way jotTextOpenUI(document.getElementById("profile-jot-text")); jotActive(); diff --git a/view/theme/frio/templates/media/filebrowser.tpl b/view/theme/frio/templates/media/filebrowser.tpl index 7b24537cee..71974eeea8 100644 --- a/view/theme/frio/templates/media/filebrowser.tpl +++ b/view/theme/frio/templates/media/filebrowser.tpl @@ -17,7 +17,7 @@ {{* Switch between image and file mode *}}
- +
diff --git a/view/theme/quattro/dark/style.css b/view/theme/quattro/dark/style.css index 30271c49b2..2b29887b29 100644 --- a/view/theme/quattro/dark/style.css +++ b/view/theme/quattro/dark/style.css @@ -2517,15 +2517,15 @@ footer { .fbrowser .list { padding: 10px; } -.fbrowser.photos .photo-album-image-wrapper { +.fbrowser.photo .photo-album-image-wrapper { width: 48px; height: 48px; } -.fbrowser.photos a img { +.fbrowser.photo a img { width: auto; height: 48px; } -.fbrowser.photos a p { +.fbrowser.photo a p { display: none; } .fbrowser.attachment .photo-album-image-wrapper { diff --git a/view/theme/quattro/green/style.css b/view/theme/quattro/green/style.css index 574f9c5318..5e9770543b 100644 --- a/view/theme/quattro/green/style.css +++ b/view/theme/quattro/green/style.css @@ -2516,15 +2516,15 @@ footer { .fbrowser .list { padding: 10px; } -.fbrowser.photos .photo-album-image-wrapper { +.fbrowser.photo .photo-album-image-wrapper { width: 48px; height: 48px; } -.fbrowser.photos a img { +.fbrowser.photo a img { width: auto; height: 48px; } -.fbrowser.photos a p { +.fbrowser.photo a p { display: none; } .fbrowser.attachment .photo-album-image-wrapper { diff --git a/view/theme/quattro/lilac/style.css b/view/theme/quattro/lilac/style.css index 6a4afb89ce..b8b66ff327 100644 --- a/view/theme/quattro/lilac/style.css +++ b/view/theme/quattro/lilac/style.css @@ -2516,15 +2516,15 @@ footer { .fbrowser .list { padding: 10px; } -.fbrowser.photos .photo-album-image-wrapper { +.fbrowser.photo .photo-album-image-wrapper { width: 48px; height: 48px; } -.fbrowser.photos a img { +.fbrowser.photo a img { width: auto; height: 48px; } -.fbrowser.photos a p { +.fbrowser.photo a p { display: none; } .fbrowser.attachment .photo-album-image-wrapper { diff --git a/view/theme/quattro/quattro.less b/view/theme/quattro/quattro.less index e6a953e483..8163e14ba8 100644 --- a/view/theme/quattro/quattro.less +++ b/view/theme/quattro/quattro.less @@ -1673,9 +1673,9 @@ footer { height: 100px; display: table-row; } } .fbrowser .folders ul { list-style: url("icons/folder.png"); padding-left: 22px;} .fbrowser .list { padding: 10px; } -.fbrowser.photos .photo-album-image-wrapper { width: 48px; height: 48px; } -.fbrowser.photos a img { width: auto; height: 48px; } -.fbrowser.photos a p { display: none;} +.fbrowser.photo .photo-album-image-wrapper { width: 48px; height: 48px; } +.fbrowser.photo a img { width: auto; height: 48px; } +.fbrowser.photo a p { display: none;} .fbrowser.attachment .photo-album-image-wrapper { float:none; white-space: nowrap; width: 100%; height: auto; } .fbrowser.attachment img { display: inline; width: 16px; height: 16px} .fbrowser.attachment p { display: inline; white-space: nowrap; } diff --git a/view/theme/vier/style.css b/view/theme/vier/style.css index c156534d31..b574a9f3e7 100644 --- a/view/theme/vier/style.css +++ b/view/theme/vier/style.css @@ -3261,7 +3261,7 @@ img.photo-album-photo { } /* upload/select popup */ -fbrowser.photos .photo-album-image-wrapper { margin-left: 10px; } +fbrowser.photo .photo-album-image-wrapper { margin-left: 10px; } #message-preview { margin-top: 15px; } #message-preview span { width: 100%; } #message-preview .mail-count, #message-preview .mail-delete { display:none; }