From d0b16b2fc15ac2b3d5db65586a7a94fda8f7224c Mon Sep 17 00:00:00 2001 From: Philipp Date: Fri, 25 Nov 2022 23:43:07 +0100 Subject: [PATCH 01/40] Move mod/fbrowser to src\Modules\Attachment|Photos\Browser --- src/App/Arguments.php | 2 + src/App/Page.php | 1 + src/App/Router.php | 2 +- src/Model/Photo.php | 53 ++++ src/Module/Attach.php | 1 - src/Module/Profile/Attachment/Browser.php | 81 +++++++ src/Module/Profile/Photos/Browser.php | 105 ++++++++ static/routes.config.php | 26 +- view/global.css | 12 +- view/js/filebrowser.js | 113 +++++---- view/js/main.js | 8 +- view/templates/jot-header.tpl | 4 +- view/templates/{ => profile}/filebrowser.tpl | 6 +- view/theme/frio/css/style.css | 4 +- view/theme/frio/js/filebrowser.js | 229 +++++++++--------- view/theme/frio/js/modal.js | 8 +- view/theme/frio/templates/jot-header.tpl | 4 +- view/theme/frio/templates/js_strings.tpl | 1 + .../templates/{ => profile}/filebrowser.tpl | 6 +- view/theme/quattro/dark/style.css | 12 +- view/theme/quattro/green/style.css | 12 +- view/theme/quattro/lilac/style.css | 12 +- view/theme/quattro/quattro.less | 12 +- view/theme/vier/style.css | 2 +- 24 files changed, 483 insertions(+), 233 deletions(-) create mode 100644 src/Module/Profile/Attachment/Browser.php create mode 100644 src/Module/Profile/Photos/Browser.php rename view/templates/{ => profile}/filebrowser.tpl (80%) rename view/theme/frio/templates/{ => profile}/filebrowser.tpl (85%) diff --git a/src/App/Arguments.php b/src/App/Arguments.php index 6dfdcb560f..5d30f9bd2b 100644 --- a/src/App/Arguments.php +++ b/src/App/Arguments.php @@ -85,6 +85,8 @@ class Arguments /** * @return string The module name based on the arguments + * @deprecated 2022.12 - With the new (sub-)routes, it's no more trustworthy, use the ModuleClass instead + * @see Router::getModuleClass() */ public function getModuleName(): string { diff --git a/src/App/Page.php b/src/App/Page.php index 37141426c3..afc94fbdf0 100644 --- a/src/App/Page.php +++ b/src/App/Page.php @@ -241,6 +241,7 @@ class Page implements ArrayAccess * being first */ $this->page['htmlhead'] = Renderer::replaceMacros($tpl, [ + '$local_nickname' => $app->getLoggedInUserNickname(), '$local_user' => $localUID, '$generator' => 'Friendica' . ' ' . App::VERSION, '$delitem' => $l10n->t('Delete this item?'), diff --git a/src/App/Router.php b/src/App/Router.php index 4e5f29521a..b6fd1098f5 100644 --- a/src/App/Router.php +++ b/src/App/Router.php @@ -266,7 +266,7 @@ class Router * @throws HTTPException\MethodNotAllowedException If a rule matched but the method didn't * @throws HTTPException\NotFoundException If no rule matched */ - private function getModuleClass(): string + public function getModuleClass(): string { $cmd = $this->args->getCommand(); $cmd = '/' . ltrim($cmd, '/'); diff --git a/src/Model/Photo.php b/src/Model/Photo.php index 7c620b0ad4..a139ba715f 100644 --- a/src/Model/Photo.php +++ b/src/Model/Photo.php @@ -173,6 +173,59 @@ class Photo return $photo; } + /** + * Returns all browsable albums for a given user + * + * @param int $uid The given user + * + * @return array An array of albums + * @throws \Exception + */ + public static function getBrowsableAlbumsForUser(int $uid): array + { + $photos = DBA::toArray( + DBA::p( + "SELECT DISTINCT(`album`) AS `albume` FROM `photo` WHERE `uid` = ? AND NOT `photo-type` IN (?, ?)", + $uid, + static::CONTACT_AVATAR, + static::CONTACT_BANNER + ) + ); + + return array_column($photos, 'album'); + } + + /** + * Returns browsable photos for a given user (optional and a given album) + * + * @param int $uid The given user id + * @param string|null $album (optional) The given album + * + * @return array All photos of the user/album + * @throws \Exception + */ + public static function getBrowsablePhotosForUser(int $uid, string $album = null): array + { + if (!empty($album)) { + $sqlExtra = sprintf("AND `album` = '%S' ", DBA::escape($album)); + $sqlExtra2 = ""; + } else { + $sqlExtra = ''; + $sqlExtra2 = ' ORDER BY created DESC LIMIT 0, 10'; + } + + return DBA::toArray( + DBA::p( + "SELECT `resource-id`, ANY_VALUE(`id`) AS `id`, ANY_VALUE(`filename`) AS `filename`, ANY_VALUE(`type`) AS `type`, + min(`scale`) AS `hiq`, max(`scale`) AS `loq`, ANY_VALUE(`desc`) AS `desc`, ANY_VALUE(`created`) AS `created` + FROM `photo` WHERE `uid` = ? $sqlExtra AND NOT `photo-type` IN (?, ?) + GROUP BY `resource-id` $sqlExtra2", + $uid, + Photo::CONTACT_AVATAR, + Photo::CONTACT_BANNER + )); + } + /** * Check if photo with given conditions exists * diff --git a/src/Module/Attach.php b/src/Module/Attach.php index a73beb2b8d..17b2d6e908 100644 --- a/src/Module/Attach.php +++ b/src/Module/Attach.php @@ -37,7 +37,6 @@ class Attach extends BaseModule */ protected function rawContent(array $request = []) { - $a = DI::app(); if (empty($this->parameters['item'])) { throw new \Friendica\Network\HTTPException\BadRequestException(); } diff --git a/src/Module/Profile/Attachment/Browser.php b/src/Module/Profile/Attachment/Browser.php new file mode 100644 index 0000000000..09429bff85 --- /dev/null +++ b/src/Module/Profile/Attachment/Browser.php @@ -0,0 +1,81 @@ +session = $session; + $this->app = $app; + } + + protected function content(array $request = []): string + { + if (!$this->session->getLocalUserId()) { + $this->baseUrl->redirect(); + } + + // 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('profile/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 : 'zip'); + + 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/Profile/Photos/Browser.php b/src/Module/Profile/Photos/Browser.php new file mode 100644 index 0000000000..1e8a28b123 --- /dev/null +++ b/src/Module/Profile/Photos/Browser.php @@ -0,0 +1,105 @@ +session = $session; + $this->app = $app; + } + + protected function content(array $request = []): string + { + if (!$this->session->getLocalUserId()) { + $this->baseUrl->redirect(); + } + + // 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('profile/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/static/routes.config.php b/static/routes.config.php index ae57557117..794f705e40 100644 --- a/static/routes.config.php +++ b/static/routes.config.php @@ -31,18 +31,20 @@ 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]], + '/attachment/upload' => [Module\Profile\Attachment\Upload::class, [ R::POST]], + '/attachment/browser' => [Module\Profile\Attachment\Browser::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\Index::class, [R::GET ]], + '/photos/browser[/{album}]' => [Module\Profile\Photos\Browser::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]], ]; $apiRoutes = [ diff --git a/view/global.css b/view/global.css index 800a3ea34d..f09d959391 100644 --- a/view/global.css +++ b/view/global.css @@ -345,12 +345,12 @@ 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.image .photo-album-image-wrapper { float: left; } -.fbrowser.image a img, .fbrowser.image .btn-link img { height: 48px; } -.fbrowser.image a p, .fbrowser.image .btn-link p { display: none;} -.fbrowser.file .photo-album-image-wrapper { float:none; white-space: nowrap; } -.fbrowser.file img { display: inline; } -.fbrowser.file p { display: inline; white-space: nowrap; } +.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.attachment .photo-album-image-wrapper { float:none; white-space: nowrap; } +.fbrowser.attachment img { display: inline; } +.fbrowser.attachment p { display: inline; white-space: nowrap; } .fbrowser .upload { clear: both; padding-top: 1em;} .fbrowser .error { background: #ffeeee; border: 1px solid #994444; color: #994444; padding: 0.5em;} .fbrowser .error .close { float: right; font-weight: bold; } diff --git a/view/js/filebrowser.js b/view/js/filebrowser.js index e5bd2730c4..1b8a4d51fb 100644 --- a/view/js/filebrowser.js +++ b/view/js/filebrowser.js @@ -33,7 +33,7 @@ * will be one of "image" or "file", and the event handler will * get the following params: * - * filemane: filename of item choosed by user + * filename: filename of item chosen by user * embed: bbcode to embed element into posts * id: id from caller code * @@ -47,52 +47,51 @@ * $("body").on("fbrowser.image.example", function(event, filename, bbcode, id) { * // close colorbox * $.colorbox.close(); - * // replace textxarea text with bbcode + * // replace textarea text with bbcode * $(id).value = bbcode; * }); **/ +const FileBrowser = { + nickname: '', + type: '', + event: '', + id: null, -var FileBrowser = { - nickname : "", - type : "", - event: "", - id : null, - - init: function(nickname, type) { + init: function (nickname, type) { FileBrowser.nickname = nickname; FileBrowser.type = type; - FileBrowser.event = "fbrowser."+type; - if (location['hash']!=="") { - var h = location['hash'].replace("#",""); + FileBrowser.event = "fbrowser." + type; + if (location['hash'] !== "") { + const h = location['hash'].replace('#', ''); FileBrowser.event = FileBrowser.event + "." + h.split("-")[0]; FileBrowser.id = h.split("-")[1]; } - console.log("FileBrowser:", nickname, type,FileBrowser.event, FileBrowser.id ); + console.log('FileBrowser:', nickname, type, FileBrowser.event, FileBrowser.id); - $(".error a.close").on("click", function(e) { + $('.error a.close').on('click', function (e) { e.preventDefault(); - $(".error").addClass("hidden"); + $('.error').addClass('hidden'); }); - $(".folders a, .path a").on("click", function(e){ + $('.folders a, .path a').on('click', function (e) { e.preventDefault(); - location.href = baseurl + "/fbrowser/" + FileBrowser.type + "/" + encodeURIComponent(this.dataset.folder) + "?mode=minimal" + location['hash']; + location.href = FileBrowser._getUrl("minimal", location['hash'], this.dataset.folder); + location.reload(); }); - $(".photo-album-photo-link").on('click', function(e){ + $(".photo-album-photo-link").on('click', function (e) { e.preventDefault(); - var embed = ""; - if (FileBrowser.type == "image") { - embed = "[url="+this.dataset.link+"][img="+this.dataset.img+"]"+this.dataset.alt+"[/img][/url]"; + let embed = ''; + if (FileBrowser.type === "photos") { + embed = '[url=' + this.dataset.link + '][img=' + this.dataset.img + ']' + this.dataset.alt + '[/img][/url]'; } - if (FileBrowser.type=="file") { - // attachment links are "baseurl/attach/id"; we need id - embed = "[attachment]"+this.dataset.link.split("/").pop()+"[/attachment]"; + if (FileBrowser.type === "attachment") { + embed = '[attachment]' + this.dataset.link + '[/attachment]'; } console.log(FileBrowser.event, this.dataset.filename, embed, FileBrowser.id); - parent.$("body").trigger(FileBrowser.event, [ + parent.$('body').trigger(FileBrowser.event, [ this.dataset.filename, embed, FileBrowser.id @@ -100,45 +99,63 @@ var FileBrowser = { }); - if ($("#upload-image").length) - var image_uploader = new window.AjaxUpload( - 'upload-image', - { action: 'profile/' + FileBrowser.nickname + '/photos/upload?response=json', + if ($('#upload-photos').length) + { + new window.AjaxUpload( + 'upload-photos', + { + action: 'profile/' + FileBrowser.nickname + '/photos/upload?response=json', name: 'userfile', responseType: 'json', - onSubmit: function(file,ext) { $('#profile-rotator').show(); $(".error").addClass('hidden'); }, - onComplete: function(file,response) { - if (response['error']!= undefined) { - $(".error span").html(response['error']); - $(".error").removeClass('hidden'); + onSubmit: function (file, ext) { + $('#profile-rotator').show(); + $('.error').addClass('hidden'); + }, + onComplete: function (file, response) { + if (response['error'] !== undefined) { + $('.error span').html(response['error']); + $('.error').removeClass('hidden'); $('#profile-rotator').hide(); return; } - location = baseurl + "/fbrowser/image/?mode=minimal"+location['hash']; - location.reload(true); + location.href = FileBrowser._getUrl("minimal", location['hash']); + location.reload(); } } ); + } - if ($("#upload-file").length) - var file_uploader = new window.AjaxUpload( - 'upload-file', - { action: 'profile/' + FileBrowser.nickname + '/attachment/upload?response=json', + if ($('#upload-attachment').length) + { + new window.AjaxUpload( + 'upload-attachment', + { + action: 'profile/' + FileBrowser.nickname + '/attachment/upload?response=json', name: 'userfile', responseType: 'json', - onSubmit: function(file,ext) { $('#profile-rotator').show(); $(".error").addClass('hidden'); }, - onComplete: function(file,response) { - if (response['error']!= undefined) { - $(".error span").html(response['error']); - $(".error").removeClass('hidden'); + onSubmit: function (file, ext) { + $('#profile-rotator').show(); + $('.error').addClass('hidden'); + }, + onComplete: function (file, response) { + if (response['error'] !== undefined) { + $('.error span').html(response['error']); + $('.error').removeClass('hidden'); $('#profile-rotator').hide(); return; } - location = baseurl + "/fbrowser/file/?mode=minimal"+location['hash']; - location.reload(true); + location.href = FileBrowser._getUrl("minimal", location['hash']); + location.reload(); } } - ); + ); + } + }, + + _getUrl: function (mode, hash, folder) { + let folderValue = folder !== undefined ? folder : FileBrowser.folder; + let folderUrl = folderValue !== undefined ? '/' + encodeURIComponent(folderValue) : ''; + return 'profile/' + FileBrowser.nickname + '/' + FileBrowser.type + '/browser' + folderUrl + '?mode=' + mode + hash; } }; // @license-end diff --git a/view/js/main.js b/view/js/main.js index 93340dc37f..3ba8240fed 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.image.comment", function(e, filename, bbcode, id) { + $("body").on("fbrowser.photos.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("image",name,id); + var url = Dialog._get_url("photos",name,id); return Dialog.show(url); }, @@ -1086,7 +1086,7 @@ var Dialog = { * to the event handler */ doFileBrowser : function (name, id) { - var url = Dialog._get_url("file",name,id); + var url = Dialog._get_url("attachment",name,id); return Dialog.show(url); }, @@ -1095,7 +1095,7 @@ var Dialog = { if (id !== undefined) { hash = hash + "-" + id; } - return baseurl + "/fbrowser/"+type+"/?mode=minimal#"+hash; + return '/profile/' + localNickname + '/' + type + '/browser?mode=minimal#' + hash; }, _get_size: function() { diff --git a/view/templates/jot-header.tpl b/view/templates/jot-header.tpl index a67f9c3f0c..2a81db6dd1 100644 --- a/view/templates/jot-header.tpl +++ b/view/templates/jot-header.tpl @@ -61,11 +61,11 @@ function enableOnUser(){ **/ /* callback */ - $('body').on('fbrowser.image.main', function(e, filename, embedcode, id) { + $('body').on('fbrowser.photos.main', function(e, filename, embedcode, id) { $.colorbox.close(); addeditortext(embedcode); }); - $('body').on('fbrowser.file.main', function(e, filename, embedcode, id) { + $('body').on('fbrowser.photos.main', function(e, filename, embedcode, id) { $.colorbox.close(); addeditortext(embedcode); }); diff --git a/view/templates/filebrowser.tpl b/view/templates/profile/filebrowser.tpl similarity index 80% rename from view/templates/filebrowser.tpl rename to view/templates/profile/filebrowser.tpl index 09bf563ee7..ff25741a9b 100644 --- a/view/templates/filebrowser.tpl +++ b/view/templates/profile/filebrowser.tpl @@ -1,8 +1,8 @@ - - + + - + - +
diff --git a/view/theme/frio/js/modal.js b/view/theme/frio/js/modal.js index ed256450cc..c3c4009b05 100644 --- a/view/theme/frio/js/modal.js +++ b/view/theme/frio/js/modal.js @@ -166,8 +166,8 @@ Dialog._load = function (url) { // Initialize the filebrowser. loadScript("view/js/ajaxupload.js"); - loadScript("view/theme/frio/js/module/media/filebrowser.js", function () { - FileBrowser.init(filebrowser.dataset.nickname, filebrowser.dataset.type, match[1]); + loadScript("view/theme/frio/js/module/media/browser.js", function () { + Browser.init(filebrowser.dataset.nickname, filebrowser.dataset.type, match[1]); }); }; diff --git a/view/theme/frio/js/module/media/filebrowser.js b/view/theme/frio/js/module/media/browser.js similarity index 78% rename from view/theme/frio/js/module/media/filebrowser.js rename to view/theme/frio/js/module/media/browser.js index 802c440989..c89f426ebd 100644 --- a/view/theme/frio/js/module/media/filebrowser.js +++ b/view/theme/frio/js/module/media/browser.js @@ -59,11 +59,11 @@ * the frio theme.and bootstrap modals * * The original file is under: - * js/filebrowser.js + * js/module/media/browser.js * */ -var FileBrowser = { +var Browser = { nickname: '', type: '', event: '', @@ -71,24 +71,24 @@ var FileBrowser = { id: null, init: function (nickname, type, hash) { - FileBrowser.nickname = nickname; - FileBrowser.type = type; - FileBrowser.event = 'fbrowser.' + type; + Browser.nickname = nickname; + Browser.type = type; + Browser.event = 'fbrowser.' + type; if (hash !== '') { const h = hash.replace('#', ''); const destination = h.split('-')[0]; - FileBrowser.id = h.split('-')[1]; - FileBrowser.event = FileBrowser.event + '.' + destination; + Browser.id = h.split('-')[1]; + Browser.event = Browser.event + '.' + destination; if (destination === 'comment') { // Get the comment textinput field - var commentElm = document.getElementById('comment-edit-text-' + FileBrowser.id); + var commentElm = document.getElementById('comment-edit-text-' + Browser.id); } } - console.log('FileBrowser: ' + nickname, type, FileBrowser.event, FileBrowser.id); + console.log('FileBrowser: ' + nickname, type, Browser.event, Browser.id); - FileBrowser.postLoad(); + Browser.postLoad(); $('.error .close').on('click', function (e) { e.preventDefault(); @@ -98,10 +98,10 @@ var FileBrowser = { // Click on album link $('.fbrowser').on('click', '.folders button, .path button', function (e) { e.preventDefault(); - let url = FileBrowser._getUrl("none", this.dataset.folder); - FileBrowser.folder = this.dataset.folder; + let url = Browser._getUrl("none", this.dataset.folder); + Browser.folder = this.dataset.folder; - FileBrowser.loadContent(url); + Browser.loadContent(url); }); //Embed on click @@ -109,10 +109,10 @@ var FileBrowser = { e.preventDefault(); let embed = ''; - if (FileBrowser.type === 'photo') { + if (Browser.type === 'photo') { embed = '[url=' + this.dataset.link + '][img=' + this.dataset.img + ']' + this.dataset.alt + '[/img][/url]'; } - if (FileBrowser.type === 'attachment') { + if (Browser.type === 'attachment') { embed = '[attachment]' + this.dataset.link + '[/attachment]'; } @@ -122,18 +122,18 @@ var FileBrowser = { // As for now we insert pieces of this function here if (commentElm !== null && typeof commentElm !== 'undefined') { if (commentElm.value === '') { - $('#comment-edit-text-' + FileBrowser.id) + $('#comment-edit-text-' + Browser.id) .addClass('comment-edit-text-full') .removeClass('comment-edit-text-empty'); - $('#comment-edit-submit-wrapper-' + FileBrowser.id).show(); - $('#comment-edit-text-' + FileBrowser.id).attr('tabindex', '9'); - $('#comment-edit-submit-' + FileBrowser.id).attr('tabindex', '10'); + $('#comment-edit-submit-wrapper-' + Browser.id).show(); + $('#comment-edit-text-' + Browser.id).attr('tabindex', '9'); + $('#comment-edit-submit-' + Browser.id).attr('tabindex', '10'); } } - console.log(FileBrowser.event, this.dataset.filename, embed, FileBrowser.id); + console.log(Browser.event, this.dataset.filename, embed, Browser.id); - $('body').trigger(FileBrowser.event, [this.dataset.filename, embed, FileBrowser.id, this.dataset.img]); + $('body').trigger(Browser.event, [this.dataset.filename, embed, Browser.id, this.dataset.img]); // Close model $('#modal').modal('hide'); @@ -144,12 +144,12 @@ var FileBrowser = { // EventListener for switching between photo and file mode $('.fbrowser').on('click', '.fbswitcher .btn', function (e) { e.preventDefault(); - FileBrowser.type = this.getAttribute('data-mode'); + Browser.type = this.getAttribute('data-mode'); $('.fbrowser') .removeClass() - .addClass('fbrowser ' + FileBrowser.type); + .addClass('fbrowser ' + Browser.type); - FileBrowser.loadContent(FileBrowser._getUrl("none")); + Browser.loadContent(Browser._getUrl("none")); }); }, @@ -160,7 +160,7 @@ var FileBrowser = { new window.AjaxUpload( 'upload-photo', { - action: 'media/photo/upload?response=json&album=' + encodeURIComponent(FileBrowser.folder), + action: 'media/photo/upload?response=json&album=' + encodeURIComponent(Browser.folder), name: 'userfile', responseType: 'json', onSubmit: function (file, ext) { @@ -177,7 +177,7 @@ var FileBrowser = { return; } // load new content to fbrowser window - FileBrowser.loadContent(FileBrowser._getUrl("none")); + Browser.loadContent(Browser._getUrl("none")); }, }); } @@ -204,7 +204,7 @@ var FileBrowser = { return; } // Load new content to fbrowser window - FileBrowser.loadContent(FileBrowser._getUrl("none")); + Browser.loadContent(Browser._getUrl("none")); }, }); } @@ -212,11 +212,11 @@ var FileBrowser = { // Stuff which should be executed if no content was loaded postLoad: function () { - FileBrowser.initGallery(); + Browser.initGallery(); $('.fbrowser .fbswitcher .btn').removeClass('active'); - $('.fbrowser .fbswitcher [data-mode=' + FileBrowser.type + ']').addClass('active'); + $('.fbrowser .fbswitcher [data-mode=' + Browser.type + ']').addClass('active'); // We need to add the AjaxUpload to the button - FileBrowser.uploadButtons(); + Browser.uploadButtons(); }, // Load new content (e.g. change photo album) @@ -229,7 +229,7 @@ var FileBrowser = { $('.profile-rotator-wrapper').hide(); if (textStatus === 'success') { $(".fbrowser_content").show(); - FileBrowser.postLoad(); + Browser.postLoad(); } }); }, @@ -244,9 +244,9 @@ var FileBrowser = { }, _getUrl: function (mode, folder) { - let folderValue = folder !== undefined ? folder : FileBrowser.folder; + let folderValue = folder !== undefined ? folder : Browser.folder; let folderUrl = folderValue !== undefined ? '/' + encodeURIComponent(folderValue) : ''; - return 'media/' + FileBrowser.type + '/browser' + folderUrl + '?mode=' + mode + "&theme=frio"; + return 'media/' + Browser.type + '/browser' + folderUrl + '?mode=' + mode + "&theme=frio"; } }; // @license-end diff --git a/view/theme/frio/templates/media/filebrowser.tpl b/view/theme/frio/templates/media/browser.tpl similarity index 100% rename from view/theme/frio/templates/media/filebrowser.tpl rename to view/theme/frio/templates/media/browser.tpl From 29190fae73e6b9cf7a4dbca47263bcc1da431628 Mon Sep 17 00:00:00 2001 From: Philipp Date: Sun, 27 Nov 2022 01:36:31 +0100 Subject: [PATCH 11/40] Update messages.po --- src/Module/Media/Attachment/Browser.php | 2 +- view/lang/C/messages.po | 155 ++++++++++++------------ 2 files changed, 80 insertions(+), 77 deletions(-) diff --git a/src/Module/Media/Attachment/Browser.php b/src/Module/Media/Attachment/Browser.php index de9f7f4fc9..ed9ae74a3f 100644 --- a/src/Module/Media/Attachment/Browser.php +++ b/src/Module/Media/Attachment/Browser.php @@ -89,7 +89,7 @@ class Browser extends BaseModule protected function map_files(array $record): array { - [$m1, $m2] = explode('/', $record['filetype']); + list($m1, $m2) = explode('/', $record['filetype']); $filetype = file_exists(sprintf('images/icons/%s.png', $m1) ? $m1 : 'text'); return [ diff --git a/view/lang/C/messages.po b/view/lang/C/messages.po index 14ac264f17..b9115ad4fe 100644 --- a/view/lang/C/messages.po +++ b/view/lang/C/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 2022.12-dev\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-11-23 18:16+0100\n" +"POT-Creation-Date: 2022-11-27 00:36+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,36 +18,13 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" -#: mod/fbrowser.php:61 src/Content/Nav.php:195 src/Module/BaseProfile.php:64 -#: view/theme/frio/theme.php:242 -msgid "Photos" -msgstr "" - -#: mod/fbrowser.php:119 mod/fbrowser.php:146 mod/photos.php:997 -#: mod/photos.php:1098 src/Content/Conversation.php:389 -#: src/Module/Contact/Follow.php:173 src/Module/Contact/Revoke.php:109 -#: src/Module/Contact/Unfollow.php:126 src/Module/Post/Edit.php:164 -#: src/Module/Post/Tag/Remove.php:109 src/Module/Profile/RemoteFollow.php:134 -#: src/Module/Security/TwoFactor/SignOut.php:125 -msgid "Cancel" -msgstr "" - -#: mod/fbrowser.php:121 mod/fbrowser.php:148 -#: src/Module/Settings/Profile/Photo/Index.php:128 -msgid "Upload" -msgstr "" - -#: mod/fbrowser.php:143 -msgid "Files" -msgstr "" - #: mod/item.php:129 mod/item.php:133 msgid "Unable to locate original post." msgstr "" -#: mod/item.php:179 mod/item.php:184 mod/item.php:853 mod/message.php:69 +#: mod/item.php:179 mod/item.php:184 mod/item.php:855 mod/message.php:69 #: mod/message.php:114 mod/notes.php:44 mod/photos.php:159 mod/photos.php:884 -#: src/Module/Attach.php:56 src/Module/BaseApi.php:94 +#: src/Module/Attach.php:55 src/Module/BaseApi.php:94 #: src/Module/BaseNotifications.php:98 src/Module/BaseSettings.php:52 #: src/Module/Calendar/Event/API.php:88 src/Module/Calendar/Event/Form.php:84 #: src/Module/Calendar/Event/Show.php:54 src/Module/Calendar/Export.php:62 @@ -62,9 +39,8 @@ msgstr "" #: src/Module/Notifications/Notification.php:76 #: src/Module/Notifications/Notification.php:107 #: src/Module/OStatus/Repair.php:60 src/Module/OStatus/Subscribe.php:66 -#: src/Module/Post/Edit.php:76 src/Module/Profile/Attachment/Upload.php:97 -#: src/Module/Profile/Common.php:55 src/Module/Profile/Contacts.php:55 -#: src/Module/Profile/Photos/Upload.php:108 src/Module/Profile/Schedule.php:39 +#: src/Module/Post/Edit.php:76 src/Module/Profile/Common.php:55 +#: src/Module/Profile/Contacts.php:55 src/Module/Profile/Schedule.php:39 #: src/Module/Profile/Schedule.php:56 src/Module/Profile/UnkMail.php:69 #: src/Module/Profile/UnkMail.php:121 src/Module/Profile/UnkMail.php:132 #: src/Module/Register.php:77 src/Module/Register.php:90 @@ -84,23 +60,23 @@ msgstr "" msgid "Permission denied." msgstr "" -#: mod/item.php:328 mod/item.php:333 +#: mod/item.php:330 mod/item.php:335 msgid "Empty post discarded." msgstr "" -#: mod/item.php:671 +#: mod/item.php:673 msgid "Post updated." msgstr "" -#: mod/item.php:681 mod/item.php:686 +#: mod/item.php:683 mod/item.php:688 msgid "Item wasn't stored." msgstr "" -#: mod/item.php:697 +#: mod/item.php:699 msgid "Item couldn't be fetched." msgstr "" -#: mod/item.php:829 src/Module/Admin/Themes/Details.php:39 +#: mod/item.php:831 src/Module/Admin/Themes/Details.php:39 #: src/Module/Admin/Themes/Index.php:59 src/Module/Debug/ItemBody.php:42 #: src/Module/Debug/ItemBody.php:57 src/Module/Item/Feed.php:80 msgid "Item not found." @@ -414,31 +390,28 @@ msgstr "" #: src/Module/HCard.php:51 src/Module/Profile/Common.php:40 #: src/Module/Profile/Common.php:51 src/Module/Profile/Contacts.php:39 #: src/Module/Profile/Contacts.php:49 src/Module/Profile/Media.php:38 -#: src/Module/Profile/Photos/Index.php:77 -#: src/Module/Profile/Photos/Upload.php:87 -#: src/Module/Profile/RemoteFollow.php:71 src/Module/Profile/Status.php:58 -#: src/Module/Register.php:267 +#: src/Module/Profile/Photos.php:77 src/Module/Profile/RemoteFollow.php:71 +#: src/Module/Profile/Status.php:58 src/Module/Register.php:267 msgid "User not found." msgstr "" #: mod/photos.php:107 src/Module/BaseProfile.php:67 -#: src/Module/Profile/Photos/Index.php:169 +#: src/Module/Profile/Photos.php:169 msgid "Photo Albums" msgstr "" -#: mod/photos.php:108 src/Module/Profile/Photos/Index.php:170 -#: src/Module/Profile/Photos/Index.php:187 +#: mod/photos.php:108 src/Module/Profile/Photos.php:170 +#: src/Module/Profile/Photos.php:187 msgid "Recent Photos" msgstr "" -#: mod/photos.php:110 mod/photos.php:1066 -#: src/Module/Profile/Photos/Index.php:172 -#: src/Module/Profile/Photos/Index.php:189 +#: mod/photos.php:110 mod/photos.php:1066 src/Module/Profile/Photos.php:172 +#: src/Module/Profile/Photos.php:189 msgid "Upload New Photos" msgstr "" #: mod/photos.php:128 src/Module/BaseSettings.php:74 -#: src/Module/Profile/Photos/Index.php:153 +#: src/Module/Profile/Photos.php:153 msgid "everybody" msgstr "" @@ -472,7 +445,7 @@ msgid "%1$s was tagged in %2$s by %3$s" msgstr "" #: mod/photos.php:630 mod/photos.php:633 mod/photos.php:660 -#: src/Module/Profile/Photos/Upload.php:213 +#: src/Module/Media/Photo/Upload.php:188 #: src/Module/Settings/Profile/Photo/Index.php:59 #, php-format msgid "Image exceeds size limit of %s" @@ -496,19 +469,19 @@ msgstr "" msgid "Image file is empty." msgstr "" -#: mod/photos.php:683 src/Module/Profile/Photos/Upload.php:179 -#: src/Module/Profile/Photos/Upload.php:180 +#: mod/photos.php:683 src/Module/Media/Photo/Upload.php:154 +#: src/Module/Media/Photo/Upload.php:155 #: src/Module/Settings/Profile/Photo/Index.php:68 msgid "Unable to process image." msgstr "" -#: mod/photos.php:709 src/Module/Profile/Photos/Upload.php:231 +#: mod/photos.php:709 src/Module/Media/Photo/Upload.php:206 #: src/Module/Settings/Profile/Photo/Index.php:95 msgid "Image upload failed." msgstr "" #: mod/photos.php:795 src/Module/Conversation/Community.php:187 -#: src/Module/Directory.php:48 src/Module/Profile/Photos/Index.php:72 +#: src/Module/Directory.php:48 src/Module/Profile/Photos.php:72 #: src/Module/Search/Index.php:64 msgid "Public access denied." msgstr "" @@ -517,7 +490,7 @@ msgstr "" msgid "No photos selected" msgstr "" -#: mod/photos.php:869 src/Module/Profile/Photos/Index.php:92 +#: mod/photos.php:869 src/Module/Profile/Photos.php:92 msgid "Access to this item is restricted." msgstr "" @@ -550,6 +523,16 @@ msgstr "" msgid "Delete Album" msgstr "" +#: mod/photos.php:997 mod/photos.php:1098 src/Content/Conversation.php:389 +#: src/Module/Contact/Follow.php:173 src/Module/Contact/Revoke.php:109 +#: src/Module/Contact/Unfollow.php:126 +#: src/Module/Media/Attachment/Browser.php:78 +#: src/Module/Media/Photo/Browser.php:88 src/Module/Post/Edit.php:164 +#: src/Module/Post/Tag/Remove.php:109 src/Module/Profile/RemoteFollow.php:134 +#: src/Module/Security/TwoFactor/SignOut.php:125 +msgid "Cancel" +msgstr "" + #: mod/photos.php:1023 msgid "Edit Album" msgstr "" @@ -566,7 +549,7 @@ msgstr "" msgid "Show Oldest First" msgstr "" -#: mod/photos.php:1051 src/Module/Profile/Photos/Index.php:140 +#: mod/photos.php:1051 src/Module/Profile/Photos.php:140 msgid "View Photo" msgstr "" @@ -1686,6 +1669,11 @@ msgstr "" msgid "Your profile page" msgstr "" +#: src/Content/Nav.php:195 src/Module/BaseProfile.php:64 +#: src/Module/Media/Photo/Browser.php:74 view/theme/frio/theme.php:242 +msgid "Photos" +msgstr "" + #: src/Content/Nav.php:195 view/theme/frio/theme.php:242 msgid "Your photos" msgstr "" @@ -3180,7 +3168,7 @@ msgstr "" msgid "[no subject]" msgstr "" -#: src/Model/Photo.php:1086 src/Module/Profile/Photos/Upload.php:223 +#: src/Model/Photo.php:1139 src/Module/Media/Photo/Upload.php:198 msgid "Wall Photos" msgstr "" @@ -5265,7 +5253,7 @@ msgstr "" msgid "Applications" msgstr "" -#: src/Module/Attach.php:50 src/Module/Attach.php:62 +#: src/Module/Attach.php:49 src/Module/Attach.php:61 msgid "Item was not found." msgstr "" @@ -5894,10 +5882,10 @@ msgid "The contact could not be added." msgstr "" #: src/Module/Contact/MatchInterests.php:94 -#: src/Module/Profile/Attachment/Upload.php:80 -#: src/Module/Profile/Attachment/Upload.php:102 -#: src/Module/Profile/Photos/Upload.php:113 -#: src/Module/Profile/Photos/Upload.php:162 +#: src/Module/Media/Attachment/Upload.php:80 +#: src/Module/Media/Attachment/Upload.php:85 +#: src/Module/Media/Photo/Upload.php:83 src/Module/Media/Photo/Upload.php:88 +#: src/Module/Media/Photo/Upload.php:137 msgid "Invalid request." msgstr "" @@ -7129,6 +7117,38 @@ msgstr "" msgid "A Decentralized Social Network" msgstr "" +#: src/Module/Media/Attachment/Browser.php:58 +#: src/Module/Media/Photo/Browser.php:59 +msgid "You need to be logged in to access this page." +msgstr "" + +#: src/Module/Media/Attachment/Browser.php:75 +msgid "Files" +msgstr "" + +#: src/Module/Media/Attachment/Browser.php:80 +#: src/Module/Media/Photo/Browser.php:90 +#: src/Module/Settings/Profile/Photo/Index.php:128 +msgid "Upload" +msgstr "" + +#: src/Module/Media/Attachment/Upload.php:100 +msgid "Sorry, maybe your upload is bigger than the PHP configuration allows" +msgstr "" + +#: src/Module/Media/Attachment/Upload.php:100 +msgid "Or - did you try to upload an empty file?" +msgstr "" + +#: src/Module/Media/Attachment/Upload.php:107 +#, php-format +msgid "File exceeds size limit of %s" +msgstr "" + +#: src/Module/Media/Attachment/Upload.php:117 +msgid "File upload failed." +msgstr "" + #: src/Module/Moderation/BaseUsers.php:72 msgid "List of all users" msgstr "" @@ -8134,28 +8154,11 @@ msgstr "" msgid "Remove" msgstr "" -#: src/Module/Profile/Attachment/Upload.php:117 -msgid "Sorry, maybe your upload is bigger than the PHP configuration allows" -msgstr "" - -#: src/Module/Profile/Attachment/Upload.php:117 -msgid "Or - did you try to upload an empty file?" -msgstr "" - -#: src/Module/Profile/Attachment/Upload.php:124 -#, php-format -msgid "File exceeds size limit of %s" -msgstr "" - -#: src/Module/Profile/Attachment/Upload.php:134 -msgid "File upload failed." -msgstr "" - #: src/Module/Profile/Contacts.php:119 msgid "No contacts." msgstr "" -#: src/Module/Profile/Photos/Index.php:146 +#: src/Module/Profile/Photos.php:146 msgid "View Album" msgstr "" From 4e53ba0c20aef86d7a5ef202faed498b4181bb76 Mon Sep 17 00:00:00 2001 From: Philipp Date: Sun, 27 Nov 2022 01:44:12 +0100 Subject: [PATCH 12/40] Cache the Module class --- src/App/Router.php | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/src/App/Router.php b/src/App/Router.php index b6fd1098f5..35ea9ada8b 100644 --- a/src/App/Router.php +++ b/src/App/Router.php @@ -40,6 +40,7 @@ use Friendica\Module\HTTPException\MethodNotAllowed; use Friendica\Module\HTTPException\PageNotFound; use Friendica\Module\Special\Options; use Friendica\Network\HTTPException; +use Friendica\Network\HTTPException\InternalServerErrorException; use Friendica\Network\HTTPException\MethodNotAllowedException; use Friendica\Network\HTTPException\NotFoundException; use Friendica\Util\Router\FriendicaGroupCountBased; @@ -114,6 +115,9 @@ class Router /** @var array */ private $server; + /** @var string|null */ + protected $moduleClass = null; + /** * @param array $server The $_SERVER variable * @param string $baseRoutesFilepath The path to a base routes file to leverage cache, can be empty @@ -216,7 +220,7 @@ class Router * * @return bool */ - private function isGroup(array $config) + private function isGroup(array $config): bool { return is_array($config) && @@ -252,21 +256,39 @@ class Router * * @return RouteCollector|null */ - public function getRouteCollector() + public function getRouteCollector(): ?RouteCollector { return $this->routeCollector; } + /** + * Returns the Friendica\BaseModule-extending class name if a route rule matched + * + * @return string + * + * @throws InternalServerErrorException + * @throws MethodNotAllowedException + * @throws NotFoundException + */ + public function getModuleClass(): string + { + if (empty($this->moduleClass)) { + $this->determineModuleClass(); + } + + return $this->moduleClass; + } + /** * Returns the relevant module class name for the given page URI or NULL if no route rule matched. * - * @return string A Friendica\BaseModule-extending class name if a route rule matched + * @return void * * @throws HTTPException\InternalServerErrorException * @throws HTTPException\MethodNotAllowedException If a rule matched but the method didn't * @throws HTTPException\NotFoundException If no rule matched */ - public function getModuleClass(): string + private function determineModuleClass(): void { $cmd = $this->args->getCommand(); $cmd = '/' . ltrim($cmd, '/'); @@ -277,21 +299,19 @@ class Router // Check if the HTTP method is OPTIONS and return the special Options Module with the possible HTTP methods if ($this->args->getMethod() === static::OPTIONS) { - $moduleClass = Options::class; - $this->parameters = ['allowedMethods' => $dispatcher->getOptions($cmd)]; + $this->moduleClass = Options::class; + $this->parameters = ['allowedMethods' => $dispatcher->getOptions($cmd)]; } else { $routeInfo = $dispatcher->dispatch($this->args->getMethod(), $cmd); if ($routeInfo[0] === Dispatcher::FOUND) { - $moduleClass = $routeInfo[1]; - $this->parameters = $routeInfo[2]; + $this->moduleClass = $routeInfo[1]; + $this->parameters = $routeInfo[2]; } elseif ($routeInfo[0] === Dispatcher::METHOD_NOT_ALLOWED) { throw new HTTPException\MethodNotAllowedException($this->l10n->t('Method not allowed for this module. Allowed method(s): %s', implode(', ', $routeInfo[1]))); } else { throw new HTTPException\NotFoundException($this->l10n->t('Page not found.')); } } - - return $moduleClass; } public function getModule(?string $module_class = null): ICanHandleRequests From 272911527cc7dd5a32fdf1a24eca641ed31be402 Mon Sep 17 00:00:00 2001 From: Philipp Date: Sun, 27 Nov 2022 01:52:14 +0100 Subject: [PATCH 13/40] Apply suggestions from code review Co-authored-by: Hypolite Petovan --- src/Module/Media/Attachment/Browser.php | 1 - src/Module/Media/Attachment/Upload.php | 1 - view/js/module/media/browser.js | 3 --- view/theme/frio/js/module/media/browser.js | 4 +--- 4 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/Module/Media/Attachment/Browser.php b/src/Module/Media/Attachment/Browser.php index ed9ae74a3f..86ea00faf8 100644 --- a/src/Module/Media/Attachment/Browser.php +++ b/src/Module/Media/Attachment/Browser.php @@ -66,7 +66,6 @@ class Browser extends BaseModule $files = Attach::selectToArray(['id', 'filename', 'filetype'], ['uid' => $this->session->getLocalUserId()]); - $fileArray = array_map([$this, 'map_files'], $files); $tpl = Renderer::getMarkupTemplate('media/browser.tpl'); diff --git a/src/Module/Media/Attachment/Upload.php b/src/Module/Media/Attachment/Upload.php index b11469f5af..0bc95fe792 100644 --- a/src/Module/Media/Attachment/Upload.php +++ b/src/Module/Media/Attachment/Upload.php @@ -74,7 +74,6 @@ class Upload extends \Friendica\BaseModule } $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.')); diff --git a/view/js/module/media/browser.js b/view/js/module/media/browser.js index 7790e2588b..c78a7f13b6 100644 --- a/view/js/module/media/browser.js +++ b/view/js/module/media/browser.js @@ -67,8 +67,6 @@ const Browser = { Browser.id = h.split('-')[1]; } - console.log('FileBrowser:', nickname, type, Browser.event, Browser.id); - $('.error a.close').on('click', function (e) { e.preventDefault(); $('.error').addClass('hidden'); @@ -90,7 +88,6 @@ const Browser = { if (Browser.type === "attachment") { embed = '[attachment]' + this.dataset.link + '[/attachment]'; } - console.log(Browser.event, this.dataset.filename, embed, Browser.id); parent.$('body').trigger(Browser.event, [ this.dataset.filename, embed, diff --git a/view/theme/frio/js/module/media/browser.js b/view/theme/frio/js/module/media/browser.js index c89f426ebd..ccd2e1b5be 100644 --- a/view/theme/frio/js/module/media/browser.js +++ b/view/theme/frio/js/module/media/browser.js @@ -56,7 +56,7 @@ * IMPORTANT * * This is a modified version to work with - * the frio theme.and bootstrap modals + * the frio theme and Bootstrap modals * * The original file is under: * js/module/media/browser.js @@ -86,8 +86,6 @@ var Browser = { } } - console.log('FileBrowser: ' + nickname, type, Browser.event, Browser.id); - Browser.postLoad(); $('.error .close').on('click', function (e) { From 3ac3b3d2af2b8613978fce9f285a5afcc9e1352e Mon Sep 17 00:00:00 2001 From: Philipp Date: Sun, 27 Nov 2022 01:52:49 +0100 Subject: [PATCH 14/40] Perfection! --- src/Model/Photo.php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/Model/Photo.php b/src/Model/Photo.php index 87a81069f8..990fb7e616 100644 --- a/src/Model/Photo.php +++ b/src/Model/Photo.php @@ -206,8 +206,15 @@ class Photo */ public static function getBrowsablePhotosForUser(int $uid, string $album = null): array { + $values = [ + $uid, + Photo::CONTACT_AVATAR, + Photo::CONTACT_BANNER + ]; + if (!empty($album)) { - $sqlExtra = sprintf("AND `album` = '%s' ", DBA::escape($album)); + $sqlExtra = "AND `album` = ? "; + $values[] = $album; $sqlExtra2 = ""; } else { $sqlExtra = ''; @@ -218,11 +225,9 @@ class Photo DBA::p( "SELECT `resource-id`, ANY_VALUE(`id`) AS `id`, ANY_VALUE(`filename`) AS `filename`, ANY_VALUE(`type`) AS `type`, min(`scale`) AS `hiq`, max(`scale`) AS `loq`, ANY_VALUE(`desc`) AS `desc`, ANY_VALUE(`created`) AS `created` - FROM `photo` WHERE `uid` = ? $sqlExtra AND NOT `photo-type` IN (?, ?) + FROM `photo` WHERE `uid` = ? AND NOT `photo-type` IN (?, ?) $sqlExtra GROUP BY `resource-id` $sqlExtra2", - $uid, - Photo::CONTACT_AVATAR, - Photo::CONTACT_BANNER + $values )); } From 25e14121747dc761f87c7f5218a359d9c82b8113 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sat, 26 Nov 2022 21:48:26 -0500 Subject: [PATCH 15/40] Remove related notifications when marking an item for deletion --- src/Model/Item.php | 3 +++ .../Notifications/Repository/Notification.php | 20 +++++++++++++++++++ .../Notifications/Repository/Notify.php | 6 ++++++ 3 files changed, 29 insertions(+) diff --git a/src/Model/Item.php b/src/Model/Item.php index 0390730fd8..cb998c0fdc 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -385,6 +385,9 @@ class Item Post\ThreadUser::update($item['uri-id'], $item['uid'], ['hidden' => true]); } + DI::notify()->deleteForItem($item['uri-id']); + DI::notification()->deleteForItem($item['uri-id']); + Logger::info('Item has been marked for deletion.', ['id' => $item_id]); return true; diff --git a/src/Navigation/Notifications/Repository/Notification.php b/src/Navigation/Notifications/Repository/Notification.php index a9630464aa..6a513c5dc2 100644 --- a/src/Navigation/Notifications/Repository/Notification.php +++ b/src/Navigation/Notifications/Repository/Notification.php @@ -33,6 +33,7 @@ use Friendica\Navigation\Notifications\Collection; use Friendica\Navigation\Notifications\Entity; use Friendica\Navigation\Notifications\Factory; use Friendica\Network\HTTPException\NotFoundException; +use Friendica\Protocol\Activity; use Friendica\Util\DateTimeFormat; use Psr\Log\LoggerInterface; @@ -268,4 +269,23 @@ class Notification extends BaseRepository return $this->db->delete(self::$table_name, $condition); } + + public function deleteForItem(int $itemUriId): bool + { + $conditionTarget = [ + 'vid' => Verb::getID(Activity::POST), + 'target-uri-id' => $itemUriId, + ]; + + $conditionParent = [ + 'vid' => Verb::getID(Activity::POST), + 'parent-uri-id' => $itemUriId, + ]; + + $this->logger->notice('deleteForItem', ['conditionTarget' => $conditionTarget, 'conditionParent' => $conditionParent]); + + return + $this->db->delete(self::$table_name, $conditionTarget) + && $this->db->delete(self::$table_name, $conditionParent); + } } diff --git a/src/Navigation/Notifications/Repository/Notify.php b/src/Navigation/Notifications/Repository/Notify.php index 3891a6e256..75aff6b870 100644 --- a/src/Navigation/Notifications/Repository/Notify.php +++ b/src/Navigation/Notifications/Repository/Notify.php @@ -807,4 +807,10 @@ class Notify extends BaseRepository return $this->storeAndSend($params, $sitelink, $tsitelink, $hsitelink, $title, $subject, $preamble, $epreamble, $item['body'], $itemlink, true); } + + public function deleteForItem(int $itemUriId): void + { + $this->db->delete('notify', ['otype' => 'item', 'uri-id' => $itemUriId]); + $this->db->delete('notify', ['otype' => 'item', 'parent-uri-id' => $itemUriId]); + } } From db987999b521e0dfa4a1171c60b361dc0acb0038 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sat, 26 Nov 2022 18:12:46 -0500 Subject: [PATCH 16/40] Return only one result in case of exact match in Api\Mastodon\Search --- src/Model/Contact.php | 3 +- src/Module/Api/Mastodon/Search.php | 73 ++++++++++++++++++++++++------ 2 files changed, 59 insertions(+), 17 deletions(-) diff --git a/src/Model/Contact.php b/src/Model/Contact.php index e0c3c1682a..eabe378a46 100644 --- a/src/Model/Contact.php +++ b/src/Model/Contact.php @@ -3420,8 +3420,7 @@ class Contact ["(NOT `unsearchable` OR `nurl` IN (SELECT `nurl` FROM `owner-view` WHERE `publish` OR `net-publish`)) AND (`addr` LIKE ? OR `name` LIKE ? OR `nick` LIKE ?)", $search, $search, $search]); - $contacts = self::selectToArray([], $condition, $params); - return $contacts; + return self::selectToArray([], $condition, $params); } /** diff --git a/src/Module/Api/Mastodon/Search.php b/src/Module/Api/Mastodon/Search.php index fafdab0fd1..fc94673082 100644 --- a/src/Module/Api/Mastodon/Search.php +++ b/src/Module/Api/Mastodon/Search.php @@ -26,6 +26,7 @@ use Friendica\Core\System; use Friendica\Database\DBA; use Friendica\DI; use Friendica\Model\Contact; +use Friendica\Model\Item; use Friendica\Model\Post; use Friendica\Model\Tag; use Friendica\Module\BaseApi; @@ -67,10 +68,24 @@ class Search extends BaseApi if (empty($request['type']) || ($request['type'] == 'accounts')) { $result['accounts'] = self::searchAccounts($uid, $request['q'], $request['resolve'], $limit, $request['offset'], $request['following']); + + if (!is_array($result['accounts'])) { + // Curbing the search if we got an exact result + $request['type'] = 'accounts'; + $result['accounts'] = [$result['accounts']]; + } } + if ((empty($request['type']) || ($request['type'] == 'statuses')) && (strpos($request['q'], '@') == false)) { $result['statuses'] = self::searchStatuses($uid, $request['q'], $request['account_id'], $request['max_id'], $request['min_id'], $limit, $request['offset']); + + if (!is_array($result['statuses'])) { + // Curbing the search if we got an exact result + $request['type'] = 'statuses'; + $result['statuses'] = [$result['statuses']]; + } } + if ((empty($request['type']) || ($request['type'] == 'hashtags')) && (strpos($request['q'], '@') == false)) { $result['hashtags'] = self::searchHashtags($request['q'], $request['exclude_unreviewed'], $limit, $request['offset'], $this->parameters['version']); } @@ -78,31 +93,59 @@ class Search extends BaseApi System::jsonExit($result); } + /** + * @param int $uid + * @param string $q + * @param bool $resolve + * @param int $limit + * @param int $offset + * @param bool $following + * @return array|\Friendica\Object\Api\Mastodon\Account Object if result is absolute (exact account match), list if not + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \Friendica\Network\HTTPException\NotFoundException + * @throws \ImagickException + */ private static function searchAccounts(int $uid, string $q, bool $resolve, int $limit, int $offset, bool $following) { - $accounts = []; - - if ((strrpos($q, '@') > 0) || Network::isValidHttpUrl($q)) { - $id = Contact::getIdForURL($q, 0, $resolve ? null : false); - - if (!empty($id)) { - $accounts[] = DI::mstdnAccount()->createFromContactId($id, $uid); - } + if ( + (strrpos($q, '@') > 0 || Network::isValidHttpUrl($q)) + && $id = Contact::getIdForURL($q, 0, $resolve ? null : false) + ) { + return DI::mstdnAccount()->createFromContactId($id, $uid); } - if (empty($accounts)) { - $contacts = Contact::searchByName($q, '', $following ? $uid : 0, $limit, $offset); - foreach ($contacts as $contact) { - $accounts[] = DI::mstdnAccount()->createFromContactId($contact['id'], $uid); - } - DBA::close($contacts); + $accounts = []; + foreach (Contact::searchByName($q, '', $following ? $uid : 0, $limit, $offset) as $contact) { + $accounts[] = DI::mstdnAccount()->createFromContactId($contact['id'], $uid); } return $accounts; } + /** + * @param int $uid + * @param string $q + * @param string $account_id + * @param int $max_id + * @param int $min_id + * @param int $limit + * @param int $offset + * @return array|\Friendica\Object\Api\Mastodon\Status Object is result is absolute (exact post match), list if not + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \Friendica\Network\HTTPException\NotFoundException + * @throws \ImagickException + */ private static function searchStatuses(int $uid, string $q, string $account_id, int $max_id, int $min_id, int $limit, int $offset) { + if (Network::isValidHttpUrl($q)) { + $q = Network::convertToIdn($q); + // If the user-specific search failed, we search and probe a public post + $item_id = Item::fetchByLink($q, $uid) ?: Item::fetchByLink($q); + if ($item_id && $item = Post::selectFirst(['uri-id'], ['id' => $item_id])) { + return DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid); + } + } + $params = ['order' => ['uri-id' => true], 'limit' => [$offset, $limit]]; if (substr($q, 0, 1) == '#') { @@ -148,7 +191,7 @@ class Search extends BaseApi return $statuses; } - private static function searchHashtags(string $q, bool $exclude_unreviewed, int $limit, int $offset, int $version) + private static function searchHashtags(string $q, bool $exclude_unreviewed, int $limit, int $offset, int $version): array { $q = ltrim($q, '#'); From 0e2c2cd0e0fc8c2ed7a94ef7b4b22c98f562656d Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 27 Nov 2022 19:22:41 +0000 Subject: [PATCH 17/40] API: Support new tag endpoints --- .htaccess-dist | 2 +- src/Module/Api/Mastodon/Tags.php | 48 +++++++++++++++++++++++ src/Module/Api/Mastodon/Tags/Follow.php | 44 +++++++++++++++++++++ src/Module/Api/Mastodon/Tags/Unfollow.php | 44 +++++++++++++++++++++ static/routes.config.php | 6 ++- 5 files changed, 142 insertions(+), 2 deletions(-) create mode 100644 src/Module/Api/Mastodon/Tags.php create mode 100644 src/Module/Api/Mastodon/Tags/Follow.php create mode 100644 src/Module/Api/Mastodon/Tags/Unfollow.php diff --git a/.htaccess-dist b/.htaccess-dist index 404137168a..c5c1b5b716 100644 --- a/.htaccess-dist +++ b/.htaccess-dist @@ -51,6 +51,6 @@ AddType audio/ogg .oga RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d - RewriteRule ^(.*)$ index.php?pagename=$1 [E=REMOTE_USER:%{HTTP:Authorization},L,QSA] + RewriteRule ^(.*)$ index.php?pagename=$1 [E=REMOTE_USER:%{HTTP:Authorization},L,QSA,B] diff --git a/src/Module/Api/Mastodon/Tags.php b/src/Module/Api/Mastodon/Tags.php new file mode 100644 index 0000000000..97631b506a --- /dev/null +++ b/src/Module/Api/Mastodon/Tags.php @@ -0,0 +1,48 @@ +. + * + */ + +namespace Friendica\Module\Api\Mastodon; + +use Friendica\App\Router; +use Friendica\Core\Logger; +use Friendica\DI; +use Friendica\Module\BaseApi; + +/** + * @see https://docs.joinmastodon.org/methods/tags/ + */ +class Tags extends BaseApi +{ + /** + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + */ + protected function rawContent(array $request = []) + { + self::checkAllowedScope(self::SCOPE_READ); + $uid = self::getCurrentUserID(); + + if (empty($this->parameters['hashtag'])) { + DI::mstdnError()->UnprocessableEntity(); + } + + $this->response->unsupported(Router::GET, $request); + } +} diff --git a/src/Module/Api/Mastodon/Tags/Follow.php b/src/Module/Api/Mastodon/Tags/Follow.php new file mode 100644 index 0000000000..9a813f7257 --- /dev/null +++ b/src/Module/Api/Mastodon/Tags/Follow.php @@ -0,0 +1,44 @@ +. + * + */ + +namespace Friendica\Module\Api\Mastodon\Tags; + +use Friendica\App\Router; +use Friendica\DI; +use Friendica\Module\BaseApi; + +/** + * @see https://docs.joinmastodon.org/methods/tags/#follow + */ +class Follow extends BaseApi +{ + protected function post(array $request = []) + { + self::checkAllowedScope(self::SCOPE_WRITE); + $uid = self::getCurrentUserID(); + + if (empty($this->parameters['hashtag'])) { + DI::mstdnError()->UnprocessableEntity(); + } + + $this->response->unsupported(Router::POST, $request); + } +} diff --git a/src/Module/Api/Mastodon/Tags/Unfollow.php b/src/Module/Api/Mastodon/Tags/Unfollow.php new file mode 100644 index 0000000000..a20b824b8d --- /dev/null +++ b/src/Module/Api/Mastodon/Tags/Unfollow.php @@ -0,0 +1,44 @@ +. + * + */ + +namespace Friendica\Module\Api\Mastodon\Tags; + +use Friendica\App\Router; +use Friendica\DI; +use Friendica\Module\BaseApi; + +/** + * @see https://docs.joinmastodon.org/methods/tags/#unfollow + */ +class Unfollow extends BaseApi +{ + protected function post(array $request = []) + { + self::checkAllowedScope(self::SCOPE_WRITE); + $uid = self::getCurrentUserID(); + + if (empty($this->parameters['hashtag'])) { + DI::mstdnError()->UnprocessableEntity(); + } + + $this->response->unsupported(Router::POST, $request); + } +} diff --git a/static/routes.config.php b/static/routes.config.php index ae57557117..522e5ff168 100644 --- a/static/routes.config.php +++ b/static/routes.config.php @@ -235,10 +235,10 @@ return [ '/featured_tags' => [Module\Api\Mastodon\Unimplemented::class, [R::GET, R::POST]], // not supported '/featured_tags/{id:\d+}' => [Module\Api\Mastodon\Unimplemented::class, [R::DELETE ]], // not supported '/featured_tags/suggestions' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // not supported - '/filters' => [Module\Api\Mastodon\Filters::class, [R::GET ]], // Dummy, not supported '/filters/{id:\d+}' => [Module\Api\Mastodon\Unimplemented::class, [R::GET, R::POST, R::PUT, R::DELETE]], // not supported '/follow_requests' => [Module\Api\Mastodon\FollowRequests::class, [R::GET ]], '/follow_requests/{id:\d+}/{action}' => [Module\Api\Mastodon\FollowRequests::class, [ R::POST]], + '/followed_tags' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // @todo '/instance' => [Module\Api\Mastodon\Instance::class, [R::GET ]], '/instance/activity' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // @todo '/instance/peers' => [Module\Api\Mastodon\Instance\Peers::class, [R::GET ]], @@ -289,6 +289,9 @@ return [ '/streaming/user' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // not implemented '/streaming/user/notification' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // not implemented '/suggestions/{id:\d+}' => [Module\Api\Mastodon\Unimplemented::class, [R::DELETE ]], // not implemented + '/tags/{hashtag}' => [Module\Api\Mastodon\Tags::class, [R::GET ]], + '/tags/{hashtag}/follow' => [Module\Api\Mastodon\Tags\Follow::class, [ R::POST]], + '/tags/{hashtag}/unfollow' => [Module\Api\Mastodon\Tags\Unfollow::class, [ R::POST]], '/timelines/direct' => [Module\Api\Mastodon\Timelines\Direct::class, [R::GET ]], '/timelines/home' => [Module\Api\Mastodon\Timelines\Home::class, [R::GET ]], '/timelines/list/{id:\d+}' => [Module\Api\Mastodon\Timelines\ListTimeline::class, [R::GET ]], @@ -301,6 +304,7 @@ return [ ], '/v{version:\d+}' => [ '/admin/accounts' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // not supported + '/filters' => [Module\Api\Mastodon\Filters::class, [R::GET ]], // Dummy, not supported '/media' => [Module\Api\Mastodon\Media::class, [ R::POST]], '/search' => [Module\Api\Mastodon\Search::class, [R::GET ]], '/suggestions' => [Module\Api\Mastodon\Suggestions::class, [R::GET ]], From 6d74d74a265366630896d1612c28f28b90f8d7ea Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 27 Nov 2022 20:47:08 +0000 Subject: [PATCH 18/40] Issue 12149: Show that a post was reshared --- src/Factory/Api/Mastodon/Status.php | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/Factory/Api/Mastodon/Status.php b/src/Factory/Api/Mastodon/Status.php index 54726815f2..9d78e5892a 100644 --- a/src/Factory/Api/Mastodon/Status.php +++ b/src/Factory/Api/Mastodon/Status.php @@ -76,16 +76,17 @@ class Status extends BaseFactory } /** - * @param int $uriId Uri-ID of the item - * @param int $uid Item user + * @param int $uriId Uri-ID of the item + * @param int $uid Item user + * @param bool $reblog Check for reblogged post * * @return \Friendica\Object\Api\Mastodon\Status * @throws HTTPException\InternalServerErrorException * @throws ImagickException|HTTPException\NotFoundException */ - public function createFromUriId(int $uriId, int $uid = 0): \Friendica\Object\Api\Mastodon\Status + public function createFromUriId(int $uriId, int $uid = 0, bool $reblog = true): \Friendica\Object\Api\Mastodon\Status { - $fields = ['uri-id', 'uid', 'author-id', 'author-uri-id', 'author-link', 'starred', 'app', 'title', 'body', 'raw-body', 'content-warning', 'question-id', + $fields = ['uri-id', 'uid', 'author-id', 'author-uri-id', 'author-link', 'causer-uri-id', 'post-reason', 'starred', 'app', 'title', 'body', 'raw-body', 'content-warning', 'question-id', 'created', 'network', 'thr-parent-id', 'parent-author-id', 'language', 'uri', 'plink', 'private', 'vid', 'gravity', 'featured', 'has-media', 'quote-uri-id']; $item = Post::selectFirst($fields, ['uri-id' => $uriId, 'uid' => [0, $uid]], ['order' => ['uid' => true]]); if (!$item) { @@ -95,7 +96,10 @@ class Status extends BaseFactory } throw new HTTPException\NotFoundException('Item with URI ID ' . $uriId . ' not found' . ($uid ? ' for user ' . $uid : '.')); } - $account = $this->mstdnAccountFactory->createFromUriId($item['author-uri-id'], $uid); + + $is_reshare = $reblog && !is_null($item['causer-uri-id']) && ($item['post-reason'] == Item::PR_ANNOUNCEMENT); + + $account = $this->mstdnAccountFactory->createFromUriId($is_reshare ? $item['causer-uri-id']:$item['author-uri-id'], $uid); $count_announce = Post::countPosts([ 'thr-parent-id' => $uriId, @@ -183,6 +187,10 @@ class Status extends BaseFactory $reshare = []; } + if ($is_reshare) { + $reshare = $this->createFromUriId($uriId, $uid, false)->toArray(); + } + return new \Friendica\Object\Api\Mastodon\Status($item, $account, $counts, $userAttributes, $sensitive, $application, $mentions, $tags, $card, $attachments, $reshare, $poll); } From 85f57e69faaca3645c596afd12e4b024194ae349 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 28 Nov 2022 03:29:43 +0000 Subject: [PATCH 19/40] Issue 12191: We can now follow and unfollow tags via API --- src/Content/Widget/SavedSearches.php | 2 +- src/Module/Api/Mastodon/FollowedTags.php | 83 +++++++++++++++++++++++ src/Module/Api/Mastodon/Tags.php | 11 ++- src/Module/Api/Mastodon/Tags/Follow.php | 11 ++- src/Module/Api/Mastodon/Tags/Unfollow.php | 10 ++- src/Object/Api/Mastodon/Tag.php | 15 ++-- static/routes.config.php | 2 +- 7 files changed, 120 insertions(+), 14 deletions(-) create mode 100644 src/Module/Api/Mastodon/FollowedTags.php diff --git a/src/Content/Widget/SavedSearches.php b/src/Content/Widget/SavedSearches.php index 6b6202ba32..1bf9e76a26 100644 --- a/src/Content/Widget/SavedSearches.php +++ b/src/Content/Widget/SavedSearches.php @@ -37,7 +37,7 @@ class SavedSearches public static function getHTML(string $return_url, string $search = ''): string { $saved = []; - $saved_searches = DBA::select('search', ['id', 'term'], ['uid' => DI::userSession()->getLocalUserId()]); + $saved_searches = DBA::select('search', ['id', 'term'], ['uid' => DI::userSession()->getLocalUserId()], ['order' => ['term']]); while ($saved_search = DBA::fetch($saved_searches)) { $saved[] = [ 'id' => $saved_search['id'], diff --git a/src/Module/Api/Mastodon/FollowedTags.php b/src/Module/Api/Mastodon/FollowedTags.php new file mode 100644 index 0000000000..6e95783c9f --- /dev/null +++ b/src/Module/Api/Mastodon/FollowedTags.php @@ -0,0 +1,83 @@ +. + * + */ + +namespace Friendica\Module\Api\Mastodon; + +use Friendica\Core\System; +use Friendica\Database\DBA; +use Friendica\Module\BaseApi; + +/** + * @see https://docs.joinmastodon.org/methods/followed_tags/ + */ +class FollowedTags extends BaseApi +{ + protected function rawContent(array $request = []) + { + self::checkAllowedScope(self::SCOPE_READ); + $uid = self::getCurrentUserID(); + + $request = $this->getRequest([ + 'max_id' => 0, + 'since_id' => 0, + 'min_id' => 0, + 'limit' => 100, // Maximum number of results to return. Defaults to 100. Paginate using the HTTP Link header. + ], $request); + + $params = ['order' => ['id' => true], 'limit' => $request['limit']]; + + $condition = ["`uid` = ? AND `term` LIKE ?", $uid, '#%']; + + if (!empty($request['max_id'])) { + $condition = DBA::mergeConditions($condition, ["`id` < ?", $request['max_id']]); + } + + if (!empty($request['since_id'])) { + $condition = DBA::mergeConditions($condition, ["`id` > ?", $request['since_id']]); + } + + if (!empty($request['min_id'])) { + $condition = DBA::mergeConditions($condition, ["`id` > ?", $request['min_id']]); + + $params['order'] = ['id']; + } + + $return = []; + + $saved_searches = DBA::select('search', ['id', 'term'], $condition); + while ($saved_search = DBA::fetch($saved_searches)) { + self::setBoundaries($saved_search['id']); + $tag = ['name' => substr($saved_search['term'], 1)]; + + $hashtag = new \Friendica\Object\Api\Mastodon\Tag($this->baseUrl, $tag, [], true); + $return[] = $hashtag->toArray(); + } + + DBA::close($saved_searches); + + if (!empty($request['min_id'])) { + $return = array_reverse($return); + } + + self::setLinkHeader(); + System::jsonExit($return); + } +} diff --git a/src/Module/Api/Mastodon/Tags.php b/src/Module/Api/Mastodon/Tags.php index 97631b506a..442f0f6576 100644 --- a/src/Module/Api/Mastodon/Tags.php +++ b/src/Module/Api/Mastodon/Tags.php @@ -21,8 +21,8 @@ namespace Friendica\Module\Api\Mastodon; -use Friendica\App\Router; -use Friendica\Core\Logger; +use Friendica\Core\System; +use Friendica\Database\DBA; use Friendica\DI; use Friendica\Module\BaseApi; @@ -43,6 +43,11 @@ class Tags extends BaseApi DI::mstdnError()->UnprocessableEntity(); } - $this->response->unsupported(Router::GET, $request); + $tag = ltrim($this->parameters['hashtag'], '#'); + $following = DBA::exists('search', ['uid' => $uid, 'term' => '#' . $tag]); + $term = ['term' => $tag]; + + $hashtag = new \Friendica\Object\Api\Mastodon\Tag($this->baseUrl, $term, [], $following); + System::jsonExit($hashtag->toArray()); } } diff --git a/src/Module/Api/Mastodon/Tags/Follow.php b/src/Module/Api/Mastodon/Tags/Follow.php index 9a813f7257..e2261f3fd5 100644 --- a/src/Module/Api/Mastodon/Tags/Follow.php +++ b/src/Module/Api/Mastodon/Tags/Follow.php @@ -21,7 +21,8 @@ namespace Friendica\Module\Api\Mastodon\Tags; -use Friendica\App\Router; +use Friendica\Core\System; +use Friendica\Database\DBA; use Friendica\DI; use Friendica\Module\BaseApi; @@ -39,6 +40,12 @@ class Follow extends BaseApi DI::mstdnError()->UnprocessableEntity(); } - $this->response->unsupported(Router::POST, $request); + $fields = ['uid' => $uid, 'term' => '#' . $this->parameters['hashtag']]; + if (!DBA::exists('search', $fields)) { + DBA::insert('search', $fields); + } + + $hashtag = new \Friendica\Object\Api\Mastodon\Tag($this->baseUrl, $fields, [], true); + System::jsonExit($hashtag->toArray()); } } diff --git a/src/Module/Api/Mastodon/Tags/Unfollow.php b/src/Module/Api/Mastodon/Tags/Unfollow.php index a20b824b8d..465c1974b5 100644 --- a/src/Module/Api/Mastodon/Tags/Unfollow.php +++ b/src/Module/Api/Mastodon/Tags/Unfollow.php @@ -21,7 +21,8 @@ namespace Friendica\Module\Api\Mastodon\Tags; -use Friendica\App\Router; +use Friendica\Core\System; +use Friendica\Database\DBA; use Friendica\DI; use Friendica\Module\BaseApi; @@ -39,6 +40,11 @@ class Unfollow extends BaseApi DI::mstdnError()->UnprocessableEntity(); } - $this->response->unsupported(Router::POST, $request); + $term = ['uid' => $uid, 'term' => '#' . $this->parameters['hashtag']]; + + DBA::delete('search', $term); + + $hashtag = new \Friendica\Object\Api\Mastodon\Tag($this->baseUrl, $term, [], false); + System::jsonExit($hashtag->toArray()); } } diff --git a/src/Object/Api/Mastodon/Tag.php b/src/Object/Api/Mastodon/Tag.php index 340e30f703..e40b793e26 100644 --- a/src/Object/Api/Mastodon/Tag.php +++ b/src/Object/Api/Mastodon/Tag.php @@ -37,18 +37,23 @@ class Tag extends BaseDataTransferObject protected $url = null; /** @var array */ protected $history = []; + /** @var bool */ + protected $following = false; /** * Creates a hashtag record from an tag-view record. * * @param BaseURL $baseUrl - * @param array $tag tag-view record + * @param array $tag tag-view record + * @param array $history + * @param array $following "true" if the user is following this tag * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public function __construct(BaseURL $baseUrl, array $tag, array $history = []) + public function __construct(BaseURL $baseUrl, array $tag, array $history = [], bool $following = false) { - $this->name = strtolower($tag['name']); - $this->url = $baseUrl . '/search?tag=' . urlencode($this->name); - $this->history = $history; + $this->name = strtolower($tag['name']); + $this->url = $baseUrl . '/search?tag=' . urlencode($this->name); + $this->history = $history; + $this->following = $following; } } diff --git a/static/routes.config.php b/static/routes.config.php index 07c2b45508..42333e65fa 100644 --- a/static/routes.config.php +++ b/static/routes.config.php @@ -236,7 +236,7 @@ return [ '/filters/{id:\d+}' => [Module\Api\Mastodon\Unimplemented::class, [R::GET, R::POST, R::PUT, R::DELETE]], // not supported '/follow_requests' => [Module\Api\Mastodon\FollowRequests::class, [R::GET ]], '/follow_requests/{id:\d+}/{action}' => [Module\Api\Mastodon\FollowRequests::class, [ R::POST]], - '/followed_tags' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // @todo + '/followed_tags' => [Module\Api\Mastodon\FollowedTags::class, [R::GET ]], '/instance' => [Module\Api\Mastodon\Instance::class, [R::GET ]], '/instance/activity' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // @todo '/instance/peers' => [Module\Api\Mastodon\Instance\Peers::class, [R::GET ]], From 4e6b6fd76b7b76fe577e3dfe19daf38a5a32aa90 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Mon, 28 Nov 2022 05:00:08 +0100 Subject: [PATCH 20/40] Update src/Module/Api/Mastodon/FollowedTags.php Co-authored-by: Hypolite Petovan --- src/Module/Api/Mastodon/FollowedTags.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Module/Api/Mastodon/FollowedTags.php b/src/Module/Api/Mastodon/FollowedTags.php index 6e95783c9f..eb5e32fdc1 100644 --- a/src/Module/Api/Mastodon/FollowedTags.php +++ b/src/Module/Api/Mastodon/FollowedTags.php @@ -65,7 +65,7 @@ class FollowedTags extends BaseApi $saved_searches = DBA::select('search', ['id', 'term'], $condition); while ($saved_search = DBA::fetch($saved_searches)) { self::setBoundaries($saved_search['id']); - $tag = ['name' => substr($saved_search['term'], 1)]; + $tag = ['name' => ltrim($saved_search['term'], '#')]; $hashtag = new \Friendica\Object\Api\Mastodon\Tag($this->baseUrl, $tag, [], true); $return[] = $hashtag->toArray(); From 934766c36406b1797741ae67b9b3840598f2cccb Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 28 Nov 2022 04:04:27 +0000 Subject: [PATCH 21/40] Trim the tag --- src/Module/Api/Mastodon/Tags/Follow.php | 2 +- src/Module/Api/Mastodon/Tags/Unfollow.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Module/Api/Mastodon/Tags/Follow.php b/src/Module/Api/Mastodon/Tags/Follow.php index e2261f3fd5..767245b60f 100644 --- a/src/Module/Api/Mastodon/Tags/Follow.php +++ b/src/Module/Api/Mastodon/Tags/Follow.php @@ -40,7 +40,7 @@ class Follow extends BaseApi DI::mstdnError()->UnprocessableEntity(); } - $fields = ['uid' => $uid, 'term' => '#' . $this->parameters['hashtag']]; + $fields = ['uid' => $uid, 'term' => '#' . ltrim($this->parameters['hashtag'], '#')]; if (!DBA::exists('search', $fields)) { DBA::insert('search', $fields); } diff --git a/src/Module/Api/Mastodon/Tags/Unfollow.php b/src/Module/Api/Mastodon/Tags/Unfollow.php index 465c1974b5..163b65003b 100644 --- a/src/Module/Api/Mastodon/Tags/Unfollow.php +++ b/src/Module/Api/Mastodon/Tags/Unfollow.php @@ -40,7 +40,7 @@ class Unfollow extends BaseApi DI::mstdnError()->UnprocessableEntity(); } - $term = ['uid' => $uid, 'term' => '#' . $this->parameters['hashtag']]; + $term = ['uid' => $uid, 'term' => '#' . ltrim($this->parameters['hashtag'], '#')]; DBA::delete('search', $term); From f7167acc74db0ac31a9ccc83da6087424e261e18 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 28 Nov 2022 04:07:25 +0000 Subject: [PATCH 22/40] Standards --- src/Module/Api/Mastodon/FollowedTags.php | 2 +- src/Module/Api/Mastodon/Tags.php | 2 +- src/Module/Api/Mastodon/Tags/Follow.php | 2 +- src/Module/Api/Mastodon/Tags/Unfollow.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Module/Api/Mastodon/FollowedTags.php b/src/Module/Api/Mastodon/FollowedTags.php index eb5e32fdc1..bfa7db7935 100644 --- a/src/Module/Api/Mastodon/FollowedTags.php +++ b/src/Module/Api/Mastodon/FollowedTags.php @@ -67,7 +67,7 @@ class FollowedTags extends BaseApi self::setBoundaries($saved_search['id']); $tag = ['name' => ltrim($saved_search['term'], '#')]; - $hashtag = new \Friendica\Object\Api\Mastodon\Tag($this->baseUrl, $tag, [], true); + $hashtag = new \Friendica\Object\Api\Mastodon\Tag($this->baseUrl, $tag, [], true); $return[] = $hashtag->toArray(); } diff --git a/src/Module/Api/Mastodon/Tags.php b/src/Module/Api/Mastodon/Tags.php index 442f0f6576..d38899ac0f 100644 --- a/src/Module/Api/Mastodon/Tags.php +++ b/src/Module/Api/Mastodon/Tags.php @@ -47,7 +47,7 @@ class Tags extends BaseApi $following = DBA::exists('search', ['uid' => $uid, 'term' => '#' . $tag]); $term = ['term' => $tag]; - $hashtag = new \Friendica\Object\Api\Mastodon\Tag($this->baseUrl, $term, [], $following); + $hashtag = new \Friendica\Object\Api\Mastodon\Tag($this->baseUrl, $term, [], $following); System::jsonExit($hashtag->toArray()); } } diff --git a/src/Module/Api/Mastodon/Tags/Follow.php b/src/Module/Api/Mastodon/Tags/Follow.php index 767245b60f..22f8fa3f27 100644 --- a/src/Module/Api/Mastodon/Tags/Follow.php +++ b/src/Module/Api/Mastodon/Tags/Follow.php @@ -45,7 +45,7 @@ class Follow extends BaseApi DBA::insert('search', $fields); } - $hashtag = new \Friendica\Object\Api\Mastodon\Tag($this->baseUrl, $fields, [], true); + $hashtag = new \Friendica\Object\Api\Mastodon\Tag($this->baseUrl, $fields, [], true); System::jsonExit($hashtag->toArray()); } } diff --git a/src/Module/Api/Mastodon/Tags/Unfollow.php b/src/Module/Api/Mastodon/Tags/Unfollow.php index 163b65003b..f3fbad2e5a 100644 --- a/src/Module/Api/Mastodon/Tags/Unfollow.php +++ b/src/Module/Api/Mastodon/Tags/Unfollow.php @@ -44,7 +44,7 @@ class Unfollow extends BaseApi DBA::delete('search', $term); - $hashtag = new \Friendica\Object\Api\Mastodon\Tag($this->baseUrl, $term, [], false); + $hashtag = new \Friendica\Object\Api\Mastodon\Tag($this->baseUrl, $term, [], false); System::jsonExit($hashtag->toArray()); } } From 30929755238448e5c08fe1f0cb53f50d700c1451 Mon Sep 17 00:00:00 2001 From: Tobias Diekershoff Date: Mon, 28 Nov 2022 07:00:11 +0100 Subject: [PATCH 23/40] DE translation update THX MarekBenjamin --- view/lang/de/messages.po | 712 ++++++++++++++++++++------------------- view/lang/de/strings.php | 37 +- 2 files changed, 394 insertions(+), 355 deletions(-) diff --git a/view/lang/de/messages.po b/view/lang/de/messages.po index 7adfb1c1e4..8dba0d681c 100644 --- a/view/lang/de/messages.po +++ b/view/lang/de/messages.po @@ -24,6 +24,7 @@ # joe slam , 2020 # Johannes Schwab , 2015 # leberwurscht , 2012 +# Marek Bachmann, 2022 # marmor , 2012 # Martin Schmitt , 2012 # Matthias Moritz , 2012 @@ -49,9 +50,9 @@ msgid "" msgstr "" "Project-Id-Version: friendica\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-11-15 21:34+0000\n" +"POT-Creation-Date: 2022-11-27 00:36+0000\n" "PO-Revision-Date: 2011-05-05 10:19+0000\n" -"Last-Translator: Tobias Diekershoff , 2016-2022\n" +"Last-Translator: Marek Bachmann, 2022\n" "Language-Team: German (http://www.transifex.com/Friendica/friendica/language/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -59,41 +60,18 @@ msgstr "" "Language: de\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: mod/fbrowser.php:61 src/Content/Nav.php:195 src/Module/BaseProfile.php:64 -#: view/theme/frio/theme.php:239 -msgid "Photos" -msgstr "Bilder" - -#: mod/fbrowser.php:119 mod/fbrowser.php:146 mod/photos.php:999 -#: mod/photos.php:1100 src/Content/Conversation.php:389 -#: src/Module/Contact/Follow.php:171 src/Module/Contact/Revoke.php:109 -#: src/Module/Contact/Unfollow.php:126 src/Module/Post/Edit.php:165 -#: src/Module/Post/Tag/Remove.php:109 src/Module/Profile/RemoteFollow.php:134 -#: src/Module/Security/TwoFactor/SignOut.php:125 -msgid "Cancel" -msgstr "Abbrechen" - -#: mod/fbrowser.php:121 mod/fbrowser.php:148 -#: src/Module/Settings/Profile/Photo/Index.php:128 -msgid "Upload" -msgstr "Hochladen" - -#: mod/fbrowser.php:143 -msgid "Files" -msgstr "Dateien" - -#: mod/item.php:131 mod/item.php:135 +#: mod/item.php:129 mod/item.php:133 msgid "Unable to locate original post." msgstr "Konnte den Originalbeitrag nicht finden." -#: mod/item.php:181 mod/item.php:186 mod/item.php:870 mod/message.php:69 -#: mod/message.php:114 mod/notes.php:44 mod/photos.php:159 mod/photos.php:886 -#: src/Module/Attach.php:56 src/Module/BaseApi.php:94 +#: mod/item.php:179 mod/item.php:184 mod/item.php:855 mod/message.php:69 +#: mod/message.php:114 mod/notes.php:44 mod/photos.php:159 mod/photos.php:884 +#: src/Module/Attach.php:55 src/Module/BaseApi.php:94 #: src/Module/BaseNotifications.php:98 src/Module/BaseSettings.php:52 #: src/Module/Calendar/Event/API.php:88 src/Module/Calendar/Event/Form.php:84 #: src/Module/Calendar/Event/Show.php:54 src/Module/Calendar/Export.php:62 #: src/Module/Calendar/Show.php:64 src/Module/Contact/Advanced.php:60 -#: src/Module/Contact/Follow.php:86 src/Module/Contact/Follow.php:158 +#: src/Module/Contact/Follow.php:86 src/Module/Contact/Follow.php:160 #: src/Module/Contact/MatchInterests.php:86 #: src/Module/Contact/Suggestions.php:54 src/Module/Contact/Unfollow.php:66 #: src/Module/Contact/Unfollow.php:80 src/Module/Contact/Unfollow.php:112 @@ -103,9 +81,8 @@ msgstr "Konnte den Originalbeitrag nicht finden." #: src/Module/Notifications/Notification.php:76 #: src/Module/Notifications/Notification.php:107 #: src/Module/OStatus/Repair.php:60 src/Module/OStatus/Subscribe.php:66 -#: src/Module/Post/Edit.php:76 src/Module/Profile/Attachment/Upload.php:97 -#: src/Module/Profile/Common.php:55 src/Module/Profile/Contacts.php:55 -#: src/Module/Profile/Photos/Upload.php:108 src/Module/Profile/Schedule.php:39 +#: src/Module/Post/Edit.php:76 src/Module/Profile/Common.php:55 +#: src/Module/Profile/Contacts.php:55 src/Module/Profile/Schedule.php:39 #: src/Module/Profile/Schedule.php:56 src/Module/Profile/UnkMail.php:69 #: src/Module/Profile/UnkMail.php:121 src/Module/Profile/UnkMail.php:132 #: src/Module/Register.php:77 src/Module/Register.php:90 @@ -125,23 +102,23 @@ msgstr "Konnte den Originalbeitrag nicht finden." msgid "Permission denied." msgstr "Zugriff verweigert." -#: mod/item.php:337 mod/item.php:342 +#: mod/item.php:330 mod/item.php:335 msgid "Empty post discarded." msgstr "Leerer Beitrag wurde verworfen." -#: mod/item.php:680 +#: mod/item.php:673 msgid "Post updated." msgstr "Beitrag aktualisiert." -#: mod/item.php:690 mod/item.php:695 +#: mod/item.php:683 mod/item.php:688 msgid "Item wasn't stored." msgstr "Eintrag wurde nicht gespeichert" -#: mod/item.php:706 +#: mod/item.php:699 msgid "Item couldn't be fetched." msgstr "Eintrag konnte nicht geholt werden." -#: mod/item.php:846 src/Module/Admin/Themes/Details.php:39 +#: mod/item.php:831 src/Module/Admin/Themes/Details.php:39 #: src/Module/Admin/Themes/Index.php:59 src/Module/Debug/ItemBody.php:42 #: src/Module/Debug/ItemBody.php:57 src/Module/Item/Feed.php:80 msgid "Item not found." @@ -281,7 +258,7 @@ msgstr "\nDie Anmeldedaten sind die folgenden:\n\nAdresse der Seite: %1$s\nLogin msgid "Your password has been changed at %s" msgstr "Auf %s wurde dein Passwort geändert" -#: mod/message.php:46 mod/message.php:129 src/Content/Nav.php:289 +#: mod/message.php:46 mod/message.php:129 src/Content/Nav.php:285 msgid "New Message" msgstr "Neue Nachricht" @@ -307,7 +284,7 @@ msgstr "Konnte Nachrichten nicht abrufen." msgid "Discard" msgstr "Verwerfen" -#: mod/message.php:136 src/Content/Nav.php:286 view/theme/frio/theme.php:246 +#: mod/message.php:136 src/Content/Nav.php:282 view/theme/frio/theme.php:249 msgid "Messages" msgstr "Nachrichten" @@ -353,18 +330,18 @@ msgstr "Foto hochladen" msgid "Insert web link" msgstr "Einen Link einfügen" -#: mod/message.php:203 mod/message.php:360 mod/photos.php:1486 +#: mod/message.php:203 mod/message.php:360 mod/photos.php:1484 #: src/Content/Conversation.php:371 src/Content/Conversation.php:717 #: src/Module/Item/Compose.php:204 src/Module/Post/Edit.php:142 #: src/Module/Profile/UnkMail.php:155 src/Object/Post.php:537 msgid "Please wait" msgstr "Bitte warten" -#: mod/message.php:204 mod/message.php:359 mod/photos.php:916 -#: mod/photos.php:1020 mod/photos.php:1292 mod/photos.php:1333 -#: mod/photos.php:1389 mod/photos.php:1463 +#: mod/message.php:204 mod/message.php:359 mod/photos.php:914 +#: mod/photos.php:1018 mod/photos.php:1290 mod/photos.php:1331 +#: mod/photos.php:1387 mod/photos.php:1461 #: src/Module/Calendar/Event/Form.php:250 src/Module/Contact/Advanced.php:132 -#: src/Module/Contact/Profile.php:328 +#: src/Module/Contact/Profile.php:327 #: src/Module/Debug/ActivityPubConversion.php:140 #: src/Module/Debug/Babel.php:313 src/Module/Debug/Localtime.php:64 #: src/Module/Debug/Probe.php:54 src/Module/Debug/WebFinger.php:51 @@ -445,31 +422,34 @@ msgstr "Persönliche Notizen sind nur für dich sichtbar." msgid "Save" msgstr "Speichern" -#: mod/photos.php:68 mod/photos.php:139 mod/photos.php:793 +#: mod/photos.php:68 mod/photos.php:139 mod/photos.php:791 #: src/Model/Event.php:514 src/Model/Profile.php:234 #: src/Module/Calendar/Export.php:67 src/Module/Feed.php:72 #: src/Module/HCard.php:51 src/Module/Profile/Common.php:40 #: src/Module/Profile/Common.php:51 src/Module/Profile/Contacts.php:39 #: src/Module/Profile/Contacts.php:49 src/Module/Profile/Media.php:38 -#: src/Module/Profile/Photos/Upload.php:87 -#: src/Module/Profile/RemoteFollow.php:71 src/Module/Profile/Status.php:58 -#: src/Module/Register.php:267 +#: src/Module/Profile/Photos.php:77 src/Module/Profile/RemoteFollow.php:71 +#: src/Module/Profile/Status.php:58 src/Module/Register.php:267 msgid "User not found." msgstr "Benutzer nicht gefunden." #: mod/photos.php:107 src/Module/BaseProfile.php:67 +#: src/Module/Profile/Photos.php:169 msgid "Photo Albums" msgstr "Fotoalben" -#: mod/photos.php:108 mod/photos.php:1581 +#: mod/photos.php:108 src/Module/Profile/Photos.php:170 +#: src/Module/Profile/Photos.php:187 msgid "Recent Photos" msgstr "Neueste Fotos" -#: mod/photos.php:110 mod/photos.php:1068 mod/photos.php:1583 +#: mod/photos.php:110 mod/photos.php:1066 src/Module/Profile/Photos.php:172 +#: src/Module/Profile/Photos.php:189 msgid "Upload New Photos" msgstr "Neue Fotos hochladen" #: mod/photos.php:128 src/Module/BaseSettings.php:74 +#: src/Module/Profile/Photos.php:153 msgid "everybody" msgstr "jeder" @@ -493,219 +473,230 @@ msgstr "Album ist leer." msgid "Failed to delete the photo." msgstr "Das Foto konnte nicht gelöscht werden." -#: mod/photos.php:552 +#: mod/photos.php:551 msgid "a photo" msgstr "einem Foto" -#: mod/photos.php:552 +#: mod/photos.php:551 #, php-format msgid "%1$s was tagged in %2$s by %3$s" msgstr "%1$s wurde von %3$s in %2$s getaggt" -#: mod/photos.php:631 mod/photos.php:634 mod/photos.php:661 -#: src/Module/Profile/Photos/Upload.php:213 +#: mod/photos.php:630 mod/photos.php:633 mod/photos.php:660 +#: src/Module/Media/Photo/Upload.php:188 #: src/Module/Settings/Profile/Photo/Index.php:59 #, php-format msgid "Image exceeds size limit of %s" msgstr "Bildgröße überschreitet das Limit von %s" -#: mod/photos.php:637 +#: mod/photos.php:636 msgid "Image upload didn't complete, please try again" msgstr "Der Upload des Bildes war nicht vollständig. Bitte versuche es erneut." -#: mod/photos.php:640 +#: mod/photos.php:639 msgid "Image file is missing" msgstr "Bilddatei konnte nicht gefunden werden." -#: mod/photos.php:645 +#: mod/photos.php:644 msgid "" "Server can't accept new file upload at this time, please contact your " "administrator" msgstr "Der Server kann derzeit keine neuen Datei-Uploads akzeptieren. Bitte kontaktiere deinen Administrator." -#: mod/photos.php:669 +#: mod/photos.php:668 msgid "Image file is empty." msgstr "Bilddatei ist leer." -#: mod/photos.php:684 src/Module/Profile/Photos/Upload.php:179 -#: src/Module/Profile/Photos/Upload.php:180 +#: mod/photos.php:683 src/Module/Media/Photo/Upload.php:154 +#: src/Module/Media/Photo/Upload.php:155 #: src/Module/Settings/Profile/Photo/Index.php:68 msgid "Unable to process image." msgstr "Konnte das Bild nicht bearbeiten." -#: mod/photos.php:710 src/Module/Profile/Photos/Upload.php:231 +#: mod/photos.php:709 src/Module/Media/Photo/Upload.php:206 #: src/Module/Settings/Profile/Photo/Index.php:95 msgid "Image upload failed." msgstr "Hochladen des Bildes gescheitert." -#: mod/photos.php:797 src/Module/Conversation/Community.php:187 -#: src/Module/Directory.php:48 src/Module/Search/Index.php:64 +#: mod/photos.php:795 src/Module/Conversation/Community.php:187 +#: src/Module/Directory.php:48 src/Module/Profile/Photos.php:72 +#: src/Module/Search/Index.php:64 msgid "Public access denied." msgstr "Öffentlicher Zugriff verweigert." -#: mod/photos.php:802 +#: mod/photos.php:800 msgid "No photos selected" msgstr "Keine Bilder ausgewählt" -#: mod/photos.php:871 +#: mod/photos.php:869 src/Module/Profile/Photos.php:92 msgid "Access to this item is restricted." msgstr "Zugriff zu diesem Eintrag wurde eingeschränkt." -#: mod/photos.php:926 +#: mod/photos.php:924 msgid "Upload Photos" msgstr "Bilder hochladen" -#: mod/photos.php:930 mod/photos.php:1016 +#: mod/photos.php:928 mod/photos.php:1014 msgid "New album name: " msgstr "Name des neuen Albums: " -#: mod/photos.php:931 +#: mod/photos.php:929 msgid "or select existing album:" msgstr "oder wähle ein bestehendes Album:" -#: mod/photos.php:932 +#: mod/photos.php:930 msgid "Do not show a status post for this upload" msgstr "Keine Status-Mitteilung für diesen Beitrag anzeigen" -#: mod/photos.php:934 mod/photos.php:1288 src/Content/Conversation.php:373 -#: src/Module/Calendar/Event/Form.php:253 src/Module/Post/Edit.php:180 +#: mod/photos.php:932 mod/photos.php:1286 src/Content/Conversation.php:373 +#: src/Module/Calendar/Event/Form.php:253 src/Module/Post/Edit.php:179 msgid "Permissions" msgstr "Berechtigungen" -#: mod/photos.php:997 +#: mod/photos.php:995 msgid "Do you really want to delete this photo album and all its photos?" msgstr "Möchtest du wirklich dieses Foto-Album und all seine Foto löschen?" -#: mod/photos.php:998 mod/photos.php:1021 +#: mod/photos.php:996 mod/photos.php:1019 msgid "Delete Album" msgstr "Album löschen" -#: mod/photos.php:1025 +#: mod/photos.php:997 mod/photos.php:1098 src/Content/Conversation.php:389 +#: src/Module/Contact/Follow.php:173 src/Module/Contact/Revoke.php:109 +#: src/Module/Contact/Unfollow.php:126 +#: src/Module/Media/Attachment/Browser.php:78 +#: src/Module/Media/Photo/Browser.php:88 src/Module/Post/Edit.php:164 +#: src/Module/Post/Tag/Remove.php:109 src/Module/Profile/RemoteFollow.php:134 +#: src/Module/Security/TwoFactor/SignOut.php:125 +msgid "Cancel" +msgstr "Abbrechen" + +#: mod/photos.php:1023 msgid "Edit Album" msgstr "Album bearbeiten" -#: mod/photos.php:1026 +#: mod/photos.php:1024 msgid "Drop Album" msgstr "Album löschen" -#: mod/photos.php:1030 +#: mod/photos.php:1028 msgid "Show Newest First" msgstr "Zeige neueste zuerst" -#: mod/photos.php:1032 +#: mod/photos.php:1030 msgid "Show Oldest First" msgstr "Zeige älteste zuerst" -#: mod/photos.php:1053 mod/photos.php:1566 +#: mod/photos.php:1051 src/Module/Profile/Photos.php:140 msgid "View Photo" msgstr "Foto betrachten" -#: mod/photos.php:1086 +#: mod/photos.php:1084 msgid "Permission denied. Access to this item may be restricted." msgstr "Zugriff verweigert. Zugriff zu diesem Eintrag könnte eingeschränkt sein." -#: mod/photos.php:1088 +#: mod/photos.php:1086 msgid "Photo not available" msgstr "Foto nicht verfügbar" -#: mod/photos.php:1098 +#: mod/photos.php:1096 msgid "Do you really want to delete this photo?" msgstr "Möchtest du wirklich dieses Foto löschen?" -#: mod/photos.php:1099 mod/photos.php:1293 +#: mod/photos.php:1097 mod/photos.php:1291 msgid "Delete Photo" msgstr "Foto löschen" -#: mod/photos.php:1191 +#: mod/photos.php:1189 msgid "View photo" msgstr "Fotos ansehen" -#: mod/photos.php:1193 +#: mod/photos.php:1191 msgid "Edit photo" msgstr "Foto bearbeiten" -#: mod/photos.php:1194 +#: mod/photos.php:1192 msgid "Delete photo" msgstr "Foto löschen" -#: mod/photos.php:1195 +#: mod/photos.php:1193 msgid "Use as profile photo" msgstr "Als Profilbild verwenden" -#: mod/photos.php:1202 +#: mod/photos.php:1200 msgid "Private Photo" msgstr "Privates Foto" -#: mod/photos.php:1208 +#: mod/photos.php:1206 msgid "View Full Size" msgstr "Betrachte Originalgröße" -#: mod/photos.php:1261 +#: mod/photos.php:1259 msgid "Tags: " msgstr "Tags: " -#: mod/photos.php:1264 +#: mod/photos.php:1262 msgid "[Select tags to remove]" msgstr "[Zu entfernende Tags auswählen]" -#: mod/photos.php:1279 +#: mod/photos.php:1277 msgid "New album name" msgstr "Name des neuen Albums" -#: mod/photos.php:1280 +#: mod/photos.php:1278 msgid "Caption" msgstr "Bildunterschrift" -#: mod/photos.php:1281 +#: mod/photos.php:1279 msgid "Add a Tag" msgstr "Tag hinzufügen" -#: mod/photos.php:1281 +#: mod/photos.php:1279 msgid "" "Example: @bob, @Barbara_Jensen, @jim@example.com, #California, #camping" msgstr "Beispiel: @bob, @Barbara_Jensen, @jim@example.com, #California, #camping" -#: mod/photos.php:1282 +#: mod/photos.php:1280 msgid "Do not rotate" msgstr "Nicht rotieren" -#: mod/photos.php:1283 +#: mod/photos.php:1281 msgid "Rotate CW (right)" msgstr "Drehen US (rechts)" -#: mod/photos.php:1284 +#: mod/photos.php:1282 msgid "Rotate CCW (left)" msgstr "Drehen EUS (links)" -#: mod/photos.php:1330 mod/photos.php:1386 mod/photos.php:1460 +#: mod/photos.php:1328 mod/photos.php:1384 mod/photos.php:1458 #: src/Module/Contact.php:547 src/Module/Item/Compose.php:188 #: src/Object/Post.php:983 msgid "This is you" msgstr "Das bist du" -#: mod/photos.php:1332 mod/photos.php:1388 mod/photos.php:1462 +#: mod/photos.php:1330 mod/photos.php:1386 mod/photos.php:1460 #: src/Object/Post.php:531 src/Object/Post.php:985 msgid "Comment" msgstr "Kommentar" -#: mod/photos.php:1334 mod/photos.php:1390 mod/photos.php:1464 +#: mod/photos.php:1332 mod/photos.php:1388 mod/photos.php:1462 #: src/Content/Conversation.php:386 src/Module/Calendar/Event/Form.php:248 -#: src/Module/Item/Compose.php:199 src/Module/Post/Edit.php:163 +#: src/Module/Item/Compose.php:199 src/Module/Post/Edit.php:162 #: src/Object/Post.php:997 msgid "Preview" msgstr "Vorschau" -#: mod/photos.php:1335 src/Content/Conversation.php:341 +#: mod/photos.php:1333 src/Content/Conversation.php:341 #: src/Module/Post/Edit.php:127 src/Object/Post.php:987 msgid "Loading..." msgstr "lädt..." -#: mod/photos.php:1421 src/Content/Conversation.php:633 +#: mod/photos.php:1419 src/Content/Conversation.php:633 #: src/Object/Post.php:255 msgid "Select" msgstr "Auswählen" -#: mod/photos.php:1422 src/Content/Conversation.php:634 +#: mod/photos.php:1420 src/Content/Conversation.php:634 #: src/Module/Moderation/Users/Active.php:136 #: src/Module/Moderation/Users/Blocked.php:136 #: src/Module/Moderation/Users/Index.php:151 @@ -713,30 +704,26 @@ msgstr "Auswählen" msgid "Delete" msgstr "Löschen" -#: mod/photos.php:1483 src/Object/Post.php:378 +#: mod/photos.php:1481 src/Object/Post.php:378 msgid "Like" msgstr "Mag ich" -#: mod/photos.php:1484 src/Object/Post.php:378 +#: mod/photos.php:1482 src/Object/Post.php:378 msgid "I like this (toggle)" msgstr "Ich mag das (toggle)" -#: mod/photos.php:1485 src/Object/Post.php:379 +#: mod/photos.php:1483 src/Object/Post.php:379 msgid "Dislike" msgstr "Mag ich nicht" -#: mod/photos.php:1487 src/Object/Post.php:379 +#: mod/photos.php:1485 src/Object/Post.php:379 msgid "I don't like this (toggle)" msgstr "Ich mag das nicht (toggle)" -#: mod/photos.php:1509 +#: mod/photos.php:1507 msgid "Map" msgstr "Karte" -#: mod/photos.php:1572 -msgid "View Album" -msgstr "Album betrachten" - #: src/App.php:493 msgid "No system theme config value set." msgstr "Es wurde kein Konfigurationswert für das systemweite Theme gesetzt." @@ -745,17 +732,17 @@ msgstr "Es wurde kein Konfigurationswert für das systemweite Theme gesetzt." msgid "Apologies but the website is unavailable at the moment." msgstr "Entschuldigung, aber die Webseite ist derzeit nicht erreichbar." -#: src/App/Page.php:282 +#: src/App/Page.php:246 msgid "Delete this item?" msgstr "Diesen Beitrag löschen?" -#: src/App/Page.php:283 +#: src/App/Page.php:247 msgid "" "Block this author? They won't be able to follow you nor see your public " "posts, and you won't be able to see their posts and their notifications." msgstr "Soll dieser Autor geblockt werden? Sie werden nicht in der Lage sein, dir zu folgen oder deine öffentlichen Beiträge zu sehen. Außerdem wirst du nicht in der Lage sein ihre Beiträge und Benachrichtigungen zu lesen." -#: src/App/Page.php:353 +#: src/App/Page.php:317 msgid "toggle mobile" msgstr "mobile Ansicht umschalten" @@ -1269,27 +1256,27 @@ msgid "attach file" msgstr "Datei anhängen" #: src/Content/Conversation.php:346 src/Module/Item/Compose.php:190 -#: src/Module/Post/Edit.php:169 src/Object/Post.php:988 +#: src/Module/Post/Edit.php:168 src/Object/Post.php:988 msgid "Bold" msgstr "Fett" #: src/Content/Conversation.php:347 src/Module/Item/Compose.php:191 -#: src/Module/Post/Edit.php:170 src/Object/Post.php:989 +#: src/Module/Post/Edit.php:169 src/Object/Post.php:989 msgid "Italic" msgstr "Kursiv" #: src/Content/Conversation.php:348 src/Module/Item/Compose.php:192 -#: src/Module/Post/Edit.php:171 src/Object/Post.php:990 +#: src/Module/Post/Edit.php:170 src/Object/Post.php:990 msgid "Underline" msgstr "Unterstrichen" #: src/Content/Conversation.php:349 src/Module/Item/Compose.php:193 -#: src/Module/Post/Edit.php:172 src/Object/Post.php:991 +#: src/Module/Post/Edit.php:171 src/Object/Post.php:991 msgid "Quote" msgstr "Zitat" #: src/Content/Conversation.php:350 src/Module/Item/Compose.php:194 -#: src/Module/Post/Edit.php:173 src/Object/Post.php:992 +#: src/Module/Post/Edit.php:172 src/Object/Post.php:992 msgid "Code" msgstr "Code" @@ -1299,12 +1286,12 @@ msgid "Image" msgstr "Bild" #: src/Content/Conversation.php:352 src/Module/Item/Compose.php:196 -#: src/Module/Post/Edit.php:174 src/Object/Post.php:994 +#: src/Module/Post/Edit.php:173 src/Object/Post.php:994 msgid "Link" msgstr "Link" #: src/Content/Conversation.php:353 src/Module/Item/Compose.php:197 -#: src/Module/Post/Edit.php:175 src/Object/Post.php:995 +#: src/Module/Post/Edit.php:174 src/Object/Post.php:995 msgid "Link or Media" msgstr "Link oder Mediendatei" @@ -1330,12 +1317,12 @@ msgid "clear location" msgstr "Ort löschen" #: src/Content/Conversation.php:360 src/Module/Item/Compose.php:205 -#: src/Module/Post/Edit.php:155 +#: src/Module/Post/Edit.php:154 msgid "Set title" msgstr "Titel setzen" #: src/Content/Conversation.php:362 src/Module/Item/Compose.php:206 -#: src/Module/Post/Edit.php:157 +#: src/Module/Post/Edit.php:156 msgid "Categories (comma-separated list)" msgstr "Kategorien (kommasepariert)" @@ -1353,16 +1340,16 @@ msgstr "Öffentlicher Beitrag" #: src/Content/Conversation.php:396 src/Content/Widget/VCard.php:113 #: src/Model/Profile.php:465 src/Module/Admin/Logs/View.php:93 -#: src/Module/Post/Edit.php:178 +#: src/Module/Post/Edit.php:177 msgid "Message" msgstr "Nachricht" -#: src/Content/Conversation.php:397 src/Module/Post/Edit.php:179 -#: src/Module/Settings/TwoFactor/Trusted.php:139 +#: src/Content/Conversation.php:397 src/Module/Post/Edit.php:178 +#: src/Module/Settings/TwoFactor/Trusted.php:140 msgid "Browser" msgstr "Browser" -#: src/Content/Conversation.php:399 src/Module/Post/Edit.php:182 +#: src/Content/Conversation.php:399 src/Module/Post/Edit.php:181 msgid "Open Compose page" msgstr "Composer Seite öffnen" @@ -1592,7 +1579,7 @@ msgstr "weniger anzeigen" msgid "show more" msgstr "mehr anzeigen" -#: src/Content/Item.php:294 src/Model/Item.php:2871 +#: src/Content/Item.php:294 src/Model/Item.php:2911 msgid "event" msgstr "Veranstaltung" @@ -1601,7 +1588,7 @@ msgstr "Veranstaltung" msgid "status" msgstr "Status" -#: src/Content/Item.php:303 src/Model/Item.php:2873 +#: src/Content/Item.php:303 src/Model/Item.php:2913 #: src/Module/Post/Tag/Add.php:123 msgid "photo" msgstr "Foto" @@ -1611,7 +1598,7 @@ msgstr "Foto" msgid "%1$s tagged %2$s's %3$s with %4$s" msgstr "%1$s hat %2$ss %3$s mit %4$s getaggt" -#: src/Content/Item.php:386 view/theme/frio/theme.php:267 +#: src/Content/Item.php:386 view/theme/frio/theme.php:270 msgid "Follow Thread" msgstr "Folge der Unterhaltung" @@ -1645,7 +1632,7 @@ msgid "Send PM" msgstr "Private Nachricht senden" #: src/Content/Item.php:393 src/Module/Contact.php:401 -#: src/Module/Contact/Profile.php:349 src/Module/Contact/Profile.php:468 +#: src/Module/Contact/Profile.php:348 src/Module/Contact/Profile.php:467 #: src/Module/Moderation/Blocklist/Contact.php:116 #: src/Module/Moderation/Users/Active.php:137 #: src/Module/Moderation/Users/Index.php:152 @@ -1653,7 +1640,7 @@ msgid "Block" msgstr "Sperren" #: src/Content/Item.php:394 src/Module/Contact.php:402 -#: src/Module/Contact/Profile.php:350 src/Module/Contact/Profile.php:476 +#: src/Module/Contact/Profile.php:349 src/Module/Contact/Profile.php:475 #: src/Module/Notifications/Introductions.php:134 #: src/Module/Notifications/Introductions.php:206 #: src/Module/Notifications/Notification.php:89 @@ -1666,7 +1653,7 @@ msgstr "Sprachen" #: src/Content/Item.php:403 src/Content/Widget.php:80 #: src/Model/Contact.php:1192 src/Model/Contact.php:1203 -#: src/Module/Contact/Follow.php:165 view/theme/vier/theme.php:198 +#: src/Module/Contact/Follow.php:167 view/theme/vier/theme.php:198 msgid "Connect/Follow" msgstr "Verbinden/Folgen" @@ -1704,19 +1691,19 @@ msgid "Sign in" msgstr "Anmelden" #: src/Content/Nav.php:193 src/Module/BaseProfile.php:56 -#: src/Module/Contact.php:436 src/Module/Contact/Profile.php:381 +#: src/Module/Contact.php:436 src/Module/Contact/Profile.php:380 #: src/Module/Settings/TwoFactor/Index.php:119 view/theme/frio/theme.php:237 msgid "Status" msgstr "Status" -#: src/Content/Nav.php:193 src/Content/Nav.php:276 +#: src/Content/Nav.php:193 src/Content/Nav.php:272 #: view/theme/frio/theme.php:237 msgid "Your posts and conversations" msgstr "Deine Beiträge und Unterhaltungen" #: src/Content/Nav.php:194 src/Module/BaseProfile.php:48 #: src/Module/BaseSettings.php:100 src/Module/Contact.php:460 -#: src/Module/Contact/Profile.php:383 src/Module/Profile/Profile.php:240 +#: src/Module/Contact/Profile.php:382 src/Module/Profile/Profile.php:240 #: src/Module/Welcome.php:57 view/theme/frio/theme.php:238 msgid "Profile" msgstr "Profil" @@ -1725,29 +1712,34 @@ msgstr "Profil" msgid "Your profile page" msgstr "Deine Profilseite" -#: src/Content/Nav.php:195 view/theme/frio/theme.php:239 +#: src/Content/Nav.php:195 src/Module/BaseProfile.php:64 +#: src/Module/Media/Photo/Browser.php:74 view/theme/frio/theme.php:242 +msgid "Photos" +msgstr "Bilder" + +#: src/Content/Nav.php:195 view/theme/frio/theme.php:242 msgid "Your photos" msgstr "Deine Fotos" #: src/Content/Nav.php:196 src/Module/BaseProfile.php:72 #: src/Module/BaseProfile.php:75 src/Module/Contact.php:452 -#: view/theme/frio/theme.php:240 +#: view/theme/frio/theme.php:243 msgid "Media" msgstr "Medien" -#: src/Content/Nav.php:196 view/theme/frio/theme.php:240 +#: src/Content/Nav.php:196 view/theme/frio/theme.php:243 msgid "Your postings with media" msgstr "Deine Beiträge die Medien beinhalten" -#: src/Content/Nav.php:197 src/Content/Nav.php:261 +#: src/Content/Nav.php:197 src/Content/Nav.php:257 #: src/Module/BaseProfile.php:84 src/Module/BaseProfile.php:87 #: src/Module/BaseProfile.php:95 src/Module/BaseProfile.php:98 -#: src/Module/Settings/Display.php:205 view/theme/frio/theme.php:241 -#: view/theme/frio/theme.php:245 +#: src/Module/Settings/Display.php:205 view/theme/frio/theme.php:244 +#: view/theme/frio/theme.php:248 msgid "Calendar" msgstr "Kalender" -#: src/Content/Nav.php:197 view/theme/frio/theme.php:241 +#: src/Content/Nav.php:197 view/theme/frio/theme.php:244 msgid "Your calendar" msgstr "Dein Kalender" @@ -1759,7 +1751,7 @@ msgstr "Persönliche Notizen" msgid "Your personal notes" msgstr "Deine persönlichen Notizen" -#: src/Content/Nav.php:215 src/Content/Nav.php:276 +#: src/Content/Nav.php:215 src/Content/Nav.php:272 msgid "Home" msgstr "Pinnwand" @@ -1777,10 +1769,10 @@ msgid "Create an account" msgstr "Nutzerkonto erstellen" #: src/Content/Nav.php:225 src/Module/Help.php:67 -#: src/Module/Settings/TwoFactor/AppSpecific.php:128 +#: src/Module/Settings/TwoFactor/AppSpecific.php:129 #: src/Module/Settings/TwoFactor/Index.php:118 -#: src/Module/Settings/TwoFactor/Recovery.php:106 -#: src/Module/Settings/TwoFactor/Verify.php:145 view/theme/vier/theme.php:243 +#: src/Module/Settings/TwoFactor/Recovery.php:107 +#: src/Module/Settings/TwoFactor/Verify.php:146 view/theme/vier/theme.php:243 msgid "Help" msgstr "Hilfe" @@ -1814,124 +1806,124 @@ msgstr "Volltext" msgid "Tags" msgstr "Tags" -#: src/Content/Nav.php:238 src/Content/Nav.php:297 +#: src/Content/Nav.php:238 src/Content/Nav.php:293 #: src/Content/Text/HTML.php:899 src/Module/BaseProfile.php:125 #: src/Module/BaseProfile.php:128 src/Module/Contact.php:373 -#: src/Module/Contact.php:467 view/theme/frio/theme.php:248 +#: src/Module/Contact.php:467 view/theme/frio/theme.php:251 msgid "Contacts" msgstr "Kontakte" -#: src/Content/Nav.php:257 +#: src/Content/Nav.php:253 msgid "Community" msgstr "Gemeinschaft" -#: src/Content/Nav.php:257 +#: src/Content/Nav.php:253 msgid "Conversations on this and other servers" msgstr "Unterhaltungen auf diesem und anderen Servern" -#: src/Content/Nav.php:264 +#: src/Content/Nav.php:260 msgid "Directory" msgstr "Verzeichnis" -#: src/Content/Nav.php:264 +#: src/Content/Nav.php:260 msgid "People directory" msgstr "Nutzerverzeichnis" -#: src/Content/Nav.php:266 src/Module/BaseAdmin.php:85 +#: src/Content/Nav.php:262 src/Module/BaseAdmin.php:85 #: src/Module/BaseModeration.php:108 msgid "Information" msgstr "Information" -#: src/Content/Nav.php:266 +#: src/Content/Nav.php:262 msgid "Information about this friendica instance" msgstr "Informationen zu dieser Friendica-Instanz" -#: src/Content/Nav.php:269 src/Module/Admin/Tos.php:76 +#: src/Content/Nav.php:265 src/Module/Admin/Tos.php:76 #: src/Module/BaseAdmin.php:95 src/Module/Register.php:176 #: src/Module/Tos.php:87 msgid "Terms of Service" msgstr "Nutzungsbedingungen" -#: src/Content/Nav.php:269 +#: src/Content/Nav.php:265 msgid "Terms of Service of this Friendica instance" msgstr "Die Nutzungsbedingungen dieser Friendica-Instanz" -#: src/Content/Nav.php:274 view/theme/frio/theme.php:244 +#: src/Content/Nav.php:270 view/theme/frio/theme.php:247 msgid "Network" msgstr "Netzwerk" -#: src/Content/Nav.php:274 view/theme/frio/theme.php:244 +#: src/Content/Nav.php:270 view/theme/frio/theme.php:247 msgid "Conversations from your friends" msgstr "Unterhaltungen Deiner Kontakte" -#: src/Content/Nav.php:280 +#: src/Content/Nav.php:276 msgid "Introductions" msgstr "Kontaktanfragen" -#: src/Content/Nav.php:280 +#: src/Content/Nav.php:276 msgid "Friend Requests" msgstr "Kontaktanfragen" -#: src/Content/Nav.php:281 src/Module/BaseNotifications.php:149 +#: src/Content/Nav.php:277 src/Module/BaseNotifications.php:149 #: src/Module/Notifications/Introductions.php:75 msgid "Notifications" msgstr "Benachrichtigungen" -#: src/Content/Nav.php:282 +#: src/Content/Nav.php:278 msgid "See all notifications" msgstr "Alle Benachrichtigungen anzeigen" -#: src/Content/Nav.php:283 src/Module/Settings/Connectors.php:242 +#: src/Content/Nav.php:279 src/Module/Settings/Connectors.php:242 msgid "Mark as seen" msgstr "Als gelesen markieren" -#: src/Content/Nav.php:283 +#: src/Content/Nav.php:279 msgid "Mark all system notifications as seen" msgstr "Markiere alle Systembenachrichtigungen als gelesen" -#: src/Content/Nav.php:286 view/theme/frio/theme.php:246 +#: src/Content/Nav.php:282 view/theme/frio/theme.php:249 msgid "Private mail" msgstr "Private E-Mail" -#: src/Content/Nav.php:287 +#: src/Content/Nav.php:283 msgid "Inbox" msgstr "Eingang" -#: src/Content/Nav.php:288 +#: src/Content/Nav.php:284 msgid "Outbox" msgstr "Ausgang" -#: src/Content/Nav.php:292 +#: src/Content/Nav.php:288 msgid "Accounts" msgstr "Nutzerkonten" -#: src/Content/Nav.php:292 +#: src/Content/Nav.php:288 msgid "Manage other pages" msgstr "Andere Seiten verwalten" -#: src/Content/Nav.php:295 src/Module/Admin/Addons/Details.php:114 +#: src/Content/Nav.php:291 src/Module/Admin/Addons/Details.php:114 #: src/Module/Admin/Themes/Details.php:93 src/Module/BaseSettings.php:170 -#: src/Module/Welcome.php:52 view/theme/frio/theme.php:247 +#: src/Module/Welcome.php:52 view/theme/frio/theme.php:250 msgid "Settings" msgstr "Einstellungen" -#: src/Content/Nav.php:295 view/theme/frio/theme.php:247 +#: src/Content/Nav.php:291 view/theme/frio/theme.php:250 msgid "Account settings" msgstr "Kontoeinstellungen" -#: src/Content/Nav.php:297 view/theme/frio/theme.php:248 +#: src/Content/Nav.php:293 view/theme/frio/theme.php:251 msgid "Manage/edit friends and contacts" msgstr "Freunde und Kontakte verwalten/bearbeiten" -#: src/Content/Nav.php:302 src/Module/BaseAdmin.php:119 +#: src/Content/Nav.php:298 src/Module/BaseAdmin.php:119 msgid "Admin" msgstr "Administration" -#: src/Content/Nav.php:302 +#: src/Content/Nav.php:298 msgid "Site setup and configuration" msgstr "Einstellungen der Seite und Konfiguration" -#: src/Content/Nav.php:303 src/Module/BaseModeration.php:127 +#: src/Content/Nav.php:299 src/Module/BaseModeration.php:127 #: src/Module/Moderation/Blocklist/Contact.php:110 #: src/Module/Moderation/Blocklist/Server/Add.php:119 #: src/Module/Moderation/Blocklist/Server/Import.php:115 @@ -1945,15 +1937,15 @@ msgstr "Einstellungen der Seite und Konfiguration" msgid "Moderation" msgstr "Moderation" -#: src/Content/Nav.php:303 +#: src/Content/Nav.php:299 msgid "Content and user moderation" msgstr "Moderation von Nutzern und Inhalten" -#: src/Content/Nav.php:306 +#: src/Content/Nav.php:302 msgid "Navigation" msgstr "Navigation" -#: src/Content/Nav.php:306 +#: src/Content/Nav.php:302 msgid "Site map" msgstr "Sitemap" @@ -1991,8 +1983,8 @@ msgstr "Bild/Foto" msgid "%2$s %3$s" msgstr "%2$s%3$s" -#: src/Content/Text/BBCode.php:1245 src/Model/Item.php:3493 -#: src/Model/Item.php:3499 src/Model/Item.php:3500 +#: src/Content/Text/BBCode.php:1245 src/Model/Item.php:3533 +#: src/Model/Item.php:3539 src/Model/Item.php:3540 msgid "Link to source" msgstr "Link zum Originalbeitrag" @@ -2025,7 +2017,7 @@ msgid "The end" msgstr "Das Ende" #: src/Content/Text/HTML.php:882 src/Content/Widget/VCard.php:109 -#: src/Model/Profile.php:459 src/Module/Contact/Profile.php:428 +#: src/Model/Profile.php:459 src/Module/Contact/Profile.php:427 msgid "Follow" msgstr "Folge" @@ -2211,19 +2203,19 @@ msgid "More Trending Tags" msgstr "mehr Trending Tags" #: src/Content/Widget/VCard.php:102 src/Model/Profile.php:378 -#: src/Module/Contact/Profile.php:372 src/Module/Profile/Profile.php:175 +#: src/Module/Contact/Profile.php:371 src/Module/Profile/Profile.php:175 msgid "XMPP:" msgstr "XMPP:" #: src/Content/Widget/VCard.php:103 src/Model/Profile.php:379 -#: src/Module/Contact/Profile.php:374 src/Module/Profile/Profile.php:179 +#: src/Module/Contact/Profile.php:373 src/Module/Profile/Profile.php:179 msgid "Matrix:" msgstr "Matrix:" #: src/Content/Widget/VCard.php:104 src/Model/Event.php:82 #: src/Model/Event.php:109 src/Model/Event.php:471 src/Model/Event.php:992 #: src/Model/Profile.php:373 src/Module/Calendar/Event/Form.php:239 -#: src/Module/Contact/Profile.php:370 src/Module/Directory.php:147 +#: src/Module/Contact/Profile.php:369 src/Module/Directory.php:147 #: src/Module/Notifications/Introductions.php:187 #: src/Module/Profile/Profile.php:193 msgid "Location:" @@ -2236,7 +2228,7 @@ msgstr "Netzwerk:" #: src/Content/Widget/VCard.php:111 src/Model/Contact.php:1193 #: src/Model/Contact.php:1204 src/Model/Profile.php:461 -#: src/Module/Contact/Profile.php:420 +#: src/Module/Contact/Profile.php:419 msgid "Unfollow" msgstr "Entfolgen" @@ -2287,7 +2279,7 @@ msgstr "Ausgenommen:" msgid "CC: email addresses" msgstr "Cc: E-Mail-Addressen" -#: src/Core/ACL.php:327 src/Module/Post/Edit.php:158 +#: src/Core/ACL.php:327 src/Module/Post/Edit.php:157 msgid "Example: bob@example.com, mary@example.com" msgstr "Z.B.: bob@example.com, mary@example.com" @@ -3151,66 +3143,66 @@ msgstr "Gruppenname:" msgid "Edit groups" msgstr "Gruppen bearbeiten" -#: src/Model/Item.php:1983 +#: src/Model/Item.php:2023 #, php-format msgid "Detected languages in this post:\\n%s" msgstr "Erkannte Sprachen in diesem Beitrag:\\n%s" -#: src/Model/Item.php:2875 +#: src/Model/Item.php:2915 msgid "activity" msgstr "Aktivität" -#: src/Model/Item.php:2877 +#: src/Model/Item.php:2917 msgid "comment" msgstr "Kommentar" -#: src/Model/Item.php:2880 +#: src/Model/Item.php:2920 msgid "post" msgstr "Beitrag" -#: src/Model/Item.php:3021 +#: src/Model/Item.php:3061 #, php-format msgid "Content warning: %s" msgstr "Inhaltswarnung: %s" -#: src/Model/Item.php:3405 +#: src/Model/Item.php:3445 msgid "bytes" msgstr "Byte" -#: src/Model/Item.php:3436 +#: src/Model/Item.php:3476 #, php-format msgid "%2$s (%3$d%%, %1$d vote)" msgid_plural "%2$s (%3$d%%, %1$d votes)" msgstr[0] "%2$s (%3$d%%, %1$d Stimme)" msgstr[1] "%2$s (%3$d%%, %1$d Stimmen)" -#: src/Model/Item.php:3438 +#: src/Model/Item.php:3478 #, php-format msgid "%2$s (%1$d vote)" msgid_plural "%2$s (%1$d votes)" msgstr[0] "%2$s (%1$d Stimme)" msgstr[1] "%2$s (%1$d Stimmen)" -#: src/Model/Item.php:3443 +#: src/Model/Item.php:3483 #, php-format msgid "%d voter. Poll end: %s" msgid_plural "%d voters. Poll end: %s" msgstr[0] "%d Stimme, Abstimmung endet: %s" msgstr[1] "%d Stimmen, Abstimmung endet: %s" -#: src/Model/Item.php:3445 +#: src/Model/Item.php:3485 #, php-format msgid "%d voter." msgid_plural "%d voters." msgstr[0] "%d Stimme." msgstr[1] "%d Stimmen." -#: src/Model/Item.php:3447 +#: src/Model/Item.php:3487 #, php-format msgid "Poll end: %s" msgstr "Abstimmung endet: %s" -#: src/Model/Item.php:3481 src/Model/Item.php:3482 +#: src/Model/Item.php:3521 src/Model/Item.php:3522 msgid "View on separate page" msgstr "Auf separater Seite ansehen" @@ -3218,7 +3210,7 @@ msgstr "Auf separater Seite ansehen" msgid "[no subject]" msgstr "[kein Betreff]" -#: src/Model/Photo.php:1086 src/Module/Profile/Photos/Upload.php:223 +#: src/Model/Photo.php:1139 src/Module/Media/Photo/Upload.php:198 msgid "Wall Photos" msgstr "Pinnwand-Bilder" @@ -3236,7 +3228,7 @@ msgstr "Profilbild ändern" msgid "Homepage:" msgstr "Homepage:" -#: src/Model/Profile.php:377 src/Module/Contact/Profile.php:376 +#: src/Model/Profile.php:377 src/Module/Contact/Profile.php:375 #: src/Module/Notifications/Introductions.php:189 msgid "About:" msgstr "Über:" @@ -3326,7 +3318,7 @@ msgstr "Dislikes:" msgid "Title/Description:" msgstr "Titel/Beschreibung:" -#: src/Model/Profile.php:1019 src/Module/Admin/Summary.php:215 +#: src/Model/Profile.php:1019 src/Module/Admin/Summary.php:217 #: src/Module/Moderation/Summary.php:77 msgid "Summary" msgstr "Zusammenfassung" @@ -3640,7 +3632,7 @@ msgstr "Einschalten" #: src/Module/Admin/Addons/Index.php:67 src/Module/Admin/Federation.php:202 #: src/Module/Admin/Logs/Settings.php:79 src/Module/Admin/Logs/View.php:84 #: src/Module/Admin/Queue.php:72 src/Module/Admin/Site.php:431 -#: src/Module/Admin/Storage.php:138 src/Module/Admin/Summary.php:214 +#: src/Module/Admin/Storage.php:138 src/Module/Admin/Summary.php:216 #: src/Module/Admin/Themes/Details.php:90 #: src/Module/Admin/Themes/Index.php:111 src/Module/Admin/Tos.php:75 #: src/Module/Moderation/Users/Create.php:61 @@ -4311,8 +4303,9 @@ msgstr "Maximale Bildgröße" #: src/Module/Admin/Site.php:470 msgid "" "Maximum size in bytes of uploaded images. Default is 0, which means no " +"limits. Be aware that this setting does not affect server-side upload " "limits." -msgstr "Maximale Uploadgröße von Bildern in Bytes. Standard ist 0, d.h. ohne Limit." +msgstr "Maximal akzeptierte Dateigröße in Bytes eines hochzuladenden Bilds. Der Standard ist 0 und entspricht keiner Beschränkung der Dateigröße. Beachte, dass diese Einstellung nicht die serverseitigen Beschränkungen von Dateigrößen beeinflusst." #: src/Module/Admin/Site.php:471 msgid "Maximum image length" @@ -5148,11 +5141,11 @@ msgstr "Nachrichten-Warteschlangen" msgid "Server Settings" msgstr "Servereinstellungen" -#: src/Module/Admin/Summary.php:217 +#: src/Module/Admin/Summary.php:219 msgid "Version" msgstr "Version" -#: src/Module/Admin/Summary.php:221 +#: src/Module/Admin/Summary.php:223 msgid "Active addons" msgstr "Aktivierte Addons" @@ -5293,7 +5286,7 @@ msgstr "Keine Applikationen installiert." msgid "Applications" msgstr "Anwendungen" -#: src/Module/Attach.php:50 src/Module/Attach.php:62 +#: src/Module/Attach.php:49 src/Module/Attach.php:61 msgid "Item was not found." msgstr "Beitrag konnte nicht gefunden werden." @@ -5430,7 +5423,7 @@ msgid "Profile Details" msgstr "Profildetails" #: src/Module/BaseProfile.php:59 src/Module/Contact.php:447 -#: src/Module/Contact/Follow.php:190 src/Module/Contact/Unfollow.php:138 +#: src/Module/Contact/Follow.php:192 src/Module/Contact/Unfollow.php:138 msgid "Status Messages and Posts" msgstr "Statusnachrichten und Beiträge" @@ -5553,7 +5546,7 @@ msgstr "Veranstaltungsbeginn:" #: src/Module/Moderation/Item/Delete.php:67 src/Module/Register.php:148 #: src/Module/Security/TwoFactor/Verify.php:101 #: src/Module/Settings/TwoFactor/Index.php:140 -#: src/Module/Settings/TwoFactor/Verify.php:154 +#: src/Module/Settings/TwoFactor/Verify.php:155 msgid "Required" msgstr "Benötigt" @@ -5685,16 +5678,16 @@ msgstr "Ergebnisse für: %s" msgid "Update" msgstr "Aktualisierungen" -#: src/Module/Contact.php:401 src/Module/Contact/Profile.php:349 -#: src/Module/Contact/Profile.php:468 +#: src/Module/Contact.php:401 src/Module/Contact/Profile.php:348 +#: src/Module/Contact/Profile.php:467 #: src/Module/Moderation/Blocklist/Contact.php:117 #: src/Module/Moderation/Users/Blocked.php:138 #: src/Module/Moderation/Users/Index.php:154 msgid "Unblock" msgstr "Entsperren" -#: src/Module/Contact.php:402 src/Module/Contact/Profile.php:350 -#: src/Module/Contact/Profile.php:476 +#: src/Module/Contact.php:402 src/Module/Contact/Profile.php:349 +#: src/Module/Contact/Profile.php:475 msgid "Unignore" msgstr "Ignorieren aufheben" @@ -5742,7 +5735,7 @@ msgstr "Ausstehende ausgehende Kontaktanfrage" msgid "Pending incoming contact request" msgstr "Ausstehende eingehende Kontaktanfrage" -#: src/Module/Contact.php:555 src/Module/Contact/Profile.php:335 +#: src/Module/Contact.php:555 src/Module/Contact/Profile.php:334 #, php-format msgid "Visit %s's profile [%s]" msgstr "Besuche %ss Profil [%s]" @@ -5866,36 +5859,36 @@ msgstr[1] "Kontakte (%s)" msgid "Access denied." msgstr "Zugriff verweigert." -#: src/Module/Contact/Follow.php:102 src/Module/Contact/Unfollow.php:125 +#: src/Module/Contact/Follow.php:104 src/Module/Contact/Unfollow.php:125 #: src/Module/Profile/RemoteFollow.php:133 msgid "Submit Request" msgstr "Anfrage abschicken" -#: src/Module/Contact/Follow.php:113 +#: src/Module/Contact/Follow.php:115 msgid "You already added this contact." msgstr "Du hast den Kontakt bereits hinzugefügt." -#: src/Module/Contact/Follow.php:128 +#: src/Module/Contact/Follow.php:130 msgid "The network type couldn't be detected. Contact can't be added." msgstr "Der Netzwerktyp wurde nicht erkannt. Der Kontakt kann nicht hinzugefügt werden." -#: src/Module/Contact/Follow.php:136 +#: src/Module/Contact/Follow.php:138 msgid "Diaspora support isn't enabled. Contact can't be added." msgstr "Diaspora-Unterstützung ist nicht aktiviert. Der Kontakt kann nicht zugefügt werden." -#: src/Module/Contact/Follow.php:141 +#: src/Module/Contact/Follow.php:143 msgid "OStatus support is disabled. Contact can't be added." msgstr "OStatus-Unterstützung ist nicht aktiviert. Der Kontakt kann nicht zugefügt werden." -#: src/Module/Contact/Follow.php:166 src/Module/Profile/RemoteFollow.php:132 +#: src/Module/Contact/Follow.php:168 src/Module/Profile/RemoteFollow.php:132 msgid "Please answer the following:" msgstr "Bitte beantworte folgendes:" -#: src/Module/Contact/Follow.php:167 src/Module/Contact/Unfollow.php:123 +#: src/Module/Contact/Follow.php:169 src/Module/Contact/Unfollow.php:123 msgid "Your Identity Address:" msgstr "Adresse Deines Profils:" -#: src/Module/Contact/Follow.php:168 src/Module/Contact/Profile.php:366 +#: src/Module/Contact/Follow.php:170 src/Module/Contact/Profile.php:365 #: src/Module/Contact/Unfollow.php:129 #: src/Module/Moderation/Blocklist/Contact.php:133 #: src/Module/Notifications/Introductions.php:129 @@ -5903,30 +5896,30 @@ msgstr "Adresse Deines Profils:" msgid "Profile URL" msgstr "Profil URL" -#: src/Module/Contact/Follow.php:169 src/Module/Contact/Profile.php:378 +#: src/Module/Contact/Follow.php:171 src/Module/Contact/Profile.php:377 #: src/Module/Notifications/Introductions.php:191 #: src/Module/Profile/Profile.php:206 msgid "Tags:" msgstr "Tags:" -#: src/Module/Contact/Follow.php:180 +#: src/Module/Contact/Follow.php:182 #, php-format msgid "%s knows you" msgstr "%skennt dich" -#: src/Module/Contact/Follow.php:181 +#: src/Module/Contact/Follow.php:183 msgid "Add a personal note:" msgstr "Eine persönliche Notiz beifügen:" -#: src/Module/Contact/Follow.php:219 +#: src/Module/Contact/Follow.php:221 msgid "The contact could not be added." msgstr "Der Kontakt konnte nicht hinzugefügt werden." #: src/Module/Contact/MatchInterests.php:94 -#: src/Module/Profile/Attachment/Upload.php:80 -#: src/Module/Profile/Attachment/Upload.php:102 -#: src/Module/Profile/Photos/Upload.php:113 -#: src/Module/Profile/Photos/Upload.php:162 +#: src/Module/Media/Attachment/Upload.php:80 +#: src/Module/Media/Attachment/Upload.php:85 +#: src/Module/Media/Photo/Upload.php:83 src/Module/Media/Photo/Upload.php:88 +#: src/Module/Media/Photo/Upload.php:137 msgid "Invalid request." msgstr "Ungültige Anfrage" @@ -5989,7 +5982,7 @@ msgstr "(Aktualisierung war nicht erfolgreich)" msgid "(Update was successful)" msgstr "(Aktualisierung war erfolgreich)" -#: src/Module/Contact/Profile.php:255 src/Module/Contact/Profile.php:439 +#: src/Module/Contact/Profile.php:255 src/Module/Contact/Profile.php:438 msgid "Suggest friends" msgstr "Kontakte vorschlagen" @@ -6025,144 +6018,140 @@ msgstr "Schlüsselwörter abrufen" msgid "Fetch information and keywords" msgstr "Beziehe Information und Schlüsselworte" -#: src/Module/Contact/Profile.php:287 src/Module/Contact/Profile.php:293 -#: src/Module/Contact/Profile.php:298 src/Module/Contact/Profile.php:304 +#: src/Module/Contact/Profile.php:287 src/Module/Contact/Profile.php:292 +#: src/Module/Contact/Profile.php:297 src/Module/Contact/Profile.php:303 msgid "No mirroring" msgstr "Kein Spiegeln" -#: src/Module/Contact/Profile.php:288 -msgid "Mirror as forwarded posting" -msgstr "Spiegeln als weitergeleitete Beiträge" - -#: src/Module/Contact/Profile.php:289 src/Module/Contact/Profile.php:299 -#: src/Module/Contact/Profile.php:305 +#: src/Module/Contact/Profile.php:288 src/Module/Contact/Profile.php:298 +#: src/Module/Contact/Profile.php:304 msgid "Mirror as my own posting" msgstr "Spiegeln als meine eigenen Beiträge" -#: src/Module/Contact/Profile.php:294 src/Module/Contact/Profile.php:300 +#: src/Module/Contact/Profile.php:293 src/Module/Contact/Profile.php:299 msgid "Native reshare" msgstr "Natives Teilen" -#: src/Module/Contact/Profile.php:317 +#: src/Module/Contact/Profile.php:316 msgid "Contact Information / Notes" msgstr "Kontakt-Informationen / -Notizen" -#: src/Module/Contact/Profile.php:318 +#: src/Module/Contact/Profile.php:317 msgid "Contact Settings" msgstr "Kontakteinstellungen" -#: src/Module/Contact/Profile.php:326 +#: src/Module/Contact/Profile.php:325 msgid "Contact" msgstr "Kontakt" -#: src/Module/Contact/Profile.php:330 +#: src/Module/Contact/Profile.php:329 msgid "Their personal note" msgstr "Die persönliche Mitteilung" -#: src/Module/Contact/Profile.php:332 +#: src/Module/Contact/Profile.php:331 msgid "Edit contact notes" msgstr "Notizen zum Kontakt bearbeiten" -#: src/Module/Contact/Profile.php:336 +#: src/Module/Contact/Profile.php:335 msgid "Block/Unblock contact" msgstr "Kontakt blockieren/freischalten" -#: src/Module/Contact/Profile.php:337 +#: src/Module/Contact/Profile.php:336 msgid "Ignore contact" msgstr "Ignoriere den Kontakt" -#: src/Module/Contact/Profile.php:338 +#: src/Module/Contact/Profile.php:337 msgid "View conversations" msgstr "Unterhaltungen anzeigen" -#: src/Module/Contact/Profile.php:343 +#: src/Module/Contact/Profile.php:342 msgid "Last update:" msgstr "Letzte Aktualisierung: " -#: src/Module/Contact/Profile.php:345 +#: src/Module/Contact/Profile.php:344 msgid "Update public posts" msgstr "Öffentliche Beiträge aktualisieren" -#: src/Module/Contact/Profile.php:347 src/Module/Contact/Profile.php:449 +#: src/Module/Contact/Profile.php:346 src/Module/Contact/Profile.php:448 msgid "Update now" msgstr "Jetzt aktualisieren" -#: src/Module/Contact/Profile.php:354 +#: src/Module/Contact/Profile.php:353 msgid "Currently blocked" msgstr "Derzeit geblockt" -#: src/Module/Contact/Profile.php:355 +#: src/Module/Contact/Profile.php:354 msgid "Currently ignored" msgstr "Derzeit ignoriert" -#: src/Module/Contact/Profile.php:356 +#: src/Module/Contact/Profile.php:355 msgid "Currently archived" msgstr "Momentan archiviert" -#: src/Module/Contact/Profile.php:357 +#: src/Module/Contact/Profile.php:356 msgid "Awaiting connection acknowledge" msgstr "Bedarf der Bestätigung des Kontakts" -#: src/Module/Contact/Profile.php:358 +#: src/Module/Contact/Profile.php:357 #: src/Module/Notifications/Introductions.php:192 msgid "Hide this contact from others" msgstr "Verbirg diesen Kontakt vor Anderen" -#: src/Module/Contact/Profile.php:358 +#: src/Module/Contact/Profile.php:357 msgid "" "Replies/likes to your public posts may still be visible" msgstr "Antworten/Likes auf deine öffentlichen Beiträge könnten weiterhin sichtbar sein" -#: src/Module/Contact/Profile.php:359 +#: src/Module/Contact/Profile.php:358 msgid "Notification for new posts" msgstr "Benachrichtigung bei neuen Beiträgen" -#: src/Module/Contact/Profile.php:359 +#: src/Module/Contact/Profile.php:358 msgid "Send a notification of every new post of this contact" msgstr "Sende eine Benachrichtigung, wann immer dieser Kontakt einen neuen Beitrag schreibt." -#: src/Module/Contact/Profile.php:361 +#: src/Module/Contact/Profile.php:360 msgid "Keyword Deny List" msgstr "Liste der gesperrten Schlüsselwörter" -#: src/Module/Contact/Profile.php:361 +#: src/Module/Contact/Profile.php:360 msgid "" "Comma separated list of keywords that should not be converted to hashtags, " "when \"Fetch information and keywords\" is selected" msgstr "Komma-Separierte Liste mit Schlüsselworten, die nicht in Hashtags konvertiert werden, wenn \"Beziehe Information und Schlüsselworte\" aktiviert wurde" -#: src/Module/Contact/Profile.php:379 +#: src/Module/Contact/Profile.php:378 #: src/Module/Settings/TwoFactor/Index.php:139 msgid "Actions" msgstr "Aktionen" -#: src/Module/Contact/Profile.php:387 +#: src/Module/Contact/Profile.php:386 msgid "Mirror postings from this contact" msgstr "Spiegle Beiträge dieses Kontakts" -#: src/Module/Contact/Profile.php:389 +#: src/Module/Contact/Profile.php:388 msgid "" "Mark this contact as remote_self, this will cause friendica to repost new " "entries from this contact." msgstr "Markiere diesen Kontakt als remote_self (entferntes Konto), dies veranlasst Friendica, alle Top-Level Beiträge dieses Kontakts an all Deine Kontakte zu senden (spiegeln)." -#: src/Module/Contact/Profile.php:459 +#: src/Module/Contact/Profile.php:458 msgid "Refetch contact data" msgstr "Kontaktdaten neu laden" -#: src/Module/Contact/Profile.php:470 +#: src/Module/Contact/Profile.php:469 msgid "Toggle Blocked status" msgstr "Geblockt-Status ein-/ausschalten" -#: src/Module/Contact/Profile.php:478 +#: src/Module/Contact/Profile.php:477 msgid "Toggle Ignored status" msgstr "Ignoriert-Status ein-/ausschalten" -#: src/Module/Contact/Profile.php:485 src/Module/Contact/Revoke.php:106 +#: src/Module/Contact/Profile.php:484 src/Module/Contact/Revoke.php:106 msgid "Revoke Follow" msgstr "Folgen widerrufen" -#: src/Module/Contact/Profile.php:487 +#: src/Module/Contact/Profile.php:486 msgid "Revoke the follow from this contact" msgstr "Widerruft das Folgen dieses Kontaktes" @@ -6195,7 +6184,7 @@ msgstr "Willst du das Folgen dieses Kontakt wirklich widerrufen? Dies kann nicht #: src/Module/Contact/Revoke.php:108 #: src/Module/Notifications/Introductions.php:144 #: src/Module/OAuth/Acknowledge.php:53 src/Module/Register.php:130 -#: src/Module/Settings/TwoFactor/Trusted.php:125 +#: src/Module/Settings/TwoFactor/Trusted.php:126 msgid "Yes" msgstr "Ja" @@ -7121,11 +7110,22 @@ msgid "" "Theme Customization settings." msgstr "Wenn du magst, kannst du unter den Benutzerdefinierte Theme-Einstellungen einstellen, dass diese Seite immer geöffnet wird, wenn du den \"Neuer Beitrag\" Button verwendest." -#: src/Module/Item/Display.php:135 src/Module/Item/Display.php:252 -#: src/Module/Update/Display.php:55 +#: src/Module/Item/Display.php:135 src/Module/Update/Display.php:55 msgid "The requested item doesn't exist or has been deleted." msgstr "Der angeforderte Beitrag existiert nicht oder wurde gelöscht." +#: src/Module/Item/Display.php:253 +msgid "" +"Unfortunately, the requested conversation isn't available to you.

\n" +"

Possible reasons include:

\n" +"
    \n" +"\t
  • The top-level post isn't visible.
  • \n" +"\t
  • The top-level post was deleted.
  • \n" +"\t
  • The node has blocked the top-level author or the author of the shared post.
  • \n" +"\t
  • You have ignored or blocked the top-level author or the author of the shared post.
  • \n" +"

" +msgstr "Leider ist die angeforderte Konversation nicht verfügbar für dich.

\n

Mögliche Gründe können sein:

\n\t
  • Der übergeordnete Beitrag ist nicht sichtbar.
  • \n\t
  • Der übergeordnete Beitrag wurde gelöscht
  • \n\t
  • Die Instanz hat den Autor des übergeordneten Beitrags oder den Nutzer, der den Beitrag geteilt hat, geblockt.
  • \n
  • Du hast den Autor des übergeordneten Beitrags oder den Nutzer, der den Beitrag geteilt hat, geblockt oder ignorierst ihn.
  • \n

      " + #: src/Module/Item/Feed.php:86 msgid "The feed for this item is unavailable." msgstr "Der Feed für diesen Beitrag ist nicht verfügbar." @@ -7149,6 +7149,38 @@ msgstr "Diese Friendica Instanz befindet sich derzeit im Wartungsmodus, entweder msgid "A Decentralized Social Network" msgstr "Ein dezentrales Soziales Netzwerk" +#: src/Module/Media/Attachment/Browser.php:58 +#: src/Module/Media/Photo/Browser.php:59 +msgid "You need to be logged in to access this page." +msgstr "Du musst angemeldet sein, um auf diese Seite zuzugreifen. " + +#: src/Module/Media/Attachment/Browser.php:75 +msgid "Files" +msgstr "Dateien" + +#: src/Module/Media/Attachment/Browser.php:80 +#: src/Module/Media/Photo/Browser.php:90 +#: src/Module/Settings/Profile/Photo/Index.php:128 +msgid "Upload" +msgstr "Hochladen" + +#: src/Module/Media/Attachment/Upload.php:100 +msgid "Sorry, maybe your upload is bigger than the PHP configuration allows" +msgstr "Entschuldige, die Datei scheint größer zu sein, als es die PHP-Konfiguration erlaubt." + +#: src/Module/Media/Attachment/Upload.php:100 +msgid "Or - did you try to upload an empty file?" +msgstr "Oder - hast du versucht, eine leere Datei hochzuladen?" + +#: src/Module/Media/Attachment/Upload.php:107 +#, php-format +msgid "File exceeds size limit of %s" +msgstr "Die Datei ist größer als das erlaubte Limit von %s" + +#: src/Module/Media/Attachment/Upload.php:117 +msgid "File upload failed." +msgstr "Hochladen der Datei fehlgeschlagen." + #: src/Module/Moderation/BaseUsers.php:72 msgid "List of all users" msgstr "Liste aller Benutzerkonten" @@ -7880,7 +7912,7 @@ msgstr "Behauptet, dich zu kennen: " #: src/Module/Notifications/Introductions.php:144 #: src/Module/OAuth/Acknowledge.php:54 src/Module/Register.php:131 -#: src/Module/Settings/TwoFactor/Trusted.php:125 +#: src/Module/Settings/TwoFactor/Trusted.php:126 msgid "No" msgstr "Nein" @@ -8112,11 +8144,11 @@ msgstr "Ungültige externe Ressource mit der URL %s" msgid "Invalid photo with id %s." msgstr "Fehlerhaftes Foto mit der ID %s." -#: src/Module/Post/Edit.php:82 src/Module/Post/Edit.php:94 +#: src/Module/Post/Edit.php:82 src/Module/Post/Edit.php:96 msgid "Post not found." msgstr "Beitrag nicht gefunden." -#: src/Module/Post/Edit.php:101 +#: src/Module/Post/Edit.php:102 msgid "Edit post" msgstr "Beitrag bearbeiten" @@ -8149,31 +8181,18 @@ msgid "Select a tag to remove: " msgstr "Wähle ein Tag zum Entfernen aus: " #: src/Module/Post/Tag/Remove.php:108 src/Module/Settings/Delegation.php:178 -#: src/Module/Settings/TwoFactor/Trusted.php:143 +#: src/Module/Settings/TwoFactor/Trusted.php:144 msgid "Remove" msgstr "Entfernen" -#: src/Module/Profile/Attachment/Upload.php:117 -msgid "Sorry, maybe your upload is bigger than the PHP configuration allows" -msgstr "Entschuldige, die Datei scheint größer zu sein, als es die PHP-Konfiguration erlaubt." - -#: src/Module/Profile/Attachment/Upload.php:117 -msgid "Or - did you try to upload an empty file?" -msgstr "Oder - hast du versucht, eine leere Datei hochzuladen?" - -#: src/Module/Profile/Attachment/Upload.php:124 -#, php-format -msgid "File exceeds size limit of %s" -msgstr "Die Datei ist größer als das erlaubte Limit von %s" - -#: src/Module/Profile/Attachment/Upload.php:134 -msgid "File upload failed." -msgstr "Hochladen der Datei fehlgeschlagen." - #: src/Module/Profile/Contacts.php:119 msgid "No contacts." msgstr "Keine Kontakte." +#: src/Module/Profile/Photos.php:146 +msgid "View Album" +msgstr "Album betrachten" + #: src/Module/Profile/Profile.php:81 msgid "Profile not found." msgstr "Profil nicht gefunden." @@ -8480,15 +8499,20 @@ msgstr "Versenden der E-Mail fehlgeschlagen. Hier sind Deine Account-Details:\n\ msgid "Registration successful." msgstr "Registrierung erfolgreich." -#: src/Module/Register.php:356 src/Module/Register.php:363 +#: src/Module/Register.php:357 src/Module/Register.php:364 +#: src/Module/Register.php:374 msgid "Your registration can not be processed." msgstr "Deine Registrierung konnte nicht verarbeitet werden." -#: src/Module/Register.php:362 +#: src/Module/Register.php:363 msgid "You have to leave a request note for the admin." msgstr "Du musst eine Nachricht für den Administrator als Begründung deiner Anfrage hinterlegen." -#: src/Module/Register.php:387 +#: src/Module/Register.php:373 +msgid "An internal error occured." +msgstr "Ein interner Fehler ist aufgetreten. " + +#: src/Module/Register.php:395 msgid "Your registration is pending approval by the site owner." msgstr "Deine Registrierung muss noch vom Betreiber der Seite freigegeben werden." @@ -8649,7 +8673,7 @@ msgstr "Verbleibende Wiederherstellungscodes: %d" #: src/Module/Security/TwoFactor/Recovery.php:80 #: src/Module/Security/TwoFactor/Verify.php:77 -#: src/Module/Settings/TwoFactor/Verify.php:94 +#: src/Module/Settings/TwoFactor/Verify.php:95 msgid "Invalid code, please retry." msgstr "Ungültiger Code, bitte erneut versuchen." @@ -8734,7 +8758,7 @@ msgid "" msgstr "Wenn du keinen Zugriff auf deinen Authentifikationscode hast, kannst du einen Zwei-Faktor Wiederherstellungsschlüssel verwenden." #: src/Module/Security/TwoFactor/Verify.php:101 -#: src/Module/Settings/TwoFactor/Verify.php:154 +#: src/Module/Settings/TwoFactor/Verify.php:155 msgid "Please enter a code from your authentication app" msgstr "Bitte gebe einen Code aus Ihrer Authentifizierungs-App ein" @@ -9883,82 +9907,82 @@ msgstr "Dein Konto wird endgültig gelöscht. Es gibt keine Möglichkeit, es wie msgid "Please enter your password for verification:" msgstr "Bitte gib dein Passwort zur Verifikation ein:" -#: src/Module/Settings/TwoFactor/AppSpecific.php:65 -#: src/Module/Settings/TwoFactor/Recovery.php:63 -#: src/Module/Settings/TwoFactor/Trusted.php:66 -#: src/Module/Settings/TwoFactor/Verify.php:68 +#: src/Module/Settings/TwoFactor/AppSpecific.php:66 +#: src/Module/Settings/TwoFactor/Recovery.php:64 +#: src/Module/Settings/TwoFactor/Trusted.php:67 +#: src/Module/Settings/TwoFactor/Verify.php:69 msgid "Please enter your password to access this page." msgstr "Bitte gib dein Passwort ein, um auf diese Seite zuzugreifen." -#: src/Module/Settings/TwoFactor/AppSpecific.php:83 +#: src/Module/Settings/TwoFactor/AppSpecific.php:84 msgid "App-specific password generation failed: The description is empty." msgstr "Die Erzeugung des App spezifischen Passworts ist fehlgeschlagen. Die Beschreibung ist leer." -#: src/Module/Settings/TwoFactor/AppSpecific.php:86 +#: src/Module/Settings/TwoFactor/AppSpecific.php:87 msgid "" "App-specific password generation failed: This description already exists." msgstr "Die Erzeugung des App spezifischen Passworts ist fehlgeschlagen. Die Beschreibung existiert bereits." -#: src/Module/Settings/TwoFactor/AppSpecific.php:90 +#: src/Module/Settings/TwoFactor/AppSpecific.php:91 msgid "New app-specific password generated." msgstr "Neues App spezifisches Passwort erzeugt." -#: src/Module/Settings/TwoFactor/AppSpecific.php:96 +#: src/Module/Settings/TwoFactor/AppSpecific.php:97 msgid "App-specific passwords successfully revoked." msgstr "App spezifische Passwörter erfolgreich widerrufen." -#: src/Module/Settings/TwoFactor/AppSpecific.php:106 +#: src/Module/Settings/TwoFactor/AppSpecific.php:107 msgid "App-specific password successfully revoked." msgstr "App spezifisches Passwort erfolgreich widerrufen." -#: src/Module/Settings/TwoFactor/AppSpecific.php:127 +#: src/Module/Settings/TwoFactor/AppSpecific.php:128 msgid "Two-factor app-specific passwords" msgstr "Zwei-Faktor App spezifische Passwörter." -#: src/Module/Settings/TwoFactor/AppSpecific.php:129 +#: src/Module/Settings/TwoFactor/AppSpecific.php:130 msgid "" "

      App-specific passwords are randomly generated passwords used instead your" " regular password to authenticate your account on third-party applications " "that don't support two-factor authentication.

      " msgstr "

      App spezifische Passwörter sind zufällig generierte Passwörter die anstelle des regulären Passworts zur Anmeldung mit Client Anwendungen verwendet werden, wenn diese Anwendungen die Zwei-Faktor-Authentifizierung nicht unterstützen.

      " -#: src/Module/Settings/TwoFactor/AppSpecific.php:130 +#: src/Module/Settings/TwoFactor/AppSpecific.php:131 msgid "" "Make sure to copy your new app-specific password now. You won’t be able to " "see it again!" msgstr "Das neue App spezifische Passwort muss jetzt übertragen werden. Später wirst du es nicht mehr einsehen können!" -#: src/Module/Settings/TwoFactor/AppSpecific.php:133 +#: src/Module/Settings/TwoFactor/AppSpecific.php:134 msgid "Description" msgstr "Beschreibung" -#: src/Module/Settings/TwoFactor/AppSpecific.php:134 +#: src/Module/Settings/TwoFactor/AppSpecific.php:135 msgid "Last Used" msgstr "Zuletzt verwendet" -#: src/Module/Settings/TwoFactor/AppSpecific.php:135 +#: src/Module/Settings/TwoFactor/AppSpecific.php:136 msgid "Revoke" msgstr "Widerrufen" -#: src/Module/Settings/TwoFactor/AppSpecific.php:136 +#: src/Module/Settings/TwoFactor/AppSpecific.php:137 msgid "Revoke All" msgstr "Alle widerrufen" -#: src/Module/Settings/TwoFactor/AppSpecific.php:139 +#: src/Module/Settings/TwoFactor/AppSpecific.php:140 msgid "" "When you generate a new app-specific password, you must use it right away, " "it will be shown to you once after you generate it." msgstr "Wenn du eine neues App spezifisches Passwort erstellst, musst du es sofort verwenden. Es wird dir nur ein einziges Mal nach der Erstellung angezeigt." -#: src/Module/Settings/TwoFactor/AppSpecific.php:140 +#: src/Module/Settings/TwoFactor/AppSpecific.php:141 msgid "Generate new app-specific password" msgstr "Neues App spezifisches Passwort erstellen" -#: src/Module/Settings/TwoFactor/AppSpecific.php:141 +#: src/Module/Settings/TwoFactor/AppSpecific.php:142 msgid "Friendiqa on my Fairphone 2..." msgstr "Friendiqa auf meinem Fairphone 2" -#: src/Module/Settings/TwoFactor/AppSpecific.php:142 +#: src/Module/Settings/TwoFactor/AppSpecific.php:143 msgid "Generate" msgstr "Erstellen" @@ -10054,15 +10078,15 @@ msgstr "Vertrauenswürdige Browser verwalten" msgid "Finish app configuration" msgstr "Beende die App-Konfiguration" -#: src/Module/Settings/TwoFactor/Recovery.php:79 +#: src/Module/Settings/TwoFactor/Recovery.php:80 msgid "New recovery codes successfully generated." msgstr "Neue Wiederherstellungscodes erfolgreich generiert." -#: src/Module/Settings/TwoFactor/Recovery.php:105 +#: src/Module/Settings/TwoFactor/Recovery.php:106 msgid "Two-factor recovery codes" msgstr "Zwei-Faktor-Wiederherstellungscodes" -#: src/Module/Settings/TwoFactor/Recovery.php:107 +#: src/Module/Settings/TwoFactor/Recovery.php:108 msgid "" "

      Recovery codes can be used to access your account in the event you lose " "access to your device and cannot receive two-factor authentication " @@ -10071,68 +10095,68 @@ msgid "" "account.

      " msgstr "

      Wiederherstellungscodes können verwendet werden, um auf dein Konto zuzugreifen, falls du den Zugriff auf dein Gerät verlieren und keine Zwei-Faktor-Authentifizierungscodes erhalten kannst.

      Bewahre diese an einem sicheren Ort auf! Wenn du dein Gerät verlierst und nicht über die Wiederherstellungscodes verfügst, verlierst du den Zugriff auf dein Konto.

      " -#: src/Module/Settings/TwoFactor/Recovery.php:109 +#: src/Module/Settings/TwoFactor/Recovery.php:110 msgid "" "When you generate new recovery codes, you must copy the new codes. Your old " "codes won’t work anymore." msgstr "Wenn du neue Wiederherstellungscodes generierst, mußt du die neuen Codes kopieren. Deine alten Codes funktionieren nicht mehr." -#: src/Module/Settings/TwoFactor/Recovery.php:110 +#: src/Module/Settings/TwoFactor/Recovery.php:111 msgid "Generate new recovery codes" msgstr "Generiere neue Wiederherstellungscodes" -#: src/Module/Settings/TwoFactor/Recovery.php:112 +#: src/Module/Settings/TwoFactor/Recovery.php:113 msgid "Next: Verification" msgstr "Weiter: Überprüfung" -#: src/Module/Settings/TwoFactor/Trusted.php:83 +#: src/Module/Settings/TwoFactor/Trusted.php:84 msgid "Trusted browsers successfully removed." msgstr "Die vertrauenswürdigen Browser wurden erfolgreich entfernt." -#: src/Module/Settings/TwoFactor/Trusted.php:93 +#: src/Module/Settings/TwoFactor/Trusted.php:94 msgid "Trusted browser successfully removed." msgstr "Der vertrauenswürdige Browser erfolgreich entfernt." -#: src/Module/Settings/TwoFactor/Trusted.php:135 +#: src/Module/Settings/TwoFactor/Trusted.php:136 msgid "Two-factor Trusted Browsers" msgstr "Zwei-Faktor vertrauenswürdige Browser" -#: src/Module/Settings/TwoFactor/Trusted.php:136 +#: src/Module/Settings/TwoFactor/Trusted.php:137 msgid "" "Trusted browsers are individual browsers you chose to skip two-factor " "authentication to access Friendica. Please use this feature sparingly, as it" " can negate the benefit of two-factor authentication." msgstr "Vertrauenswürdige Browser sind spezielle Browser für die du entscheidest, dass die Zwei-Faktor Authentifikation übersprungen werden soll. Bitte verwende diese Option sparsam, da sie die Vorteile der 2FA aufhebt." -#: src/Module/Settings/TwoFactor/Trusted.php:137 +#: src/Module/Settings/TwoFactor/Trusted.php:138 msgid "Device" msgstr "Gerät" -#: src/Module/Settings/TwoFactor/Trusted.php:138 +#: src/Module/Settings/TwoFactor/Trusted.php:139 msgid "OS" msgstr "OS" -#: src/Module/Settings/TwoFactor/Trusted.php:140 +#: src/Module/Settings/TwoFactor/Trusted.php:141 msgid "Trusted" msgstr "Vertrauenswürdig" -#: src/Module/Settings/TwoFactor/Trusted.php:141 +#: src/Module/Settings/TwoFactor/Trusted.php:142 msgid "Created At" msgstr "Erstellt am" -#: src/Module/Settings/TwoFactor/Trusted.php:142 +#: src/Module/Settings/TwoFactor/Trusted.php:143 msgid "Last Use" msgstr "Zuletzt verwendet" -#: src/Module/Settings/TwoFactor/Trusted.php:144 +#: src/Module/Settings/TwoFactor/Trusted.php:145 msgid "Remove All" msgstr "Alle entfernen" -#: src/Module/Settings/TwoFactor/Verify.php:90 +#: src/Module/Settings/TwoFactor/Verify.php:91 msgid "Two-factor authentication successfully activated." msgstr "Zwei-Faktor-Authentifizierung erfolgreich aktiviert." -#: src/Module/Settings/TwoFactor/Verify.php:124 +#: src/Module/Settings/TwoFactor/Verify.php:125 #, php-format msgid "" "

      Or you can submit the authentication settings manually:

      \n" @@ -10152,24 +10176,24 @@ msgid "" "" msgstr "

      Oder du kannst die Authentifizierungseinstellungen manuell übermitteln:

      \n
      \n\tVerursacher\n\t
      %s
      \n\t
      Kontoname
      \n\t
      %s
      \n\t
      Geheimer Schlüssel
      \n\t
      %s
      \n\t
      Typ
      \n\t
      Zeitbasiert
      \n\t
      Anzahl an Ziffern
      \n\t
      6
      \n\t
      Hashing-Algorithmus
      \n\t
      SHA-1
      \n
      " -#: src/Module/Settings/TwoFactor/Verify.php:144 +#: src/Module/Settings/TwoFactor/Verify.php:145 msgid "Two-factor code verification" msgstr "Überprüfung des Zwei-Faktor-Codes" -#: src/Module/Settings/TwoFactor/Verify.php:146 +#: src/Module/Settings/TwoFactor/Verify.php:147 msgid "" "

      Please scan this QR Code with your authenticator app and submit the " "provided code.

      " msgstr "

      Bitte scanne diesen QR-Code mit deiner Authentifikator-App und übermittele den bereitgestellten Code.

      " -#: src/Module/Settings/TwoFactor/Verify.php:148 +#: src/Module/Settings/TwoFactor/Verify.php:149 #, php-format msgid "" "

      Or you can open the following URL in your mobile device:

      %s

      " msgstr "

      Oder du kannst die folgende URL in deinem Mobilgerät öffnen:

      %s

      " -#: src/Module/Settings/TwoFactor/Verify.php:155 +#: src/Module/Settings/TwoFactor/Verify.php:156 msgid "Verify code and enable two-factor authentication" msgstr "Überprüfe den Code und aktiviere die Zwei-Faktor-Authentifizierung" diff --git a/view/lang/de/strings.php b/view/lang/de/strings.php index bcc2427981..3195eee043 100644 --- a/view/lang/de/strings.php +++ b/view/lang/de/strings.php @@ -5,10 +5,6 @@ function string_plural_select_de($n){ $n = intval($n); return intval($n != 1); }} -$a->strings['Photos'] = 'Bilder'; -$a->strings['Cancel'] = 'Abbrechen'; -$a->strings['Upload'] = 'Hochladen'; -$a->strings['Files'] = 'Dateien'; $a->strings['Unable to locate original post.'] = 'Konnte den Originalbeitrag nicht finden.'; $a->strings['Permission denied.'] = 'Zugriff verweigert.'; $a->strings['Empty post discarded.'] = 'Leerer Beitrag wurde verworfen.'; @@ -168,6 +164,7 @@ $a->strings['Do not show a status post for this upload'] = 'Keine Status-Mitteil $a->strings['Permissions'] = 'Berechtigungen'; $a->strings['Do you really want to delete this photo album and all its photos?'] = 'Möchtest du wirklich dieses Foto-Album und all seine Foto löschen?'; $a->strings['Delete Album'] = 'Album löschen'; +$a->strings['Cancel'] = 'Abbrechen'; $a->strings['Edit Album'] = 'Album bearbeiten'; $a->strings['Drop Album'] = 'Album löschen'; $a->strings['Show Newest First'] = 'Zeige neueste zuerst'; @@ -203,7 +200,6 @@ $a->strings['I like this (toggle)'] = 'Ich mag das (toggle)'; $a->strings['Dislike'] = 'Mag ich nicht'; $a->strings['I don\'t like this (toggle)'] = 'Ich mag das nicht (toggle)'; $a->strings['Map'] = 'Karte'; -$a->strings['View Album'] = 'Album betrachten'; $a->strings['No system theme config value set.'] = 'Es wurde kein Konfigurationswert für das systemweite Theme gesetzt.'; $a->strings['Apologies but the website is unavailable at the moment.'] = 'Entschuldigung, aber die Webseite ist derzeit nicht erreichbar.'; $a->strings['Delete this item?'] = 'Diesen Beitrag löschen?'; @@ -420,6 +416,7 @@ $a->strings['Status'] = 'Status'; $a->strings['Your posts and conversations'] = 'Deine Beiträge und Unterhaltungen'; $a->strings['Profile'] = 'Profil'; $a->strings['Your profile page'] = 'Deine Profilseite'; +$a->strings['Photos'] = 'Bilder'; $a->strings['Your photos'] = 'Deine Fotos'; $a->strings['Media'] = 'Medien'; $a->strings['Your postings with media'] = 'Deine Beiträge die Medien beinhalten'; @@ -1150,7 +1147,7 @@ $a->strings['Displays the menu entry for the Help pages from the navigation menu $a->strings['Single user instance'] = 'Ein-Nutzer Instanz'; $a->strings['Make this instance multi-user or single-user for the named user'] = 'Bestimmt, ob es sich bei dieser Instanz um eine Installation mit nur einen Nutzer oder mit mehreren Nutzern handelt.'; $a->strings['Maximum image size'] = 'Maximale Bildgröße'; -$a->strings['Maximum size in bytes of uploaded images. Default is 0, which means no limits.'] = 'Maximale Uploadgröße von Bildern in Bytes. Standard ist 0, d.h. ohne Limit.'; +$a->strings['Maximum size in bytes of uploaded images. Default is 0, which means no limits. Be aware that this setting does not affect server-side upload limits.'] = 'Maximal akzeptierte Dateigröße in Bytes eines hochzuladenden Bilds. Der Standard ist 0 und entspricht keiner Beschränkung der Dateigröße. Beachte, dass diese Einstellung nicht die serverseitigen Beschränkungen von Dateigrößen beeinflusst.'; $a->strings['Maximum image length'] = 'Maximale Bildlänge'; $a->strings['Maximum length in pixels of the longest side of uploaded images. Default is -1, which means no limits.'] = 'Maximale Länge in Pixeln der längsten Seite eines hochgeladenen Bildes. Grundeinstellung ist -1, was keine Einschränkung bedeutet.'; $a->strings['JPEG image quality'] = 'Qualität des JPEG Bildes'; @@ -1527,7 +1524,6 @@ $a->strings['Fetch information'] = 'Beziehe Information'; $a->strings['Fetch keywords'] = 'Schlüsselwörter abrufen'; $a->strings['Fetch information and keywords'] = 'Beziehe Information und Schlüsselworte'; $a->strings['No mirroring'] = 'Kein Spiegeln'; -$a->strings['Mirror as forwarded posting'] = 'Spiegeln als weitergeleitete Beiträge'; $a->strings['Mirror as my own posting'] = 'Spiegeln als meine eigenen Beiträge'; $a->strings['Native reshare'] = 'Natives Teilen'; $a->strings['Contact Information / Notes'] = 'Kontakt-Informationen / -Notizen'; @@ -1781,11 +1777,32 @@ $a->strings['Location services are unavailable on your device'] = 'Ortungsdienst $a->strings['Location services are disabled. Please check the website\'s permissions on your device'] = 'Ortungsdienste sind deaktiviert. Bitte überprüfe die Berechtigungen der Website auf deinem Gerät'; $a->strings['You can make this page always open when you use the New Post button in the Theme Customization settings.'] = 'Wenn du magst, kannst du unter den Benutzerdefinierte Theme-Einstellungen einstellen, dass diese Seite immer geöffnet wird, wenn du den "Neuer Beitrag" Button verwendest.'; $a->strings['The requested item doesn\'t exist or has been deleted.'] = 'Der angeforderte Beitrag existiert nicht oder wurde gelöscht.'; +$a->strings['Unfortunately, the requested conversation isn\'t available to you.

      +

      Possible reasons include:

      +
        +
      • The top-level post isn\'t visible.
      • +
      • The top-level post was deleted.
      • +
      • The node has blocked the top-level author or the author of the shared post.
      • +
      • You have ignored or blocked the top-level author or the author of the shared post.
      • +

      '] = 'Leider ist die angeforderte Konversation nicht verfügbar für dich.

      +

      Mögliche Gründe können sein:

      +
    • Der übergeordnete Beitrag ist nicht sichtbar.
    • +
    • Der übergeordnete Beitrag wurde gelöscht
    • +
    • Die Instanz hat den Autor des übergeordneten Beitrags oder den Nutzer, der den Beitrag geteilt hat, geblockt.
    • +
    • Du hast den Autor des übergeordneten Beitrags oder den Nutzer, der den Beitrag geteilt hat, geblockt oder ignorierst ihn.
    • +

        '; $a->strings['The feed for this item is unavailable.'] = 'Der Feed für diesen Beitrag ist nicht verfügbar.'; $a->strings['Unable to follow this item.'] = 'Konnte dem Beitrag nicht folgen.'; $a->strings['System down for maintenance'] = 'System zur Wartung abgeschaltet'; $a->strings['This Friendica node is currently in maintenance mode, either automatically because it is self-updating or manually by the node administrator. This condition should be temporary, please come back in a few minutes.'] = 'Diese Friendica Instanz befindet sich derzeit im Wartungsmodus, entweder aufgrund von automatischen Updateprozessen oder weil die Administratoren der Instanz den Wartungsmodus aktiviert haben. Dies sollte ein vorübergehender Zustand sein. Bitte versuche es in ein paar Minuten erneut.'; $a->strings['A Decentralized Social Network'] = 'Ein dezentrales Soziales Netzwerk'; +$a->strings['You need to be logged in to access this page.'] = 'Du musst angemeldet sein, um auf diese Seite zuzugreifen. '; +$a->strings['Files'] = 'Dateien'; +$a->strings['Upload'] = 'Hochladen'; +$a->strings['Sorry, maybe your upload is bigger than the PHP configuration allows'] = 'Entschuldige, die Datei scheint größer zu sein, als es die PHP-Konfiguration erlaubt.'; +$a->strings['Or - did you try to upload an empty file?'] = 'Oder - hast du versucht, eine leere Datei hochzuladen?'; +$a->strings['File exceeds size limit of %s'] = 'Die Datei ist größer als das erlaubte Limit von %s'; +$a->strings['File upload failed.'] = 'Hochladen der Datei fehlgeschlagen.'; $a->strings['List of all users'] = 'Liste aller Benutzerkonten'; $a->strings['Active'] = 'Aktive'; $a->strings['List of active accounts'] = 'Liste der aktiven Benutzerkonten'; @@ -2041,11 +2058,8 @@ $a->strings['audio link'] = 'Audio-Link'; $a->strings['Remove Item Tag'] = 'Gegenstands-Tag entfernen'; $a->strings['Select a tag to remove: '] = 'Wähle ein Tag zum Entfernen aus: '; $a->strings['Remove'] = 'Entfernen'; -$a->strings['Sorry, maybe your upload is bigger than the PHP configuration allows'] = 'Entschuldige, die Datei scheint größer zu sein, als es die PHP-Konfiguration erlaubt.'; -$a->strings['Or - did you try to upload an empty file?'] = 'Oder - hast du versucht, eine leere Datei hochzuladen?'; -$a->strings['File exceeds size limit of %s'] = 'Die Datei ist größer als das erlaubte Limit von %s'; -$a->strings['File upload failed.'] = 'Hochladen der Datei fehlgeschlagen.'; $a->strings['No contacts.'] = 'Keine Kontakte.'; +$a->strings['View Album'] = 'Album betrachten'; $a->strings['Profile not found.'] = 'Profil nicht gefunden.'; $a->strings['You\'re currently viewing your profile as %s Cancel'] = 'Du betrachtest dein Profil gerade als %s Abbrechen'; $a->strings['Full Name:'] = 'Kompletter Name:'; @@ -2121,6 +2135,7 @@ Du kannst das Passwort nach dem Anmelden ändern.'; $a->strings['Registration successful.'] = 'Registrierung erfolgreich.'; $a->strings['Your registration can not be processed.'] = 'Deine Registrierung konnte nicht verarbeitet werden.'; $a->strings['You have to leave a request note for the admin.'] = 'Du musst eine Nachricht für den Administrator als Begründung deiner Anfrage hinterlegen.'; +$a->strings['An internal error occured.'] = 'Ein interner Fehler ist aufgetreten. '; $a->strings['Your registration is pending approval by the site owner.'] = 'Deine Registrierung muss noch vom Betreiber der Seite freigegeben werden.'; $a->strings['You must be logged in to use this module.'] = 'Du musst eingeloggt sein, um dieses Modul benutzen zu können.'; $a->strings['Only logged in users are permitted to perform a search.'] = 'Nur eingeloggten Benutzern ist das Suchen gestattet.'; From a7639a2341bcd181d8730b220cab0f9ec18f965e Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 28 Nov 2022 06:46:18 +0000 Subject: [PATCH 24/40] Updated documentation --- doc/API-Mastodon.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/API-Mastodon.md b/doc/API-Mastodon.md index 63c487caf3..6c6a1691a2 100644 --- a/doc/API-Mastodon.md +++ b/doc/API-Mastodon.md @@ -73,7 +73,7 @@ These endpoints use the [Mastodon API entities](https://docs.joinmastodon.org/en - `:id` is a follow request ID, not a regular account id - Returns a [Relationship](https://docs.joinmastodon.org/entities/relationship) object. - +- [`GET /api/v1/followed_tags'](https://docs.joinmastodon.org/methods/followed_tags/) - [`GET /api/v1/instance`](https://docs.joinmastodon.org/methods/instance#fetch-instance) - `GET /api/v1/instance/rules` Undocumented, returns Terms of Service - [`GET /api/v1/instance/peers`](https://docs.joinmastodon.org/methods/instance#list-of-connected-domains) @@ -126,6 +126,9 @@ These endpoints use the [Mastodon API entities](https://docs.joinmastodon.org/en - [`GET /api/v1/statuses/:id/source`](https://docs.joinmastodon.org/methods/statuses/#source) - [`GET /api/v1/statuses/:id/card`](https://docs.joinmastodon.org/methods/statuses/#card) - [`GET /api/v1/suggestions`](https://docs.joinmastodon.org/methods/accounts/suggestions/) +- [`GET /api/v1/tags/:id'](https://docs.joinmastodon.org/methods/tags/#get) +- [`GET /api/v1/tags/:id/follow'](https://docs.joinmastodon.org/methods/tags/#follow) +- [`GET /api/v1/tags/:id/unfollow'](https://docs.joinmastodon.org/methods/tags/#unfollow) - [`GET /api/v1/timelines/direct`](https://docs.joinmastodon.org/methods/timelines/) - [`GET /api/v1/timelines/home`](https://docs.joinmastodon.org/methods/timelines/) - [`GET /api/v1/timelines/list/:id`](https://docs.joinmastodon.org/methods/timelines/) From 73ba7d800540f6106f1f2bb344e3f33a3bf12714 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 28 Nov 2022 06:52:55 +0000 Subject: [PATCH 25/40] Coding styles --- src/Module/Api/Mastodon/FollowedTags.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Module/Api/Mastodon/FollowedTags.php b/src/Module/Api/Mastodon/FollowedTags.php index bfa7db7935..eb5e32fdc1 100644 --- a/src/Module/Api/Mastodon/FollowedTags.php +++ b/src/Module/Api/Mastodon/FollowedTags.php @@ -67,7 +67,7 @@ class FollowedTags extends BaseApi self::setBoundaries($saved_search['id']); $tag = ['name' => ltrim($saved_search['term'], '#')]; - $hashtag = new \Friendica\Object\Api\Mastodon\Tag($this->baseUrl, $tag, [], true); + $hashtag = new \Friendica\Object\Api\Mastodon\Tag($this->baseUrl, $tag, [], true); $return[] = $hashtag->toArray(); } From 6b36bd893bd8b1b44d578f19acbaa4d4bb670c36 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 28 Nov 2022 07:08:01 +0000 Subject: [PATCH 26/40] API: Trending tags are added --- doc/API-Mastodon.md | 1 + static/routes.config.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/API-Mastodon.md b/doc/API-Mastodon.md index 6c6a1691a2..d77218f670 100644 --- a/doc/API-Mastodon.md +++ b/doc/API-Mastodon.md @@ -135,6 +135,7 @@ These endpoints use the [Mastodon API entities](https://docs.joinmastodon.org/en - [`GET /api/v1/timelines/public`](https://docs.joinmastodon.org/methods/timelines/) - [`GET /api/v1/timelines/tag/:hashtag`](https://docs.joinmastodon.org/methods/timelines/) - [`GET /api/v1/trends`](https://docs.joinmastodon.org/methods/instance/trends/) +- [`GET /api/v1/trends/tags`](https://docs.joinmastodon.org/methods/trends/#tags) - [`GET /api/v2/search`](https://docs.joinmastodon.org/methods/search/) diff --git a/static/routes.config.php b/static/routes.config.php index 42333e65fa..9b2d3d9365 100644 --- a/static/routes.config.php +++ b/static/routes.config.php @@ -298,7 +298,7 @@ return [ '/trends' => [Module\Api\Mastodon\Trends::class, [R::GET ]], '/trends/links' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // not implemented '/trends/statuses' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // not implemented - '/trends/tags' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // not implemented + '/trends/tags' => [Module\Api\Mastodon\Trends::class, [R::GET ]], ], '/v{version:\d+}' => [ '/admin/accounts' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // not supported From c00004f6ea05646310904c97c1289cc1c5ac1d2d Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 28 Nov 2022 09:30:41 +0000 Subject: [PATCH 27/40] API: Tredning statuses added --- database.sql | 3 +- doc/API-Mastodon.md | 9 ++- src/Model/Post.php | 15 +++++ src/Module/Api/Mastodon/Trends/Statuses.php | 57 +++++++++++++++++++ .../Mastodon/{Trends.php => Trends/Tags.php} | 4 +- static/dbstructure.config.php | 2 +- static/dbview.config.php | 1 + static/routes.config.php | 6 +- 8 files changed, 85 insertions(+), 12 deletions(-) create mode 100644 src/Module/Api/Mastodon/Trends/Statuses.php rename src/Module/Api/Mastodon/{Trends.php => Trends/Tags.php} (95%) diff --git a/database.sql b/database.sql index 8fa20be52c..cccb233d37 100644 --- a/database.sql +++ b/database.sql @@ -1,6 +1,6 @@ -- ------------------------------------------ -- Friendica 2022.12-dev (Giant Rhubarb) --- DB_UPDATE_VERSION 1491 +-- DB_UPDATE_VERSION 1492 -- ------------------------------------------ @@ -2437,6 +2437,7 @@ CREATE VIEW `post-thread-view` AS SELECT `post-question`.`end-time` AS `question-end-time`, 0 AS `has-categories`, EXISTS(SELECT `id` FROM `post-media` WHERE `post-media`.`uri-id` = `post-thread`.`uri-id`) AS `has-media`, + (SELECT COUNT(*) FROM `post` WHERE `parent-uri-id` = `post-thread`.`uri-id` AND `gravity` = 6) AS `total-comments`, `diaspora-interaction`.`interaction` AS `signed_text`, `parent-item-uri`.`guid` AS `parent-guid`, `parent-post`.`network` AS `parent-network`, diff --git a/doc/API-Mastodon.md b/doc/API-Mastodon.md index d77218f670..2850f0ebf0 100644 --- a/doc/API-Mastodon.md +++ b/doc/API-Mastodon.md @@ -126,15 +126,16 @@ These endpoints use the [Mastodon API entities](https://docs.joinmastodon.org/en - [`GET /api/v1/statuses/:id/source`](https://docs.joinmastodon.org/methods/statuses/#source) - [`GET /api/v1/statuses/:id/card`](https://docs.joinmastodon.org/methods/statuses/#card) - [`GET /api/v1/suggestions`](https://docs.joinmastodon.org/methods/accounts/suggestions/) -- [`GET /api/v1/tags/:id'](https://docs.joinmastodon.org/methods/tags/#get) -- [`GET /api/v1/tags/:id/follow'](https://docs.joinmastodon.org/methods/tags/#follow) -- [`GET /api/v1/tags/:id/unfollow'](https://docs.joinmastodon.org/methods/tags/#unfollow) +- [`GET /api/v1/tags/:id`](https://docs.joinmastodon.org/methods/tags/#get) +- [`GET /api/v1/tags/:id/follow`](https://docs.joinmastodon.org/methods/tags/#follow) +- [`GET /api/v1/tags/:id/unfollow`](https://docs.joinmastodon.org/methods/tags/#unfollow) - [`GET /api/v1/timelines/direct`](https://docs.joinmastodon.org/methods/timelines/) - [`GET /api/v1/timelines/home`](https://docs.joinmastodon.org/methods/timelines/) - [`GET /api/v1/timelines/list/:id`](https://docs.joinmastodon.org/methods/timelines/) - [`GET /api/v1/timelines/public`](https://docs.joinmastodon.org/methods/timelines/) - [`GET /api/v1/timelines/tag/:hashtag`](https://docs.joinmastodon.org/methods/timelines/) - [`GET /api/v1/trends`](https://docs.joinmastodon.org/methods/instance/trends/) +- [`GET /api/v1/trends/statuses`](https://docs.joinmastodon.org/methods/trends/#statuses) - [`GET /api/v1/trends/tags`](https://docs.joinmastodon.org/methods/trends/#tags) - [`GET /api/v2/search`](https://docs.joinmastodon.org/methods/search/) @@ -147,8 +148,6 @@ These emdpoints are planned to be implemented somewhere in the future. - [`GET /api/v1/accounts/familiar_followers`](https://github.com/mastodon/mastodon/pull/17700) - [`GET /api/v1/accounts/lookup`](https://github.com/mastodon/mastodon/pull/15740) - [`GET /api/v1/trends/links`](https://github.com/mastodon/mastodon/pull/16917) -- [`GET /api/v1/trends/statuses`](https://github.com/mastodon/mastodon/pull/17431) -- [`GET /api/v1/trends/tags`](https://github.com/mastodon/mastodon/pull/16917) - [`POST /api/v1/polls/:id/votes`](https://docs.joinmastodon.org/methods/statuses/polls/) - [`GET /api/v1/featured_tags`](https://docs.joinmastodon.org/methods/accounts/featured_tags/) - [`POST /api/v1/featured_tags`](https://docs.joinmastodon.org/methods/accounts/featured_tags/) diff --git a/src/Model/Post.php b/src/Model/Post.php index 11e5c2c985..2baa76b5be 100644 --- a/src/Model/Post.php +++ b/src/Model/Post.php @@ -374,6 +374,21 @@ class Post return self::selectView('post-thread-user-view', $selected, $condition, $params); } + /** + * Select rows from the post-thread-view view + * + * @param array $selected Array of selected fields, empty for all + * @param array $condition Array of fields for condition + * @param array $params Array of several parameters + * + * @return boolean|object + * @throws \Exception + */ + public static function selectPostThread(array $selected = [], array $condition = [], array $params = []) + { + return self::selectView('post-thread-view', $selected, $condition, $params); + } + /** * Select rows from the given view for a given user * diff --git a/src/Module/Api/Mastodon/Trends/Statuses.php b/src/Module/Api/Mastodon/Trends/Statuses.php new file mode 100644 index 0000000000..70b23f5cc1 --- /dev/null +++ b/src/Module/Api/Mastodon/Trends/Statuses.php @@ -0,0 +1,57 @@ +. + * + */ + +namespace Friendica\Module\Api\Mastodon\Trends; + +use Friendica\Core\Protocol; +use Friendica\Core\System; +use Friendica\Database\DBA; +use Friendica\DI; +use Friendica\Model\Post; +use Friendica\Module\BaseApi; +use Friendica\Util\DateTimeFormat; + +/** + * @see https://docs.joinmastodon.org/methods/trends/#statuses + */ +class Statuses extends BaseApi +{ + /** + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + */ + protected function rawContent(array $request = []) + { + $request = $this->getRequest([ + 'limit' => 10, // Maximum number of results to return. Defaults to 10. + ], $request); + + $trending = []; + $condition = ["NOT `private` AND `commented` > ?", DateTimeFormat::utc('now -1 day')]; + $condition = DBA::mergeConditions($condition, ['network' => Protocol::FEDERATED]); + $statuses = Post::selectPostThread(['uri-id'], $condition, ['limit' => $request['limit'], 'order' => ['total-comments' => true]]); + while ($status = Post::fetch($statuses)) { + $trending[] = DI::mstdnStatus()->createFromUriId($status['uri-id']); + } + DBA::close($statuses); + + System::jsonExit($trending); + } +} diff --git a/src/Module/Api/Mastodon/Trends.php b/src/Module/Api/Mastodon/Trends/Tags.php similarity index 95% rename from src/Module/Api/Mastodon/Trends.php rename to src/Module/Api/Mastodon/Trends/Tags.php index c42a27641b..2014b7a384 100644 --- a/src/Module/Api/Mastodon/Trends.php +++ b/src/Module/Api/Mastodon/Trends/Tags.php @@ -19,7 +19,7 @@ * */ -namespace Friendica\Module\Api\Mastodon; +namespace Friendica\Module\Api\Mastodon\Trends; use Friendica\Core\System; use Friendica\DI; @@ -29,7 +29,7 @@ use Friendica\Module\BaseApi; /** * @see https://docs.joinmastodon.org/methods/instance/trends/ */ -class Trends extends BaseApi +class Tags extends BaseApi { /** * @throws \Friendica\Network\HTTPException\InternalServerErrorException diff --git a/static/dbstructure.config.php b/static/dbstructure.config.php index 942f2237d5..2f613f9749 100644 --- a/static/dbstructure.config.php +++ b/static/dbstructure.config.php @@ -55,7 +55,7 @@ use Friendica\Database\DBA; if (!defined('DB_UPDATE_VERSION')) { - define('DB_UPDATE_VERSION', 1491); + define('DB_UPDATE_VERSION', 1492); } return [ diff --git a/static/dbview.config.php b/static/dbview.config.php index 2452dc341b..6c4f00a986 100644 --- a/static/dbview.config.php +++ b/static/dbview.config.php @@ -664,6 +664,7 @@ "question-end-time" => ["post-question", "end-time"], "has-categories" => "0", "has-media" => "EXISTS(SELECT `id` FROM `post-media` WHERE `post-media`.`uri-id` = `post-thread`.`uri-id`)", + "total-comments" => "(SELECT COUNT(*) FROM `post` WHERE `parent-uri-id` = `post-thread`.`uri-id` AND `gravity` = 6)", "signed_text" => ["diaspora-interaction", "interaction"], "parent-guid" => ["parent-item-uri", "guid"], "parent-network" => ["parent-post", "network"], diff --git a/static/routes.config.php b/static/routes.config.php index 9b2d3d9365..81a9d2e2fd 100644 --- a/static/routes.config.php +++ b/static/routes.config.php @@ -295,10 +295,10 @@ return [ '/timelines/list/{id:\d+}' => [Module\Api\Mastodon\Timelines\ListTimeline::class, [R::GET ]], '/timelines/public' => [Module\Api\Mastodon\Timelines\PublicTimeline::class, [R::GET ]], '/timelines/tag/{hashtag}' => [Module\Api\Mastodon\Timelines\Tag::class, [R::GET ]], - '/trends' => [Module\Api\Mastodon\Trends::class, [R::GET ]], + '/trends' => [Module\Api\Mastodon\Trends\Tags::class, [R::GET ]], '/trends/links' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // not implemented - '/trends/statuses' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // not implemented - '/trends/tags' => [Module\Api\Mastodon\Trends::class, [R::GET ]], + '/trends/statuses' => [Module\Api\Mastodon\Trends\Statuses::class, [R::GET ]], + '/trends/tags' => [Module\Api\Mastodon\Trends\Tags::class, [R::GET ]], ], '/v{version:\d+}' => [ '/admin/accounts' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // not supported From 0e160040d49fdd82935a2d48530cdec552212b81 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 28 Nov 2022 10:54:26 +0000 Subject: [PATCH 28/40] Code standards --- src/Module/Api/Mastodon/Trends/Statuses.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Module/Api/Mastodon/Trends/Statuses.php b/src/Module/Api/Mastodon/Trends/Statuses.php index 70b23f5cc1..cb69be5ed7 100644 --- a/src/Module/Api/Mastodon/Trends/Statuses.php +++ b/src/Module/Api/Mastodon/Trends/Statuses.php @@ -43,9 +43,10 @@ class Statuses extends BaseApi 'limit' => 10, // Maximum number of results to return. Defaults to 10. ], $request); - $trending = []; $condition = ["NOT `private` AND `commented` > ?", DateTimeFormat::utc('now -1 day')]; $condition = DBA::mergeConditions($condition, ['network' => Protocol::FEDERATED]); + + $trending = []; $statuses = Post::selectPostThread(['uri-id'], $condition, ['limit' => $request['limit'], 'order' => ['total-comments' => true]]); while ($status = Post::fetch($statuses)) { $trending[] = DI::mstdnStatus()->createFromUriId($status['uri-id']); From bded1c3989854bbf8a23fd39592cd42161813165 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 28 Nov 2022 14:51:37 +0000 Subject: [PATCH 29/40] Only use items that had originally been posted in the last week --- src/Module/Api/Mastodon/Trends/Statuses.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Module/Api/Mastodon/Trends/Statuses.php b/src/Module/Api/Mastodon/Trends/Statuses.php index cb69be5ed7..8974403d77 100644 --- a/src/Module/Api/Mastodon/Trends/Statuses.php +++ b/src/Module/Api/Mastodon/Trends/Statuses.php @@ -43,7 +43,7 @@ class Statuses extends BaseApi 'limit' => 10, // Maximum number of results to return. Defaults to 10. ], $request); - $condition = ["NOT `private` AND `commented` > ?", DateTimeFormat::utc('now -1 day')]; + $condition = ["NOT `private` AND `commented` > ? AND `created` > ?", DateTimeFormat::utc('now -1 day'), DateTimeFormat::utc('now -1 week')]; $condition = DBA::mergeConditions($condition, ['network' => Protocol::FEDERATED]); $trending = []; From de25d3a7eebd0c14c1b6449a45fd47d0ac93fbd6 Mon Sep 17 00:00:00 2001 From: Philipp Date: Mon, 28 Nov 2022 20:13:38 +0100 Subject: [PATCH 30/40] Fix Legacy Router class routing --- src/App/Router.php | 76 ++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 43 deletions(-) diff --git a/src/App/Router.php b/src/App/Router.php index 35ea9ada8b..5b915c0e6a 100644 --- a/src/App/Router.php +++ b/src/App/Router.php @@ -80,7 +80,7 @@ class Router /** * @var array Module parameters */ - private $parameters = []; + protected $parameters = []; /** @var L10n */ private $l10n; @@ -268,7 +268,6 @@ class Router * * @throws InternalServerErrorException * @throws MethodNotAllowedException - * @throws NotFoundException */ public function getModuleClass(): string { @@ -284,9 +283,8 @@ class Router * * @return void * - * @throws HTTPException\InternalServerErrorException - * @throws HTTPException\MethodNotAllowedException If a rule matched but the method didn't - * @throws HTTPException\NotFoundException If no rule matched + * @throws HTTPException\InternalServerErrorException Unexpected exceptions + * @throws HTTPException\MethodNotAllowedException If a rule is private only */ private function determineModuleClass(): void { @@ -295,39 +293,26 @@ class Router $dispatcher = new FriendicaGroupCountBased($this->getCachedDispatchData()); - $this->parameters = []; + $this->parameters = [$this->server]; - // Check if the HTTP method is OPTIONS and return the special Options Module with the possible HTTP methods - if ($this->args->getMethod() === static::OPTIONS) { - $this->moduleClass = Options::class; - $this->parameters = ['allowedMethods' => $dispatcher->getOptions($cmd)]; - } else { - $routeInfo = $dispatcher->dispatch($this->args->getMethod(), $cmd); - if ($routeInfo[0] === Dispatcher::FOUND) { - $this->moduleClass = $routeInfo[1]; - $this->parameters = $routeInfo[2]; - } elseif ($routeInfo[0] === Dispatcher::METHOD_NOT_ALLOWED) { - throw new HTTPException\MethodNotAllowedException($this->l10n->t('Method not allowed for this module. Allowed method(s): %s', implode(', ', $routeInfo[1]))); - } else { - throw new HTTPException\NotFoundException($this->l10n->t('Page not found.')); - } - } - } - - public function getModule(?string $module_class = null): ICanHandleRequests - { - $module_parameters = [$this->server]; - /** - * ROUTING - * - * From the request URL, routing consists of obtaining the name of a BaseModule-extending class of which the - * post() and/or content() static methods can be respectively called to produce a data change or an output. - **/ try { - $module_class = $module_class ?? $this->getModuleClass(); - $module_parameters[] = $this->parameters; + // Check if the HTTP method is OPTIONS and return the special Options Module with the possible HTTP methods + if ($this->args->getMethod() === static::OPTIONS) { + $this->moduleClass = Options::class; + $this->parameters = ['allowedMethods' => $dispatcher->getOptions($cmd)]; + } else { + $routeInfo = $dispatcher->dispatch($this->args->getMethod(), $cmd); + if ($routeInfo[0] === Dispatcher::FOUND) { + $this->moduleClass = $routeInfo[1]; + $this->parameters[] = $routeInfo[2]; + } else if ($routeInfo[0] === Dispatcher::METHOD_NOT_ALLOWED) { + throw new HTTPException\MethodNotAllowedException($this->l10n->t('Method not allowed for this module. Allowed method(s): %s', implode(', ', $routeInfo[1]))); + } else { + throw new HTTPException\NotFoundException($this->l10n->t('Page not found.')); + } + } } catch (MethodNotAllowedException $e) { - $module_class = MethodNotAllowed::class; + $this->moduleClass = MethodNotAllowed::class; } catch (NotFoundException $e) { $moduleName = $this->args->getModuleName(); // Then we try addon-provided modules that we wrap in the LegacyModule class @@ -339,8 +324,8 @@ class Router } else { include_once "addon/{$moduleName}/{$moduleName}.php"; if (function_exists($moduleName . '_module')) { - $module_parameters[] = "addon/{$moduleName}/{$moduleName}.php"; - $module_class = LegacyModule::class; + $this->parameters[] = "addon/{$moduleName}/{$moduleName}.php"; + $this->moduleClass = LegacyModule::class; } } } @@ -348,24 +333,29 @@ class Router /* Finally, we look for a 'standard' program module in the 'mod' directory * We emulate a Module class through the LegacyModule class */ - if (!$module_class && file_exists("mod/{$moduleName}.php")) { - $module_parameters[] = "mod/{$moduleName}.php"; - $module_class = LegacyModule::class; + if (!$this->moduleClass && file_exists("mod/{$moduleName}.php")) { + $this->parameters[] = "mod/{$moduleName}.php"; + $this->moduleClass = LegacyModule::class; } - $module_class = $module_class ?: PageNotFound::class; + $this->moduleClass = $this->moduleClass ?: PageNotFound::class; } + } + + public function getModule(?string $module_class = null): ICanHandleRequests + { + $moduleClass = $module_class ?? $this->getModuleClass(); $stamp = microtime(true); try { /** @var ICanHandleRequests $module */ - return $this->dice->create($module_class, $module_parameters); + return $this->dice->create($moduleClass, $this->parameters); } finally { if ($this->dice_profiler_threshold > 0) { $dur = floatval(microtime(true) - $stamp); if ($dur >= $this->dice_profiler_threshold) { - $this->logger->notice('Dice module creation lasts too long.', ['duration' => round($dur, 3), 'module' => $module_class, 'parameters' => $module_parameters]); + $this->logger->notice('Dice module creation lasts too long.', ['duration' => round($dur, 3), 'module' => $moduleClass, 'parameters' => $this->parameters]); } } } From e391328cbf7edf05b6d40fd15c538f2f9260346a Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 28 Nov 2022 19:31:04 +0000 Subject: [PATCH 31/40] Added changelog entry --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index b2e549610f..b9a1dd966b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,6 @@ Version 2022.12 (unreleased) Friendica Core + The rewrite rule in .htaccess-dist has been changed. The change has to be applied manually to the existing .htaccess Friendica Addons BREAKING: The functions from the boot.php file have been moved into better fitting classes From de76e860ad024a7cc0b5f3366cdabefd4915c3e9 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 28 Nov 2022 20:19:57 +0000 Subject: [PATCH 32/40] API: Added trending links --- database.sql | 1 + doc/API-Mastodon.md | 2 +- src/Factory/Api/Mastodon/Card.php | 7 +-- src/Module/Api/Mastodon/Trends/Links.php | 60 +++++++++++++++++++++ src/Module/Api/Mastodon/Trends/Statuses.php | 6 ++- src/Object/Api/Mastodon/Card.php | 3 +- static/dbview.config.php | 1 + static/routes.config.php | 2 +- 8 files changed, 74 insertions(+), 8 deletions(-) create mode 100644 src/Module/Api/Mastodon/Trends/Links.php diff --git a/database.sql b/database.sql index cccb233d37..c68ae094c1 100644 --- a/database.sql +++ b/database.sql @@ -2438,6 +2438,7 @@ CREATE VIEW `post-thread-view` AS SELECT 0 AS `has-categories`, EXISTS(SELECT `id` FROM `post-media` WHERE `post-media`.`uri-id` = `post-thread`.`uri-id`) AS `has-media`, (SELECT COUNT(*) FROM `post` WHERE `parent-uri-id` = `post-thread`.`uri-id` AND `gravity` = 6) AS `total-comments`, + (SELECT COUNT(DISTINCT(`author-id`)) FROM `post` WHERE `parent-uri-id` = `post-thread`.`uri-id` AND `gravity` = 6) AS `total-actors`, `diaspora-interaction`.`interaction` AS `signed_text`, `parent-item-uri`.`guid` AS `parent-guid`, `parent-post`.`network` AS `parent-network`, diff --git a/doc/API-Mastodon.md b/doc/API-Mastodon.md index 2850f0ebf0..0e2f574303 100644 --- a/doc/API-Mastodon.md +++ b/doc/API-Mastodon.md @@ -135,6 +135,7 @@ These endpoints use the [Mastodon API entities](https://docs.joinmastodon.org/en - [`GET /api/v1/timelines/public`](https://docs.joinmastodon.org/methods/timelines/) - [`GET /api/v1/timelines/tag/:hashtag`](https://docs.joinmastodon.org/methods/timelines/) - [`GET /api/v1/trends`](https://docs.joinmastodon.org/methods/instance/trends/) +- [`GET /api/v1/trends/links`](https://github.com/mastodon/mastodon/pull/16917) - [`GET /api/v1/trends/statuses`](https://docs.joinmastodon.org/methods/trends/#statuses) - [`GET /api/v1/trends/tags`](https://docs.joinmastodon.org/methods/trends/#tags) - [`GET /api/v2/search`](https://docs.joinmastodon.org/methods/search/) @@ -147,7 +148,6 @@ These emdpoints are planned to be implemented somewhere in the future. - [`POST /api/v1/accounts/:id/remove_from_followers`](https://github.com/mastodon/mastodon/pull/16864) - [`GET /api/v1/accounts/familiar_followers`](https://github.com/mastodon/mastodon/pull/17700) - [`GET /api/v1/accounts/lookup`](https://github.com/mastodon/mastodon/pull/15740) -- [`GET /api/v1/trends/links`](https://github.com/mastodon/mastodon/pull/16917) - [`POST /api/v1/polls/:id/votes`](https://docs.joinmastodon.org/methods/statuses/polls/) - [`GET /api/v1/featured_tags`](https://docs.joinmastodon.org/methods/accounts/featured_tags/) - [`POST /api/v1/featured_tags`](https://docs.joinmastodon.org/methods/accounts/featured_tags/) diff --git a/src/Factory/Api/Mastodon/Card.php b/src/Factory/Api/Mastodon/Card.php index 659ab3a3de..ac50841847 100644 --- a/src/Factory/Api/Mastodon/Card.php +++ b/src/Factory/Api/Mastodon/Card.php @@ -30,13 +30,14 @@ use Friendica\Util\Strings; class Card extends BaseFactory { /** - * @param int $uriId Uri-ID of the item + * @param int $uriId Uri-ID of the item + * @param array $history Link request history * * @return \Friendica\Object\Api\Mastodon\Card * @throws HTTPException\InternalServerErrorException * @throws \ImagickException*@throws \Exception */ - public function createFromUriId(int $uriId): \Friendica\Object\Api\Mastodon\Card + public function createFromUriId(int $uriId, array $history = []): \Friendica\Object\Api\Mastodon\Card { $item = Post::selectFirst(['body'], ['uri-id' => $uriId]); if (!empty($item['body'])) { @@ -76,6 +77,6 @@ class Card extends BaseFactory } } - return new \Friendica\Object\Api\Mastodon\Card($data); + return new \Friendica\Object\Api\Mastodon\Card($data, $history); } } diff --git a/src/Module/Api/Mastodon/Trends/Links.php b/src/Module/Api/Mastodon/Trends/Links.php new file mode 100644 index 0000000000..ee535c7f3c --- /dev/null +++ b/src/Module/Api/Mastodon/Trends/Links.php @@ -0,0 +1,60 @@ +. + * + */ + +namespace Friendica\Module\Api\Mastodon\Trends; + +use Friendica\Core\Protocol; +use Friendica\Core\System; +use Friendica\Database\DBA; +use Friendica\DI; +use Friendica\Model\Post; +use Friendica\Module\BaseApi; +use Friendica\Util\DateTimeFormat; + +/** + * @see https://docs.joinmastodon.org/methods/trends/#links + */ +class Links extends BaseApi +{ + /** + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + */ + protected function rawContent(array $request = []) + { + $request = $this->getRequest([ + 'limit' => 10, // Maximum number of results to return. Defaults to 10. + ], $request); + + $condition = ["EXISTS(SELECT `id` FROM `post-media` WHERE `post-media`.`uri-id` = `post-thread-view`.`uri-id` AND `type` = ? AND NOT `name` IS NULL AND NOT `description` IS NULL) AND NOT `private` AND `commented` > ? AND `created` > ?", + Post\Media::HTML, DateTimeFormat::utc('now -1 day'), DateTimeFormat::utc('now -1 week')]; + $condition = DBA::mergeConditions($condition, ['network' => Protocol::FEDERATED]); + + $trending = []; + $statuses = Post::selectPostThread(['uri-id', 'total-comments', 'total-actors'], $condition, ['limit' => $request['limit'], 'order' => ['total-actors' => true]]); + while ($status = Post::fetch($statuses)) { + $history = [['day' => (string)time(), 'uses' => (string)$status['total-comments'], 'accounts' => (string)$status['total-actors']]]; + $trending[] = DI::mstdnCard()->createFromUriId($status['uri-id'], $history)->toArray(); + } + DBA::close($statuses); + + System::jsonExit($trending); + } +} diff --git a/src/Module/Api/Mastodon/Trends/Statuses.php b/src/Module/Api/Mastodon/Trends/Statuses.php index 8974403d77..26eb52d7ae 100644 --- a/src/Module/Api/Mastodon/Trends/Statuses.php +++ b/src/Module/Api/Mastodon/Trends/Statuses.php @@ -39,6 +39,8 @@ class Statuses extends BaseApi */ protected function rawContent(array $request = []) { + $uid = self::getCurrentUserID(); + $request = $this->getRequest([ 'limit' => 10, // Maximum number of results to return. Defaults to 10. ], $request); @@ -47,9 +49,9 @@ class Statuses extends BaseApi $condition = DBA::mergeConditions($condition, ['network' => Protocol::FEDERATED]); $trending = []; - $statuses = Post::selectPostThread(['uri-id'], $condition, ['limit' => $request['limit'], 'order' => ['total-comments' => true]]); + $statuses = Post::selectPostThread(['uri-id'], $condition, ['limit' => $request['limit'], 'order' => ['total-actors' => true]]); while ($status = Post::fetch($statuses)) { - $trending[] = DI::mstdnStatus()->createFromUriId($status['uri-id']); + $trending[] = DI::mstdnStatus()->createFromUriId($status['uri-id'], $uid); } DBA::close($statuses); diff --git a/src/Object/Api/Mastodon/Card.php b/src/Object/Api/Mastodon/Card.php index 4bd6c6e769..bf87617190 100644 --- a/src/Object/Api/Mastodon/Card.php +++ b/src/Object/Api/Mastodon/Card.php @@ -59,7 +59,7 @@ class Card extends BaseDataTransferObject * @param array $attachment Attachment record * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public function __construct(array $attachment) + public function __construct(array $attachment, array $history = []) { $this->url = $attachment['url'] ?? ''; $this->title = $attachment['title'] ?? ''; @@ -72,6 +72,7 @@ class Card extends BaseDataTransferObject $this->width = $attachment['width'] ?? 0; $this->height = $attachment['height'] ?? 0; $this->image = $attachment['image'] ?? ''; + $this->history = $history; } /** diff --git a/static/dbview.config.php b/static/dbview.config.php index 6c4f00a986..d06904a91f 100644 --- a/static/dbview.config.php +++ b/static/dbview.config.php @@ -665,6 +665,7 @@ "has-categories" => "0", "has-media" => "EXISTS(SELECT `id` FROM `post-media` WHERE `post-media`.`uri-id` = `post-thread`.`uri-id`)", "total-comments" => "(SELECT COUNT(*) FROM `post` WHERE `parent-uri-id` = `post-thread`.`uri-id` AND `gravity` = 6)", + "total-actors" => "(SELECT COUNT(DISTINCT(`author-id`)) FROM `post` WHERE `parent-uri-id` = `post-thread`.`uri-id` AND `gravity` = 6)", "signed_text" => ["diaspora-interaction", "interaction"], "parent-guid" => ["parent-item-uri", "guid"], "parent-network" => ["parent-post", "network"], diff --git a/static/routes.config.php b/static/routes.config.php index 81a9d2e2fd..da5dda0278 100644 --- a/static/routes.config.php +++ b/static/routes.config.php @@ -296,7 +296,7 @@ return [ '/timelines/public' => [Module\Api\Mastodon\Timelines\PublicTimeline::class, [R::GET ]], '/timelines/tag/{hashtag}' => [Module\Api\Mastodon\Timelines\Tag::class, [R::GET ]], '/trends' => [Module\Api\Mastodon\Trends\Tags::class, [R::GET ]], - '/trends/links' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // not implemented + '/trends/links' => [Module\Api\Mastodon\Trends\Links::class, [R::GET ]], '/trends/statuses' => [Module\Api\Mastodon\Trends\Statuses::class, [R::GET ]], '/trends/tags' => [Module\Api\Mastodon\Trends\Tags::class, [R::GET ]], ], From 437419bbd95879904876e2e218778460625b40fa Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 28 Nov 2022 20:22:08 +0000 Subject: [PATCH 33/40] Updated database.sql --- database.sql | 2 +- static/dbstructure.config.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/database.sql b/database.sql index c68ae094c1..04401f4c0d 100644 --- a/database.sql +++ b/database.sql @@ -1,6 +1,6 @@ -- ------------------------------------------ -- Friendica 2022.12-dev (Giant Rhubarb) --- DB_UPDATE_VERSION 1492 +-- DB_UPDATE_VERSION 1493 -- ------------------------------------------ diff --git a/static/dbstructure.config.php b/static/dbstructure.config.php index 2f613f9749..4f231b4c32 100644 --- a/static/dbstructure.config.php +++ b/static/dbstructure.config.php @@ -55,7 +55,7 @@ use Friendica\Database\DBA; if (!defined('DB_UPDATE_VERSION')) { - define('DB_UPDATE_VERSION', 1492); + define('DB_UPDATE_VERSION', 1493); } return [ From 7898f9cccb9edd62cf6e2f2f20aa3df827067418 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Mon, 28 Nov 2022 21:42:34 +0100 Subject: [PATCH 34/40] Update src/Module/Api/Mastodon/Trends/Links.php Co-authored-by: Hypolite Petovan --- src/Module/Api/Mastodon/Trends/Links.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Module/Api/Mastodon/Trends/Links.php b/src/Module/Api/Mastodon/Trends/Links.php index ee535c7f3c..b41b1d6eaa 100644 --- a/src/Module/Api/Mastodon/Trends/Links.php +++ b/src/Module/Api/Mastodon/Trends/Links.php @@ -50,7 +50,7 @@ class Links extends BaseApi $trending = []; $statuses = Post::selectPostThread(['uri-id', 'total-comments', 'total-actors'], $condition, ['limit' => $request['limit'], 'order' => ['total-actors' => true]]); while ($status = Post::fetch($statuses)) { - $history = [['day' => (string)time(), 'uses' => (string)$status['total-comments'], 'accounts' => (string)$status['total-actors']]]; + $history = [['day' => (string)time(), 'uses' => (string)$status['total-comments'], 'accounts' => (string)$status['total-actors']]]; $trending[] = DI::mstdnCard()->createFromUriId($status['uri-id'], $history)->toArray(); } DBA::close($statuses); From 3288efb323eae6ee98d3520f0b7ba48a17baea5d Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 28 Nov 2022 21:22:21 +0000 Subject: [PATCH 35/40] Fix fatal errors because of unknown function/variable names --- src/Object/Post.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Object/Post.php b/src/Object/Post.php index 8b8463f858..c81b49580f 100644 --- a/src/Object/Post.php +++ b/src/Object/Post.php @@ -622,7 +622,7 @@ class Post public function addChild(Post $item) { if (!$item->getId()) { - Logger::fatal('Post object has no id', ['post' => $item]); + Logger::error('Post object has no id', ['post' => $item]); return false; } elseif ($this->getChild($item->getId())) { Logger::warning('Post object already exists', ['post' => $item]); @@ -633,7 +633,7 @@ class Post * Only add what will be displayed */ if ($item->getDataValue('network') === Protocol::MAIL && DI::userSession()->getLocalUserId() != $item->getDataValue('uid')) { - Logger::warning('Post object does not belong to local user', ['post' => $item, 'local_user' => $local_user]); + Logger::warning('Post object does not belong to local user', ['post' => $item, 'local_user' => DI::userSession()->getLocalUserId()]); return false; } elseif (DI::activity()->match($item->getDataValue('verb'), Activity::LIKE) || DI::activity()->match($item->getDataValue('verb'), Activity::DISLIKE)) { From c0c414ab95be0111dbee26dac49dbbd952866f3d Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Tue, 29 Nov 2022 06:37:41 -0500 Subject: [PATCH 36/40] [frio] Add page wrapper to contact follow page --- view/theme/frio/css/style.css | 5 ++ view/theme/frio/templates/auto_request.tpl | 66 +++++++++++----------- 2 files changed, 39 insertions(+), 32 deletions(-) diff --git a/view/theme/frio/css/style.css b/view/theme/frio/css/style.css index eecb0b242d..9c8c74eb2a 100644 --- a/view/theme/frio/css/style.css +++ b/view/theme/frio/css/style.css @@ -3605,6 +3605,11 @@ section .profile-match-wrapper { font-size: 13px; } + +.generic-page-wrapper.contact-follow-wrapper { + min-height: auto; +} + /* Medium devices (desktops, 992px and up) */ @media (min-width: 992px) { .mod-home.is-not-singleuser #content, diff --git a/view/theme/frio/templates/auto_request.tpl b/view/theme/frio/templates/auto_request.tpl index 2d1861389c..659dc644f3 100644 --- a/view/theme/frio/templates/auto_request.tpl +++ b/view/theme/frio/templates/auto_request.tpl @@ -1,43 +1,45 @@ -

        {{$header}}

        +
        +

        {{$header}}

        {{if !$myaddr}} -

        - {{$page_desc nofilter}} -

        -

        - {{$invite_desc nofilter}} -

        +

        + {{$page_desc nofilter}} +

        +

        + {{$invite_desc nofilter}} +

        {{/if}} -
        + {{if $url}} -
        -
        {{$url_label}}
        -
        {{$url}}
        -
        +
        +
        {{$url_label}}
        +
        {{$url}}
        +
        {{/if}} {{if $keywords}} -
        -
        {{$keywords_label}}
        -
        {{$keywords}}
        -
        +
        +
        {{$keywords_label}}
        +
        {{$keywords}}
        +
        {{/if}} -
        - - {{if $myaddr}} - {{$myaddr}} - - {{else}} - - {{/if}} - -
        -
        +
        + + {{if $myaddr}} + {{$myaddr}} + + {{else}} + + {{/if}} + +
        +
        -
        +
        {{if $submit}} - + {{/if}} - -
        - + +
        + +
        \ No newline at end of file From 8b41d62a8819b02d6bf04e84a59d6828750903ee Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 29 Nov 2022 18:45:30 +0000 Subject: [PATCH 37/40] API: Speed improvements --- database.sql | 20 ++++++++++++++++++- src/Model/GServer.php | 1 + src/Module/Api/Mastodon/Accounts/Statuses.php | 15 +++++++------- static/dbstructure.config.php | 2 +- static/dbview.config.php | 16 +++++++++++++++ static/routes.config.php | 5 +++++ 6 files changed, 50 insertions(+), 9 deletions(-) diff --git a/database.sql b/database.sql index 04401f4c0d..596dfa4708 100644 --- a/database.sql +++ b/database.sql @@ -1,6 +1,6 @@ -- ------------------------------------------ -- Friendica 2022.12-dev (Giant Rhubarb) --- DB_UPDATE_VERSION 1493 +-- DB_UPDATE_VERSION 1494 -- ------------------------------------------ @@ -2499,6 +2499,24 @@ CREATE VIEW `collection-view` AS SELECT INNER JOIN `post` ON `post-collection`.`uri-id` = `post`.`uri-id` INNER JOIN `post-thread` ON `post-thread`.`uri-id` = `post`.`parent-uri-id`; +-- +-- VIEW media-view +-- +DROP VIEW IF EXISTS `media-view`; +CREATE VIEW `media-view` AS SELECT + `post-media`.`uri-id` AS `uri-id`, + `post-media`.`type` AS `type`, + `post`.`received` AS `received`, + `post`.`created` AS `created`, + `post`.`private` AS `private`, + `post`.`visible` AS `visible`, + `post`.`deleted` AS `deleted`, + `post`.`thr-parent-id` AS `thr-parent-id`, + `post`.`author-id` AS `author-id`, + `post`.`gravity` AS `gravity` + FROM `post-media` + INNER JOIN `post` ON `post-media`.`uri-id` = `post`.`uri-id`; + -- -- VIEW tag-view -- diff --git a/src/Model/GServer.php b/src/Model/GServer.php index 03e42c62b4..a128060f4c 100644 --- a/src/Model/GServer.php +++ b/src/Model/GServer.php @@ -70,6 +70,7 @@ class GServer const DETECT_UNSPECIFIC = [self::DETECT_MANUAL, self::DETECT_HEADER, self::DETECT_BODY, self::DETECT_HOST_META, self::DETECT_CONTACTS, self::DETECT_AP_ACTOR]; // Implementation specific endpoints + // @todo Possibly add Lemmy detection via the endpoint /api/v3/site const DETECT_FRIENDIKA = 10; const DETECT_FRIENDICA = 11; const DETECT_STATUSNET = 12; diff --git a/src/Module/Api/Mastodon/Accounts/Statuses.php b/src/Module/Api/Mastodon/Accounts/Statuses.php index 9481172129..b244c56fb2 100644 --- a/src/Module/Api/Mastodon/Accounts/Statuses.php +++ b/src/Module/Api/Mastodon/Accounts/Statuses.php @@ -69,6 +69,8 @@ class Statuses extends BaseApi if ($request['pinned']) { $condition = ['author-id' => $id, 'private' => [Item::PUBLIC, Item::UNLISTED], 'type' => Post\Collection::FEATURED]; + } elseif ($request['only_media']) { + $condition = ['author-id' => $id, 'private' => [Item::PUBLIC, Item::UNLISTED], 'type' => [Post\Media::AUDIO, Post\Media::IMAGE, Post\Media::VIDEO]]; } elseif (!$uid) { $condition = ['author-id' => $id, 'private' => [Item::PUBLIC, Item::UNLISTED], 'uid' => 0, 'network' => Protocol::FEDERATED]; @@ -76,16 +78,11 @@ class Statuses extends BaseApi $condition = ["`author-id` = ? AND (`uid` = 0 OR (`uid` = ? AND NOT `global`))", $id, $uid]; } - if (!$request['pinned']) { + if (!$request['pinned'] && !$request['only_media']) { $condition = DBA::mergeConditions($condition, ["(`gravity` IN (?, ?) OR (`gravity` = ? AND `vid` = ?))", Item::GRAVITY_PARENT, Item::GRAVITY_COMMENT, Item::GRAVITY_ACTIVITY, Verb::getID(Activity::ANNOUNCE)]); } - if ($request['only_media']) { - $condition = DBA::mergeConditions($condition, ["`uri-id` IN (SELECT `uri-id` FROM `post-media` WHERE `type` IN (?, ?, ?))", - Post\Media::AUDIO, Post\Media::IMAGE, Post\Media::VIDEO]); - } - if (!empty($request['max_id'])) { $condition = DBA::mergeConditions($condition, ["`uri-id` < ?", $request['max_id']]); } @@ -99,12 +96,16 @@ class Statuses extends BaseApi $params['order'] = ['uri-id']; } - if ($request['exclude_replies']) { + if (($request['pinned'] || $request['only_media']) && $request['exclude_replies']) { $condition = DBA::mergeConditions($condition, ['gravity' => Item::GRAVITY_PARENT]); } if ($request['pinned']) { $items = DBA::select('collection-view', ['uri-id'], $condition, $params); + } elseif ($request['only_media']) { + $items = DBA::select('media-view', ['uri-id'], $condition, $params); + } elseif ($request['exclude_replies']) { + $items = Post::selectThreadForUser($uid, ['uri-id'], $condition, $params); } else { $items = Post::selectForUser($uid, ['uri-id'], $condition, $params); } diff --git a/static/dbstructure.config.php b/static/dbstructure.config.php index 4f231b4c32..a72f17032e 100644 --- a/static/dbstructure.config.php +++ b/static/dbstructure.config.php @@ -55,7 +55,7 @@ use Friendica\Database\DBA; if (!defined('DB_UPDATE_VERSION')) { - define('DB_UPDATE_VERSION', 1493); + define('DB_UPDATE_VERSION', 1494); } return [ diff --git a/static/dbview.config.php b/static/dbview.config.php index d06904a91f..a2e3e1b45f 100644 --- a/static/dbview.config.php +++ b/static/dbview.config.php @@ -723,6 +723,22 @@ INNER JOIN `post` ON `post-collection`.`uri-id` = `post`.`uri-id` INNER JOIN `post-thread` ON `post-thread`.`uri-id` = `post`.`parent-uri-id`" ], + "media-view" => [ + "fields" => [ + "uri-id" => ["post-media", "uri-id"], + "type" => ["post-media", "type"], + "received" => ["post", "received"], + "created" => ["post", "created"], + "private" => ["post", "private"], + "visible" => ["post", "visible"], + "deleted" => ["post", "deleted"], + "thr-parent-id" => ["post", "thr-parent-id"], + "author-id" => ["post", "author-id"], + "gravity" => ["post", "gravity"], + ], + "query" => "FROM `post-media` + INNER JOIN `post` ON `post-media`.`uri-id` = `post`.`uri-id`" + ], "tag-view" => [ "fields" => [ "uri-id" => ["post-tag", "uri-id"], diff --git a/static/routes.config.php b/static/routes.config.php index da5dda0278..8d1fec6f0e 100644 --- a/static/routes.config.php +++ b/static/routes.config.php @@ -239,6 +239,8 @@ return [ '/followed_tags' => [Module\Api\Mastodon\FollowedTags::class, [R::GET ]], '/instance' => [Module\Api\Mastodon\Instance::class, [R::GET ]], '/instance/activity' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // @todo + '/instance/domain_blocks' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // @todo + '/instance/extended_description' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // @todo '/instance/peers' => [Module\Api\Mastodon\Instance\Peers::class, [R::GET ]], '/instance/rules' => [Module\Api\Mastodon\Instance\Rules::class, [R::GET ]], '/lists' => [Module\Api\Mastodon\Lists::class, [R::GET, R::POST]], @@ -300,6 +302,9 @@ return [ '/trends/statuses' => [Module\Api\Mastodon\Trends\Statuses::class, [R::GET ]], '/trends/tags' => [Module\Api\Mastodon\Trends\Tags::class, [R::GET ]], ], + '/v2' => [ + '/instance' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // not supported + ], '/v{version:\d+}' => [ '/admin/accounts' => [Module\Api\Mastodon\Unimplemented::class, [R::GET ]], // not supported '/filters' => [Module\Api\Mastodon\Filters::class, [R::GET ]], // Dummy, not supported From 8eca961aeb574201d0742c9161eb59066a79ac18 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 29 Nov 2022 19:50:12 +0000 Subject: [PATCH 38/40] Added status to the report --- database.sql | 4 +++- doc/database/db_report-post.md | 9 +++++---- doc/database/db_report.md | 1 + static/dbstructure.config.php | 4 +++- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/database.sql b/database.sql index 596dfa4708..4e940b3197 100644 --- a/database.sql +++ b/database.sql @@ -1,6 +1,6 @@ -- ------------------------------------------ -- Friendica 2022.12-dev (Giant Rhubarb) --- DB_UPDATE_VERSION 1494 +-- DB_UPDATE_VERSION 1495 -- ------------------------------------------ @@ -1656,6 +1656,7 @@ CREATE TABLE IF NOT EXISTS `report` ( `comment` text COMMENT 'Report', `forward` boolean COMMENT 'Forward the report to the remote server', `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', + `status` tinyint unsigned COMMENT 'Status of the report', PRIMARY KEY(`id`), INDEX `uid` (`uid`), INDEX `cid` (`cid`), @@ -1669,6 +1670,7 @@ CREATE TABLE IF NOT EXISTS `report` ( CREATE TABLE IF NOT EXISTS `report-post` ( `rid` int unsigned NOT NULL COMMENT 'Report id', `uri-id` int unsigned NOT NULL COMMENT 'Uri-id of the reported post', + `status` tinyint unsigned COMMENT 'Status of the reported post', PRIMARY KEY(`rid`,`uri-id`), INDEX `uri-id` (`uri-id`), FOREIGN KEY (`rid`) REFERENCES `report` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE, diff --git a/doc/database/db_report-post.md b/doc/database/db_report-post.md index 303aa3256f..fcaff6c2e4 100644 --- a/doc/database/db_report-post.md +++ b/doc/database/db_report-post.md @@ -6,10 +6,11 @@ Table report-post Fields ------ -| Field | Description | Type | Null | Key | Default | Extra | -| ------ | --------------------------- | ------------ | ---- | --- | ------- | ----- | -| rid | Report id | int unsigned | NO | PRI | NULL | | -| uri-id | Uri-id of the reported post | int unsigned | NO | PRI | NULL | | +| Field | Description | Type | Null | Key | Default | Extra | +| ------ | --------------------------- | ---------------- | ---- | --- | ------- | ----- | +| rid | Report id | int unsigned | NO | PRI | NULL | | +| uri-id | Uri-id of the reported post | int unsigned | NO | PRI | NULL | | +| status | Status of the reported post | tinyint unsigned | YES | | NULL | | Indexes ------------ diff --git a/doc/database/db_report.md b/doc/database/db_report.md index ababf6472f..9a87abe1f4 100644 --- a/doc/database/db_report.md +++ b/doc/database/db_report.md @@ -14,6 +14,7 @@ Fields | comment | Report | text | YES | | NULL | | | forward | Forward the report to the remote server | boolean | YES | | NULL | | | created | | datetime | NO | | 0001-01-01 00:00:00 | | +| status | Status of the report | tinyint unsigned | YES | | NULL | | Indexes ------------ diff --git a/static/dbstructure.config.php b/static/dbstructure.config.php index a72f17032e..9ec2ae52ed 100644 --- a/static/dbstructure.config.php +++ b/static/dbstructure.config.php @@ -55,7 +55,7 @@ use Friendica\Database\DBA; if (!defined('DB_UPDATE_VERSION')) { - define('DB_UPDATE_VERSION', 1494); + define('DB_UPDATE_VERSION', 1495); } return [ @@ -1658,6 +1658,7 @@ return [ "comment" => ["type" => "text", "comment" => "Report"], "forward" => ["type" => "boolean", "comment" => "Forward the report to the remote server"], "created" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], + "status" => ["type" => "tinyint unsigned", "comment" => "Status of the report"], ], "indexes" => [ "PRIMARY" => ["id"], @@ -1670,6 +1671,7 @@ return [ "fields" => [ "rid" => ["type" => "int unsigned", "not null" => "1", "primary" => "1", "foreign" => ["report" => "id"], "comment" => "Report id"], "uri-id" => ["type" => "int unsigned", "not null" => "1", "primary" => "1", "foreign" => ["item-uri" => "id"], "comment" => "Uri-id of the reported post"], + "status" => ["type" => "tinyint unsigned", "comment" => "Status of the reported post"], ], "indexes" => [ "PRIMARY" => ["rid", "uri-id"], From 8eda9dfe7cec31d10ab86b3544be33dad5d35ea9 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 29 Nov 2022 23:21:27 +0000 Subject: [PATCH 39/40] Fix warning 'Undefined array key "name"' --- src/Module/Api/Mastodon/FollowedTags.php | 3 +-- src/Module/Api/Mastodon/Tags.php | 3 +-- src/Module/Api/Mastodon/Tags/Follow.php | 2 +- src/Module/Api/Mastodon/Tags/Unfollow.php | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Module/Api/Mastodon/FollowedTags.php b/src/Module/Api/Mastodon/FollowedTags.php index eb5e32fdc1..7e9dd49c92 100644 --- a/src/Module/Api/Mastodon/FollowedTags.php +++ b/src/Module/Api/Mastodon/FollowedTags.php @@ -65,9 +65,8 @@ class FollowedTags extends BaseApi $saved_searches = DBA::select('search', ['id', 'term'], $condition); while ($saved_search = DBA::fetch($saved_searches)) { self::setBoundaries($saved_search['id']); - $tag = ['name' => ltrim($saved_search['term'], '#')]; - $hashtag = new \Friendica\Object\Api\Mastodon\Tag($this->baseUrl, $tag, [], true); + $hashtag = new \Friendica\Object\Api\Mastodon\Tag($this->baseUrl, ['name' => ltrim($saved_search['term'], '#')], [], true); $return[] = $hashtag->toArray(); } diff --git a/src/Module/Api/Mastodon/Tags.php b/src/Module/Api/Mastodon/Tags.php index d38899ac0f..606aecaff2 100644 --- a/src/Module/Api/Mastodon/Tags.php +++ b/src/Module/Api/Mastodon/Tags.php @@ -45,9 +45,8 @@ class Tags extends BaseApi $tag = ltrim($this->parameters['hashtag'], '#'); $following = DBA::exists('search', ['uid' => $uid, 'term' => '#' . $tag]); - $term = ['term' => $tag]; - $hashtag = new \Friendica\Object\Api\Mastodon\Tag($this->baseUrl, $term, [], $following); + $hashtag = new \Friendica\Object\Api\Mastodon\Tag($this->baseUrl, ['name' => $tag], [], $following); System::jsonExit($hashtag->toArray()); } } diff --git a/src/Module/Api/Mastodon/Tags/Follow.php b/src/Module/Api/Mastodon/Tags/Follow.php index 22f8fa3f27..b5879bb0e4 100644 --- a/src/Module/Api/Mastodon/Tags/Follow.php +++ b/src/Module/Api/Mastodon/Tags/Follow.php @@ -45,7 +45,7 @@ class Follow extends BaseApi DBA::insert('search', $fields); } - $hashtag = new \Friendica\Object\Api\Mastodon\Tag($this->baseUrl, $fields, [], true); + $hashtag = new \Friendica\Object\Api\Mastodon\Tag($this->baseUrl, ['name' => ltrim($this->parameters['hashtag'])], [], true); System::jsonExit($hashtag->toArray()); } } diff --git a/src/Module/Api/Mastodon/Tags/Unfollow.php b/src/Module/Api/Mastodon/Tags/Unfollow.php index f3fbad2e5a..8530c9d777 100644 --- a/src/Module/Api/Mastodon/Tags/Unfollow.php +++ b/src/Module/Api/Mastodon/Tags/Unfollow.php @@ -44,7 +44,7 @@ class Unfollow extends BaseApi DBA::delete('search', $term); - $hashtag = new \Friendica\Object\Api\Mastodon\Tag($this->baseUrl, $term, [], false); + $hashtag = new \Friendica\Object\Api\Mastodon\Tag($this->baseUrl, ['name' => ltrim($this->parameters['hashtag'])], [], false); System::jsonExit($hashtag->toArray()); } } From 150c0e0750cd4aca38d450e896fcd2fccbbe164b Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Tue, 29 Nov 2022 19:31:16 -0500 Subject: [PATCH 40/40] Address some PHP 8.1 deprecation notices - Replace a strstr call by strpos in Model\APContact - Simplify conditions in Protocol\DFRN - Address part of https://github.com/friendica/friendica/issues/12011#issuecomment-1331012289 --- src/Model/APContact.php | 4 ++-- src/Navigation/Notifications/ValueObject/Introduction.php | 1 + src/Protocol/DFRN.php | 8 ++++---- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Model/APContact.php b/src/Model/APContact.php index 3b568f39f1..67ce2b66bf 100644 --- a/src/Model/APContact.php +++ b/src/Model/APContact.php @@ -305,8 +305,8 @@ class APContact $apcontact['pubkey'] = null; if (!empty($compacted['w3id:publicKey'])) { - $apcontact['pubkey'] = trim(JsonLD::fetchElement($compacted['w3id:publicKey'], 'w3id:publicKeyPem', '@value')); - if (strstr($apcontact['pubkey'], 'RSA ')) { + $apcontact['pubkey'] = trim(JsonLD::fetchElement($compacted['w3id:publicKey'], 'w3id:publicKeyPem', '@value') ?? ''); + if (strpos($apcontact['pubkey'], 'RSA ') !== false) { $apcontact['pubkey'] = Crypto::rsaToPem($apcontact['pubkey']); } } diff --git a/src/Navigation/Notifications/ValueObject/Introduction.php b/src/Navigation/Notifications/ValueObject/Introduction.php index cb27b38886..da664ce8e5 100644 --- a/src/Navigation/Notifications/ValueObject/Introduction.php +++ b/src/Navigation/Notifications/ValueObject/Introduction.php @@ -226,6 +226,7 @@ class Introduction implements \JsonSerializable /** * @inheritDoc */ + #[\ReturnTypeWillChange] public function jsonSerialize() { return $this->toArray(); diff --git a/src/Protocol/DFRN.php b/src/Protocol/DFRN.php index da4db5d9ad..a86cf2094d 100644 --- a/src/Protocol/DFRN.php +++ b/src/Protocol/DFRN.php @@ -538,7 +538,7 @@ class DFRN XML::addElement($doc, $author, 'poco:utcOffset', DateTimeFormat::timezoneNow($profile['timezone'], 'P')); - if (trim($profile['homepage']) != '') { + if (trim($profile['homepage'])) { $urls = $doc->createElement('poco:urls'); XML::addElement($doc, $urls, 'poco:type', 'homepage'); XML::addElement($doc, $urls, 'poco:value', $profile['homepage']); @@ -546,7 +546,7 @@ class DFRN $author->appendChild($urls); } - if (trim($profile['pub_keywords']) != '') { + if (trim($profile['pub_keywords'] ?? '')) { $keywords = explode(',', $profile['pub_keywords']); foreach ($keywords as $keyword) { @@ -554,7 +554,7 @@ class DFRN } } - if (trim($profile['xmpp']) != '') { + if (trim($profile['xmpp'])) { $ims = $doc->createElement('poco:ims'); XML::addElement($doc, $ims, 'poco:type', 'xmpp'); XML::addElement($doc, $ims, 'poco:value', $profile['xmpp']); @@ -562,7 +562,7 @@ class DFRN $author->appendChild($ims); } - if (trim($profile['locality'] . $profile['region'] . $profile['country-name']) != '') { + if (trim($profile['locality'] . $profile['region'] . $profile['country-name'])) { $element = $doc->createElement('poco:address'); XML::addElement($doc, $element, 'poco:formatted', Profile::formatLocation($profile));