diff --git a/VERSION b/VERSION index e9cd37efec..79ec0dc3af 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2021.06-dev +2021.06-rc diff --git a/boot.php b/boot.php index bbb66c2f9a..aa3739f010 100644 --- a/boot.php +++ b/boot.php @@ -38,7 +38,7 @@ use Friendica\Util\DateTimeFormat; define('FRIENDICA_PLATFORM', 'Friendica'); define('FRIENDICA_CODENAME', 'Siberian Iris'); -define('FRIENDICA_VERSION', '2021.06-dev'); +define('FRIENDICA_VERSION', '2021.06-rc'); define('DFRN_PROTOCOL_VERSION', '2.23'); define('NEW_TABLE_STRUCTURE_VERSION', 1288); diff --git a/database.sql b/database.sql index d080b41582..3e6d398cf1 100644 --- a/database.sql +++ b/database.sql @@ -1,6 +1,6 @@ -- ------------------------------------------ --- Friendica 2021.06-dev (Siberian Iris) --- DB_UPDATE_VERSION 1418 +-- Friendica 2021.06-rc (Siberian Iris) +-- DB_UPDATE_VERSION 1419 -- ------------------------------------------ @@ -751,6 +751,7 @@ CREATE TABLE IF NOT EXISTS `mail` ( `from-photo` varchar(255) NOT NULL DEFAULT '' COMMENT 'contact photo link of the sender', `from-url` varchar(255) NOT NULL DEFAULT '' COMMENT 'profile linke of the sender', `contact-id` varchar(255) COMMENT 'contact.id', + `author-id` int unsigned COMMENT 'Link to the contact table with uid=0 of the author of the mail', `convid` int unsigned COMMENT 'conv.id', `title` varchar(255) NOT NULL DEFAULT '' COMMENT '', `body` mediumtext COMMENT '', @@ -759,7 +760,11 @@ CREATE TABLE IF NOT EXISTS `mail` ( `replied` boolean NOT NULL DEFAULT '0' COMMENT '', `unknown` boolean NOT NULL DEFAULT '0' COMMENT 'if sender not in the contact table this is 1', `uri` varchar(255) NOT NULL DEFAULT '' COMMENT '', + `uri-id` int unsigned COMMENT 'Item-uri id of the related mail', `parent-uri` varchar(255) NOT NULL DEFAULT '' COMMENT '', + `parent-uri-id` int unsigned COMMENT 'Item-uri id of the parent of the related mail', + `thr-parent` varchar(255) COMMENT '', + `thr-parent-id` int unsigned COMMENT 'Id of the item-uri table that contains the thread parent uri', `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'creation time of the private message', PRIMARY KEY(`id`), INDEX `uid_seen` (`uid`,`seen`), @@ -767,7 +772,15 @@ CREATE TABLE IF NOT EXISTS `mail` ( INDEX `uri` (`uri`(64)), INDEX `parent-uri` (`parent-uri`(64)), INDEX `contactid` (`contact-id`(32)), - FOREIGN KEY (`uid`) REFERENCES `user` (`uid`) ON UPDATE RESTRICT ON DELETE CASCADE + INDEX `author-id` (`author-id`), + INDEX `uri-id` (`uri-id`), + INDEX `parent-uri-id` (`parent-uri-id`), + INDEX `thr-parent-id` (`thr-parent-id`), + FOREIGN KEY (`uid`) REFERENCES `user` (`uid`) ON UPDATE RESTRICT ON DELETE CASCADE, + FOREIGN KEY (`author-id`) REFERENCES `contact` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT, + FOREIGN KEY (`uri-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE, + FOREIGN KEY (`parent-uri-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE, + FOREIGN KEY (`thr-parent-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='private messages'; -- diff --git a/doc/API-Mastodon.md b/doc/API-Mastodon.md index a734bd5445..37f62e0607 100644 --- a/doc/API-Mastodon.md +++ b/doc/API-Mastodon.md @@ -119,17 +119,29 @@ These endpoints use the [Mastodon API entities](https://docs.joinmastodon.org/en ## Currently unimplemented endpoints -These emdpoints are planned to be implemented +These emdpoints are planned to be implemented somewhere in the future. - [`PATCH /api/v1/accounts/update_credentials`](https://docs.joinmastodon.org/methods/accounts/) - [`GET /api/v1/instance/activity`](https://docs.joinmastodon.org/methods/instance#weekly-activity) +## Dummy endpoints + +These endpoints are returning empty data to avoid error messages when using third party clients. +They refer to features that don't exist in Friendica yet. + +- [`GET /api/v1/accounts/:id/identity_proofs`](https://docs.joinmastodon.org/methods/accounts/) +- [`GET /api/v1/announcements`](https://docs.joinmastodon.org/methods/announcements/) +- [`GET /api/v1/endorsements`](https://docs.joinmastodon.org/methods/accounts/endorsements/) +- [`GET /api/v1/filters`](https://docs.joinmastodon.org/methods/accounts/filters/) +- [`GET /api/v1/markers`](https://docs.joinmastodon.org/methods/timelines/markers/) +- [`GET /api/v1/scheduled_statuses`](https://docs.joinmastodon.org/methods/statuses/scheduled_statuses/) + ## Non supportable endpoints -These endpoints won't be implemented, since they refer to functionality that doesn't exist in Friendica +These endpoints won't be implemented at the moment. +They refer to features that don't exist in Friendica yet. - [`POST /api/v1/accounts`](https://docs.joinmastodon.org/methods/accounts/) -- [`GET /api/v1/accounts/:id/identity_proofs`](https://docs.joinmastodon.org/methods/accounts/) - [`POST /api/v1/accounts/:id/pin`](https://docs.joinmastodon.org/methods/accounts/) - [`POST /api/v1/accounts/:id/unpin`](https://docs.joinmastodon.org/methods/accounts/) - [`GET /api/v1/admin/accounts`](https://docs.joinmastodon.org/methods/admin/) @@ -138,29 +150,24 @@ These endpoints won't be implemented, since they refer to functionality that doe - [`GET /api/v1/admin/reports`](https://docs.joinmastodon.org/methods/admin/) - [`GET /api/v1/admin/reports/:id`](https://docs.joinmastodon.org/methods/admin/) - [`POST /api/v1/admin/reports/:id/{action}`](https://docs.joinmastodon.org/methods/admin/) -- [`GET /api/v1/announcements`](https://docs.joinmastodon.org/methods/announcements/) - [`POST /api/v1/announcements/:id/dismiss`](https://docs.joinmastodon.org/methods/announcements/) - [`PUT /api/v1/announcements/:id/reactions/{name}`](https://docs.joinmastodon.org/methods/announcements/) - [`DELETE /api/v1/announcements/:id/reactions/{name}`](https://docs.joinmastodon.org/methods/announcements/) - [`GET /api/v1/domain_blocks`](https://docs.joinmastodon.org/methods/accounts/domain_blocks/) - [`POST /api/v1/domain_blocks`](https://docs.joinmastodon.org/methods/accounts/domain_blocks/) - [`DELETE /api/v1/domain_blocks`](https://docs.joinmastodon.org/methods/accounts/domain_blocks/) -- [`GET /api/v1/endorsements`](https://docs.joinmastodon.org/methods/accounts/endorsements/) - [`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/) - [`DELETE /api/v1/featured_tags/:id`](https://docs.joinmastodon.org/methods/accounts/featured_tags/) - [`GET /api/v1/featured_tags/suggestions`](https://docs.joinmastodon.org/methods/accounts/featured_tags/) -- [`GET /api/v1/filters`](https://docs.joinmastodon.org/methods/accounts/filters/) - [`GET /api/v1/filters/:id`](https://docs.joinmastodon.org/methods/accounts/filters/) - [`POST /api/v1/filters/:id`](https://docs.joinmastodon.org/methods/accounts/filters/) - [`PUT /api/v1/filters/:id`](https://docs.joinmastodon.org/methods/accounts/filters/) - [`DELETE /api/v1/filters/:id`](https://docs.joinmastodon.org/methods/accounts/filters/) -- [`GET /api/v1/markers`](https://docs.joinmastodon.org/methods/timelines/markers/) - [`POST /api/v1/markers`](https://docs.joinmastodon.org/methods/timelines/markers/) - [`GET /api/v1/polls/:id`](https://docs.joinmastodon.org/methods/statuses/polls/) - [`POST /api/v1/polls/:id/votes`](https://docs.joinmastodon.org/methods/statuses/polls/) - [`POST /api/v1/reports`](https://docs.joinmastodon.org/methods/accounts/reports/) -- [`GET /api/v1/scheduled_statuses`](https://docs.joinmastodon.org/methods/statuses/scheduled_statuses/) - [`GET /api/v1/scheduled_statuses/:id`](https://docs.joinmastodon.org/methods/statuses/scheduled_statuses/) - [`PUT /api/v1/scheduled_statuses/:id`](https://docs.joinmastodon.org/methods/statuses/scheduled_statuses/) - [`DELETE /api/v1/scheduled_statuses/:id`](https://docs.joinmastodon.org/methods/statuses/scheduled_statuses/) diff --git a/src/Content/Text/BBCode.php b/src/Content/Text/BBCode.php index 32cd818cac..03ccd889a4 100644 --- a/src/Content/Text/BBCode.php +++ b/src/Content/Text/BBCode.php @@ -50,7 +50,7 @@ use Friendica\Util\XML; class BBCode { // Update this value to the current date whenever changes are made to BBCode::convert - const VERSION = '2021-05-01'; + const VERSION = '2021-05-21'; const INTERNAL = 0; const EXTERNAL = 1; @@ -1039,7 +1039,9 @@ class BBCode switch ($simplehtml) { case self::API: - $text = ($is_quote_share? '
' : '') . '

' . html_entity_decode('♲ ', ENT_QUOTES, 'UTF-8') . ' ' . $author_contact['addr'] . ':

' . "\n" . $content; + $text = ($is_quote_share? '
' : '') . + '

' . html_entity_decode('♲ ', ENT_QUOTES, 'UTF-8') . ' ' . $author_contact['addr'] . ":

\n" . + '
' . $content . '
'; break; case self::DIASPORA: if (stripos(Strings::normaliseLink($attributes['link']), 'http://twitter.com/') === 0) { @@ -1721,7 +1723,7 @@ class BBCode $text); } elseif (!$simple_html) { $text = preg_replace("/([@!])\[url\=(.*?)\](.*?)\[\/url\]/ism", - '$1$3', + '$1$3', $text); } diff --git a/src/Factory/Api/Mastodon/Status.php b/src/Factory/Api/Mastodon/Status.php index 3f16b3c380..41f64daa16 100644 --- a/src/Factory/Api/Mastodon/Status.php +++ b/src/Factory/Api/Mastodon/Status.php @@ -136,7 +136,9 @@ class Status extends BaseFactory $account = DI::mstdnAccount()->createFromContactId($item['author-id']); - $counts = new \Friendica\Object\Api\Mastodon\Status\Counts(0, 0, 0); + $replies = DBA::count('mail', ['thr-parent-id' => $item['uri-id'], 'reply' => true]); + + $counts = new \Friendica\Object\Api\Mastodon\Status\Counts($replies, 0, 0); $userAttributes = new \Friendica\Object\Api\Mastodon\Status\UserAttributes(false, false, false, false, false); diff --git a/src/Model/Contact.php b/src/Model/Contact.php index 89325e0939..4af1d9bb6d 100644 --- a/src/Model/Contact.php +++ b/src/Model/Contact.php @@ -1941,6 +1941,11 @@ class Contact return false; } + if (Contact::isLocal($ret['url'])) { + Logger::info('Local contacts are not updated here.'); + return true; + } + if (!empty($ret['account-type']) && $ret['account-type'] == User::ACCOUNT_TYPE_DELETED) { Logger::info('Deleted account', ['id' => $id, 'url' => $ret['url'], 'ret' => $ret]); self::remove($id); diff --git a/src/Model/Mail.php b/src/Model/Mail.php index e7ed2c8454..aa90586601 100644 --- a/src/Model/Mail.php +++ b/src/Model/Mail.php @@ -71,6 +71,20 @@ class Mail return false; } + $msg['author-id'] = Contact::getIdForURL($msg['from-url'], 0, false); + $msg['uri-id'] = ItemURI::insert(['uri' => $msg['uri'], 'guid' => $msg['guid']]); + $msg['parent-uri-id'] = ItemURI::getIdByURI($msg['parent-uri']); + + if ($msg['reply']) { + $reply = DBA::selectFirst('mail', ['uri', 'uri-id'], ['parent-uri' => $mail['parent-uri'], 'reply' => false]); + + $msg['thr-parent'] = $reply['uri']; + $msg['thr-parent-id'] = $reply['uri-id']; + } else { + $msg['thr-parent'] = $msg['uri']; + $msg['thr-parent-id'] = $msg['uri-id']; + } + DBA::insert('mail', $msg); $msg['id'] = DBA::lastInsertId(); diff --git a/src/Model/Profile.php b/src/Model/Profile.php index 3e35d60c29..c1d85bfe00 100644 --- a/src/Model/Profile.php +++ b/src/Model/Profile.php @@ -145,7 +145,7 @@ class Profile */ public static function load(App $a, $nickname, array $profiledata = [], $show_connect = true) { - $user = DBA::selectFirst('user', ['uid'], ['nickname' => $nickname, 'account_removed' => false]); + $user = User::getByNickname($nickname); if (!DBA::isResult($user) && empty($profiledata)) { Logger::log('profile error: ' . DI::args()->getQueryString(), Logger::DEBUG); diff --git a/src/Model/Tag.php b/src/Model/Tag.php index 796cc13f88..1bc700c3f1 100644 --- a/src/Model/Tag.php +++ b/src/Model/Tag.php @@ -425,8 +425,8 @@ class Tag $item['body'] = str_replace($orig_tag, $tag['url'], $item['body']); } - $return['hashtags'][] = $prefix . '' . htmlspecialchars($tag['name']) . ''; - $return['tags'][] = $prefix . '' . htmlspecialchars($tag['name']) . ''; + $return['hashtags'][] = '' . $prefix . '' . htmlspecialchars($tag['name']) . ''; + $return['tags'][] = '' . $prefix . '' . htmlspecialchars($tag['name']) . ''; break; case self::MENTION: case self::EXCLUSIVE_MENTION: @@ -435,8 +435,8 @@ class Tag } else { $tag['url'] = Contact::magicLink($tag['url']); } - $return['mentions'][] = $prefix . '' . htmlspecialchars($tag['name']) . ''; - $return['tags'][] = $prefix . '' . htmlspecialchars($tag['name']) . ''; + $return['mentions'][] = '' . $prefix . '' . htmlspecialchars($tag['name']) . ''; + $return['tags'][] = '' . $prefix . '' . htmlspecialchars($tag['name']) . ''; break; case self::IMPLICIT_MENTION: $return['implicit_mentions'][] = $prefix . $tag['name']; diff --git a/src/Model/User.php b/src/Model/User.php index 3b11ee6ce8..38a22f70f9 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -515,7 +515,27 @@ class User */ public static function getIdFromPasswordAuthentication($user_info, $password, $third_party = false) { - $user = self::getAuthenticationInfo($user_info); + // Addons registered with the "authenticate" hook may create the user on the + // fly. `getAuthenticationInfo` will fail if the user doesn't exist yet. If + // the user doesn't exist, we should give the addons a chance to create the + // user in our database, if applicable, before re-throwing the exception if + // they fail. + try { + $user = self::getAuthenticationInfo($user_info); + } catch (Exception $e) { + $username = (is_string($user_info) ? $user_info : $user_info['nickname'] ?? ''); + + // Addons can create users, and since this 'catch' branch should only + // execute if getAuthenticationInfo can't find an existing user, that's + // exactly what will happen here. Creating a numeric username would create + // abiguity with user IDs, possibly opening up an attack vector. + // So let's be very careful about that. + if (empty($username) || is_numeric($username)) { + throw $e; + } + + return self::getIdFromAuthenticateHooks($username, $password); + } if ($third_party && DI::pConfig()->get($user['uid'], '2fa', 'verified')) { // Third-party apps can't verify two-factor authentication, we use app-specific passwords instead @@ -545,23 +565,40 @@ class User return $user['uid']; } else { - $addon_auth = [ - 'username' => $user['nickname'], - 'password' => $password, - 'authenticated' => 0, - 'user_record' => null - ]; + return self::getIdFromAuthenticateHooks($user['nickname'], $password); // throws + } - /* - * An addon indicates successful login by setting 'authenticated' to non-zero value and returning a user record - * Addons should never set 'authenticated' except to indicate success - as hooks may be chained - * and later addons should not interfere with an earlier one that succeeded. - */ - Hook::callAll('authenticate', $addon_auth); + throw new HTTPException\ForbiddenException(DI::l10n()->t('Login failed')); + } - if ($addon_auth['authenticated'] && $addon_auth['user_record']) { - return $user['uid']; - } + /** + * Try to obtain a user ID via "authenticate" hook addons + * + * Returns the user id associated with a successful password authentication + * + * @param string $username + * @param string $password + * @return int User Id if authentication is successful + * @throws HTTPException\ForbiddenException + */ + public static function getIdFromAuthenticateHooks($username, $password) + { + $addon_auth = [ + 'username' => $username, + 'password' => $password, + 'authenticated' => 0, + 'user_record' => null + ]; + + /* + * An addon indicates successful login by setting 'authenticated' to non-zero value and returning a user record + * Addons should never set 'authenticated' except to indicate success - as hooks may be chained + * and later addons should not interfere with an earlier one that succeeded. + */ + Hook::callAll('authenticate', $addon_auth); + + if ($addon_auth['authenticated'] && $addon_auth['user_record']) { + return $addon_auth['user_record']['uid']; } throw new HTTPException\ForbiddenException(DI::l10n()->t('Login failed')); diff --git a/src/Module/Api/Mastodon/Conversation.php b/src/Module/Api/Mastodon/Conversations.php similarity index 98% rename from src/Module/Api/Mastodon/Conversation.php rename to src/Module/Api/Mastodon/Conversations.php index e87818ac27..3b4496a012 100644 --- a/src/Module/Api/Mastodon/Conversation.php +++ b/src/Module/Api/Mastodon/Conversations.php @@ -29,7 +29,7 @@ use Friendica\Module\BaseApi; /** * @see https://docs.joinmastodon.org/methods/timelines/conversations/ */ -class Conversation extends BaseApi +class Conversations extends BaseApi { public static function delete(array $parameters = []) { diff --git a/src/Module/Api/Mastodon/Conversations/Read.php b/src/Module/Api/Mastodon/Conversations/Read.php index d1c349eaac..955ca5c96f 100644 --- a/src/Module/Api/Mastodon/Conversations/Read.php +++ b/src/Module/Api/Mastodon/Conversations/Read.php @@ -19,7 +19,7 @@ * */ -namespace Friendica\Module\Api\Mastodon\Conversation; +namespace Friendica\Module\Api\Mastodon\Conversations; use Friendica\Core\System; use Friendica\Database\DBA; diff --git a/src/Module/Api/Mastodon/Timelines/Direct.php b/src/Module/Api/Mastodon/Timelines/Direct.php index 104f88d1c2..050bcbf478 100644 --- a/src/Module/Api/Mastodon/Timelines/Direct.php +++ b/src/Module/Api/Mastodon/Timelines/Direct.php @@ -48,22 +48,22 @@ class Direct extends BaseApi 'limit' => 20, // Maximum number of results to return. Defaults to 20. ]); - $params = ['order' => ['id' => true], 'limit' => $request['limit']]; + $params = ['order' => ['uri-id' => true], 'limit' => $request['limit']]; $condition = ['uid' => $uid]; if (!empty($request['max_id'])) { - $condition = DBA::mergeConditions($condition, ["`id` < ?", $request['max_id']]); + $condition = DBA::mergeConditions($condition, ["`uri-id` < ?", $request['max_id']]); } if (!empty($request['since_id'])) { - $condition = DBA::mergeConditions($condition, ["`id` > ?", $request['since_id']]); + $condition = DBA::mergeConditions($condition, ["`uri-id` > ?", $request['since_id']]); } if (!empty($request['min_id'])) { - $condition = DBA::mergeConditions($condition, ["`id` > ?", $request['min_id']]); + $condition = DBA::mergeConditions($condition, ["`uri-id` > ?", $request['min_id']]); - $params['order'] = ['id']; + $params['order'] = ['uri-id']; } $mails = DBA::select('mail', ['id'], $condition, $params); diff --git a/src/Module/NoScrape.php b/src/Module/NoScrape.php index 8f799aa966..a76b3a9517 100644 --- a/src/Module/NoScrape.php +++ b/src/Module/NoScrape.php @@ -50,20 +50,20 @@ class NoScrape extends BaseModule System::jsonError(403, 'Authentication required'); } - Profile::load($a, $which); + $profile = Profile::getByNickname($which, local_user()); - if (empty($a->profile['uid'])) { + if (empty($profile['uid'])) { System::jsonError(404, 'Profile not found'); } $json_info = [ - 'addr' => $a->profile['addr'], + 'addr' => $profile['addr'], 'nick' => $which, - 'guid' => $a->profile['guid'], - 'key' => $a->profile['upubkey'], + 'guid' => $profile['guid'], + 'key' => $profile['upubkey'], 'homepage' => DI::baseUrl() . "/profile/{$which}", - 'comm' => ($a->profile['account-type'] == User::ACCOUNT_TYPE_COMMUNITY), - 'account-type' => $a->profile['account-type'], + 'comm' => ($profile['account-type'] == User::ACCOUNT_TYPE_COMMUNITY), + 'account-type' => $profile['account-type'], ]; $dfrn_pages = ['request', 'confirm', 'notify', 'poll']; @@ -71,30 +71,30 @@ class NoScrape extends BaseModule $json_info["dfrn-{$dfrn}"] = DI::baseUrl() . "/dfrn_{$dfrn}/{$which}"; } - if (!$a->profile['net-publish']) { + if (!$profile['net-publish']) { $json_info['hide'] = true; System::jsonExit($json_info); } - $keywords = $a->profile['pub_keywords'] ?? ''; + $keywords = $profile['pub_keywords'] ?? ''; $keywords = str_replace(['#', ',', ' ', ',,'], ['', ' ', ',', ','], $keywords); $keywords = explode(',', $keywords); - $contactPhoto = DBA::selectFirst('contact', ['photo'], ['self' => true, 'uid' => $a->profile['uid']]); + $contactPhoto = DBA::selectFirst('contact', ['photo'], ['self' => true, 'uid' => $profile['uid']]); - $json_info['fn'] = $a->profile['name']; + $json_info['fn'] = $profile['name']; $json_info['photo'] = $contactPhoto["photo"]; $json_info['tags'] = $keywords; - $json_info['language'] = $a->profile['language']; + $json_info['language'] = $profile['language']; - if (!empty($a->profile['last-item'])) { - $json_info['updated'] = date("c", strtotime($a->profile['last-item'])); + if (!empty($profile['last-item'])) { + $json_info['updated'] = date("c", strtotime($profile['last-item'])); } - if (!($a->profile['hide-friends'] ?? false)) { + if (!($profile['hide-friends'] ?? false)) { $json_info['contacts'] = DBA::count('contact', [ - 'uid' => $a->profile['uid'], + 'uid' => $profile['uid'], 'self' => 0, 'blocked' => 0, 'pending' => 0, @@ -106,13 +106,13 @@ class NoScrape extends BaseModule // We display the last activity (post or login), reduced to year and week number $last_active = 0; - $condition = ['uid' => $a->profile['uid'], 'self' => true]; + $condition = ['uid' => $profile['uid'], 'self' => true]; $contact = DBA::selectFirst('contact', ['last-item'], $condition); if (DBA::isResult($contact)) { $last_active = strtotime($contact['last-item']); } - $condition = ['uid' => $a->profile['uid']]; + $condition = ['uid' => $profile['uid']]; $user = DBA::selectFirst('user', ['login_date'], $condition); if (DBA::isResult($user)) { if ($last_active < strtotime($user['login_date'])) { @@ -124,8 +124,8 @@ class NoScrape extends BaseModule //These are optional fields. $profile_fields = ['about', 'locality', 'region', 'postal-code', 'country-name']; foreach ($profile_fields as $field) { - if (!empty($a->profile[$field])) { - $json_info["$field"] = $a->profile[$field]; + if (!empty($profile[$field])) { + $json_info["$field"] = $profile[$field]; } } diff --git a/src/Module/OAuth/Authorize.php b/src/Module/OAuth/Authorize.php index d5dc68932a..a46c4c7ac5 100644 --- a/src/Module/OAuth/Authorize.php +++ b/src/Module/OAuth/Authorize.php @@ -63,9 +63,9 @@ class Authorize extends BaseApi // @todo Compare the application scope and requested scope - $request = $_REQUEST; - unset($request['pagename']); - $redirect = 'oauth/authorize?' . http_build_query($request); + $redirect_request = $_REQUEST; + unset($redirect_request['pagename']); + $redirect = 'oauth/authorize?' . http_build_query($redirect_request); $uid = local_user(); if (empty($uid)) { diff --git a/src/Protocol/ActivityPub/Transmitter.php b/src/Protocol/ActivityPub/Transmitter.php index 20c1e49b88..83e3d35a97 100644 --- a/src/Protocol/ActivityPub/Transmitter.php +++ b/src/Protocol/ActivityPub/Transmitter.php @@ -868,24 +868,19 @@ class Transmitter return []; } - $mail['uri-id'] = ItemURI::insert(['uri' => $mail['uri'], 'guid' => $mail['guid']]); - - $reply = DBA::selectFirst('mail', ['uri', 'from-url', 'guid'], ['parent-uri' => $mail['parent-uri'], 'reply' => false]); + $reply = DBA::selectFirst('mail', ['uri', 'uri-id', 'from-url'], ['parent-uri' => $mail['parent-uri'], 'reply' => false]); // Making the post more compatible for Mastodon by: // - Making it a note and not an article (no title) // - Moving the title into the "summary" field that is used as a "content warning" - if ($use_title) { - $mail['body'] = $mail['body']; - $mail['title'] = $mail['title']; - } else { + if (!$use_title) { $mail['body'] = '[abstract]' . $mail['title'] . "[/abstract]\n" . $mail['body']; $mail['title'] = ''; } $mail['author-link'] = $mail['owner-link'] = $mail['from-url']; - $mail['author-id'] = Contact::getIdForURL($mail['author-link'], 0, false); + $mail['owner-id'] = $mail['author-id']; $mail['allow_cid'] = '<'.$mail['contact-id'].'>'; $mail['allow_gid'] = ''; $mail['deny_cid'] = ''; @@ -893,9 +888,9 @@ class Transmitter $mail['private'] = Item::PRIVATE; $mail['deleted'] = false; $mail['edited'] = $mail['created']; - $mail['plink'] = $mail['uri']; - $mail['thr-parent'] = $reply['uri']; - $mail['thr-parent-id'] = ItemURI::insert(['uri' => $reply['uri'], 'guid' => $reply['guid']]); + $mail['plink'] = DI::baseUrl() . '/message/' . $mail['id']; + $mail['parent-uri'] = $reply['uri']; + $mail['parent-uri-id'] = $reply['uri-id']; $mail['parent-author-id'] = Contact::getIdForURL($reply['from-url'], 0, false); $mail['gravity'] = ($mail['reply'] ? GRAVITY_COMMENT: GRAVITY_PARENT); $mail['event-type'] = ''; @@ -1530,12 +1525,21 @@ class Transmitter if ($type == 'Note') { $body = $item['raw-body'] ?? self::removePictures($body); - } elseif (($type == 'Article') && empty($data['summary'])) { - $regexp = "/[@!]\[url\=([^\[\]]*)\].*?\[\/url\]/ism"; - $summary = preg_replace_callback($regexp, ['self', 'mentionAddrCallback'], $body); - $data['summary'] = BBCode::toPlaintext(Plaintext::shorten(self::removePictures($summary), 1000)); } + /** + * @todo Improve the automated summary + * This part is currently deactivated. The automated summary seems to be more + * confusing than helping. But possibly we will find a better way. + * So the code is left here for now as a reminder + * + * } elseif (($type == 'Article') && empty($data['summary'])) { + * $regexp = "/[@!]\[url\=([^\[\]]*)\].*?\[\/url\]/ism"; + * $summary = preg_replace_callback($regexp, ['self', 'mentionAddrCallback'], $body); + * $data['summary'] = BBCode::toPlaintext(Plaintext::shorten(self::removePictures($summary), 1000)); + * } + */ + if (empty($item['uid']) || !Feature::isEnabled($item['uid'], 'explicit_mentions')) { $body = self::prependMentions($body, $item['uri-id'], $item['author-link']); } diff --git a/src/Util/HTTPSignature.php b/src/Util/HTTPSignature.php index 5fb4ab7337..584ac356fb 100644 --- a/src/Util/HTTPSignature.php +++ b/src/Util/HTTPSignature.php @@ -558,8 +558,10 @@ class HTTPSignature if (!empty($key['url']) && !empty($key['type']) && ($key['type'] == 'Tombstone')) { Logger::info('Actor is a tombstone', ['key' => $key]); - // We now delete everything that we possibly knew from this actor - Contact::deleteContactByUrl($key['url']); + if (!Contact::isLocal($key['url'])) { + // We now delete everything that we possibly knew from this actor + Contact::deleteContactByUrl($key['url']); + } return null; } diff --git a/src/Worker/ExpirePosts.php b/src/Worker/ExpirePosts.php index 2c3f6f68a1..3f1075db5d 100644 --- a/src/Worker/ExpirePosts.php +++ b/src/Worker/ExpirePosts.php @@ -181,7 +181,10 @@ class ExpirePosts AND NOT EXISTS(SELECT `uri-id` FROM `post-user` WHERE `uri-id` = `item-uri`.`id`) AND NOT EXISTS(SELECT `parent-uri-id` FROM `post-user` WHERE `parent-uri-id` = `item-uri`.`id`) AND NOT EXISTS(SELECT `thr-parent-id` FROM `post-user` WHERE `thr-parent-id` = `item-uri`.`id`) - AND NOT EXISTS(SELECT `external-id` FROM `post-user` WHERE `external-id` = `item-uri`.`id`)", $item['uri-id']]); + AND NOT EXISTS(SELECT `external-id` FROM `post-user` WHERE `external-id` = `item-uri`.`id`) + AND NOT EXISTS(SELECT `uri-id` FROM `mail` WHERE `uri-id` = `item-uri`.`id`) + AND NOT EXISTS(SELECT `parent-uri-id` FROM `mail` WHERE `parent-uri-id` = `item-uri`.`id`) + AND NOT EXISTS(SELECT `thr-parent-id` FROM `mail` WHERE `thr-parent-id` = `item-uri`.`id`)", $item['uri-id']]); Logger::notice('Start deleting orphaned URI-ID', ['last-id' => $item['uri-id']]); $affected_count = 0; diff --git a/src/Worker/RemoveContact.php b/src/Worker/RemoveContact.php index 13cbbec8ba..f64d4d02d5 100644 --- a/src/Worker/RemoveContact.php +++ b/src/Worker/RemoveContact.php @@ -55,6 +55,7 @@ class RemoveContact { } DBA::delete('mail', ['contact-id' => $id]); + DBA::delete('mail', ['author-id' => $id]); Post\ThreadUser::delete(['author-id' => $id]); Post\ThreadUser::delete(['owner-id' => $id]); diff --git a/static/dbstructure.config.php b/static/dbstructure.config.php index 835cb3ff37..14b7814c09 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', 1418); + define('DB_UPDATE_VERSION', 1419); } return [ @@ -818,6 +818,7 @@ return [ "from-photo" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "contact photo link of the sender"], "from-url" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "profile linke of the sender"], "contact-id" => ["type" => "varchar(255)", "relation" => ["contact" => "id"], "comment" => "contact.id"], + "author-id" => ["type" => "int unsigned", "foreign" => ["contact" => "id", "on delete" => "restrict"], "comment" => "Link to the contact table with uid=0 of the author of the mail"], "convid" => ["type" => "int unsigned", "relation" => ["conv" => "id"], "comment" => "conv.id"], "title" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], "body" => ["type" => "mediumtext", "comment" => ""], @@ -826,7 +827,11 @@ return [ "replied" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], "unknown" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "if sender not in the contact table this is 1"], "uri" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "uri-id" => ["type" => "int unsigned", "foreign" => ["item-uri" => "id"], "comment" => "Item-uri id of the related mail"], "parent-uri" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "parent-uri-id" => ["type" => "int unsigned", "foreign" => ["item-uri" => "id"], "comment" => "Item-uri id of the parent of the related mail"], + "thr-parent" => ["type" => "varchar(255)", "comment" => ""], + "thr-parent-id" => ["type" => "int unsigned", "foreign" => ["item-uri" => "id"], "comment" => "Id of the item-uri table that contains the thread parent uri"], "created" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "creation time of the private message"], ], "indexes" => [ @@ -836,6 +841,10 @@ return [ "uri" => ["uri(64)"], "parent-uri" => ["parent-uri(64)"], "contactid" => ["contact-id(32)"], + "author-id" => ["author-id"], + "uri-id" => ["uri-id"], + "parent-uri-id" => ["parent-uri-id"], + "thr-parent-id" => ["thr-parent-id"], ] ], "mailacct" => [ diff --git a/static/routes.config.php b/static/routes.config.php index 80b1aadeb8..4569038a41 100644 --- a/static/routes.config.php +++ b/static/routes.config.php @@ -90,9 +90,9 @@ return [ '/apps/verify_credentials' => [Module\Api\Mastodon\Apps\VerifyCredentials::class, [R::GET ]], '/blocks' => [Module\Api\Mastodon\Blocks::class, [R::GET ]], '/bookmarks' => [Module\Api\Mastodon\Bookmarks::class, [R::GET ]], - '/conversations' => [Module\Api\Mastodon\Conversation::class, [R::GET ]], - '/conversations/{id:\d+}' => [Module\Api\Mastodon\Conversation::class, [R::DELETE ]], - '/conversations/{id:\d+}/read' => [Module\Api\Mastodon\Conversation\Read::class, [R::POST ]], + '/conversations' => [Module\Api\Mastodon\Conversations::class, [R::GET ]], + '/conversations/{id:\d+}' => [Module\Api\Mastodon\Conversations::class, [R::DELETE ]], + '/conversations/{id:\d+}/read' => [Module\Api\Mastodon\Conversations\Read::class, [R::POST ]], '/custom_emojis' => [Module\Api\Mastodon\CustomEmojis::class, [R::GET ]], '/domain_blocks' => [Module\Api\Mastodon\Unimplemented::class, [R::GET, R::POST, R::DELETE]], // not supported '/directory' => [Module\Api\Mastodon\Directory::class, [R::GET ]], diff --git a/update.php b/update.php index a34a5dbb0b..0a97b4e10c 100644 --- a/update.php +++ b/update.php @@ -49,6 +49,7 @@ use Friendica\Database\DBStructure; use Friendica\DI; use Friendica\Model\Contact; use Friendica\Model\Item; +use Friendica\Model\ItemURI; use Friendica\Model\Notification; use Friendica\Model\Photo; use Friendica\Model\Post; @@ -912,3 +913,31 @@ function update_1413() return Update::FAILED; } } + +function update_1419() +{ + $mails = DBA::select('mail', ['id', 'from-url', 'uri', 'parent-uri', 'guid'], [], ['order' => ['id']]); + while ($mail = DBA::fetch($mails)) { + $fields = []; + $fields['author-id'] = Contact::getIdForURL($mail['from-url'], 0, false); + if (empty($fields['author-id'])) { + continue; + } + + $fields['uri-id'] = ItemURI::insert(['uri' => $mail['uri'], 'guid' => $mail['guid']]); + $fields['parent-uri-id'] = ItemURI::getIdByURI($mail['parent-uri']); + + $reply = DBA::selectFirst('mail', ['uri', 'uri-id', 'guid'], ['parent-uri' => $mail['parent-uri'], 'reply' => false]); + if (!empty($reply)) { + $fields['thr-parent'] = $reply['uri']; + if (!empty($reply['uri-id'])) { + $fields['thr-parent-id'] = $reply['uri-id']; + } else { + $fields['thr-parent-id'] = ItemURI::insert(['uri' => $reply['uri'], 'guid' => $reply['guid']]); + } + } + + DBA::update('mail', $fields, ['id' => $mail['id']]); + } + return Update::SUCCESS; +} diff --git a/view/lang/C/messages.po b/view/lang/C/messages.po index 2234a8c16c..ac5bf2bf9a 100644 --- a/view/lang/C/messages.po +++ b/view/lang/C/messages.po @@ -6,9 +6,9 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: 2021.06-dev\n" +"Project-Id-Version: 2021.06-rc\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-05-16 07:41+0000\n" +"POT-Creation-Date: 2021-05-21 18:18+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -39,8 +39,8 @@ msgstr "" #: include/api.php:4528 mod/photos.php:107 mod/photos.php:211 #: mod/photos.php:639 mod/photos.php:1043 mod/photos.php:1060 -#: mod/photos.php:1609 src/Model/User.php:1045 src/Model/User.php:1053 -#: src/Model/User.php:1061 src/Module/Settings/Profile/Photo/Crop.php:97 +#: mod/photos.php:1609 src/Model/User.php:1100 src/Model/User.php:1108 +#: src/Model/User.php:1116 src/Module/Settings/Profile/Photo/Crop.php:97 #: src/Module/Settings/Profile/Photo/Crop.php:113 #: src/Module/Settings/Profile/Photo/Crop.php:129 #: src/Module/Settings/Profile/Photo/Crop.php:178 @@ -54,7 +54,7 @@ msgstr "" msgid "%1$s poked %2$s" msgstr "" -#: include/conversation.php:227 src/Model/Item.php:2523 +#: include/conversation.php:227 src/Model/Item.php:2534 msgid "event" msgstr "" @@ -62,7 +62,7 @@ msgstr "" msgid "status" msgstr "" -#: include/conversation.php:235 mod/tagger.php:90 src/Model/Item.php:2525 +#: include/conversation.php:235 mod/tagger.php:90 src/Model/Item.php:2536 msgid "photo" msgstr "" @@ -951,7 +951,7 @@ msgstr "" msgid "list" msgstr "" -#: mod/cal.php:297 src/Console/User.php:182 src/Model/User.php:607 +#: mod/cal.php:297 src/Console/User.php:182 src/Model/User.php:662 #: src/Module/Admin/Users/Active.php:73 src/Module/Admin/Users/Blocked.php:74 #: src/Module/Admin/Users/Index.php:80 src/Module/Admin/Users/Pending.php:71 #: src/Module/Api/Twitter/ContactEndpoint.php:73 @@ -2966,7 +2966,7 @@ msgstr "" msgid "File upload failed." msgstr "" -#: mod/wall_upload.php:233 +#: mod/wall_upload.php:233 src/Model/Photo.php:953 msgid "Wall Photos" msgstr "" @@ -3636,39 +3636,39 @@ msgstr "" msgid "last" msgstr "" -#: src/Content/Text/BBCode.php:942 src/Content/Text/BBCode.php:1605 -#: src/Content/Text/BBCode.php:1606 +#: src/Content/Text/BBCode.php:942 src/Content/Text/BBCode.php:1607 +#: src/Content/Text/BBCode.php:1608 msgid "Image/photo" msgstr "" -#: src/Content/Text/BBCode.php:1064 +#: src/Content/Text/BBCode.php:1066 #, php-format msgid "" "%2$s %3$s" msgstr "" -#: src/Content/Text/BBCode.php:1089 src/Model/Item.php:3024 -#: src/Model/Item.php:3030 src/Model/Item.php:3031 +#: src/Content/Text/BBCode.php:1091 src/Model/Item.php:3035 +#: src/Model/Item.php:3041 src/Model/Item.php:3042 msgid "Link to source" msgstr "" -#: src/Content/Text/BBCode.php:1523 src/Content/Text/HTML.php:951 +#: src/Content/Text/BBCode.php:1525 src/Content/Text/HTML.php:951 msgid "Click to open/close" msgstr "" -#: src/Content/Text/BBCode.php:1554 +#: src/Content/Text/BBCode.php:1556 msgid "$1 wrote:" msgstr "" -#: src/Content/Text/BBCode.php:1608 src/Content/Text/BBCode.php:1609 +#: src/Content/Text/BBCode.php:1610 src/Content/Text/BBCode.php:1611 msgid "Encrypted content" msgstr "" -#: src/Content/Text/BBCode.php:1822 +#: src/Content/Text/BBCode.php:1824 msgid "Invalid source protocol" msgstr "" -#: src/Content/Text/BBCode.php:1837 +#: src/Content/Text/BBCode.php:1839 msgid "Invalid link protocol" msgstr "" @@ -4542,25 +4542,25 @@ msgstr "" msgid "%s: updating %s table." msgstr "" -#: src/Factory/Api/Mastodon/Error.php:32 +#: src/Factory/Api/Mastodon/Error.php:38 msgid "Record not found" msgstr "" -#: src/Factory/Api/Mastodon/Error.php:41 +#: src/Factory/Api/Mastodon/Error.php:48 msgid "Unprocessable Entity" msgstr "" -#: src/Factory/Api/Mastodon/Error.php:50 +#: src/Factory/Api/Mastodon/Error.php:58 #: src/Module/Special/HTTPException.php:50 msgid "Unauthorized" msgstr "" -#: src/Factory/Api/Mastodon/Error.php:59 +#: src/Factory/Api/Mastodon/Error.php:68 msgid "" "Token is not authorized with a valid user or is missing a required scope" msgstr "" -#: src/Factory/Api/Mastodon/Error.php:68 +#: src/Factory/Api/Mastodon/Error.php:78 #: src/Module/Special/HTTPException.php:53 msgid "Internal Server Error" msgstr "" @@ -4815,33 +4815,33 @@ msgstr "" msgid "Edit groups" msgstr "" -#: src/Model/Item.php:1582 +#: src/Model/Item.php:1600 #, php-format msgid "Detected languages in this post:\\n%s" msgstr "" -#: src/Model/Item.php:2527 +#: src/Model/Item.php:2538 msgid "activity" msgstr "" -#: src/Model/Item.php:2529 +#: src/Model/Item.php:2540 msgid "comment" msgstr "" -#: src/Model/Item.php:2532 +#: src/Model/Item.php:2543 msgid "post" msgstr "" -#: src/Model/Item.php:2646 +#: src/Model/Item.php:2657 #, php-format msgid "Content warning: %s" msgstr "" -#: src/Model/Item.php:2989 +#: src/Model/Item.php:3000 msgid "bytes" msgstr "" -#: src/Model/Item.php:3018 src/Model/Item.php:3019 +#: src/Model/Item.php:3029 src/Model/Item.php:3030 msgid "View on separate page" msgstr "" @@ -4959,138 +4959,138 @@ msgstr "" msgid "Enter a valid existing folder" msgstr "" -#: src/Model/User.php:186 src/Model/User.php:931 +#: src/Model/User.php:186 src/Model/User.php:986 msgid "SERIOUS ERROR: Generation of security keys failed." msgstr "" -#: src/Model/User.php:549 +#: src/Model/User.php:571 src/Model/User.php:604 msgid "Login failed" msgstr "" -#: src/Model/User.php:581 +#: src/Model/User.php:636 msgid "Not enough information to authenticate" msgstr "" -#: src/Model/User.php:676 +#: src/Model/User.php:731 msgid "Password can't be empty" msgstr "" -#: src/Model/User.php:695 +#: src/Model/User.php:750 msgid "Empty passwords are not allowed." msgstr "" -#: src/Model/User.php:699 +#: src/Model/User.php:754 msgid "" "The new password has been exposed in a public data dump, please choose " "another." msgstr "" -#: src/Model/User.php:705 +#: src/Model/User.php:760 msgid "" "The password can't contain accentuated letters, white spaces or colons (:)" msgstr "" -#: src/Model/User.php:811 +#: src/Model/User.php:866 msgid "Passwords do not match. Password unchanged." msgstr "" -#: src/Model/User.php:818 +#: src/Model/User.php:873 msgid "An invitation is required." msgstr "" -#: src/Model/User.php:822 +#: src/Model/User.php:877 msgid "Invitation could not be verified." msgstr "" -#: src/Model/User.php:830 +#: src/Model/User.php:885 msgid "Invalid OpenID url" msgstr "" -#: src/Model/User.php:843 src/Security/Authentication.php:224 +#: src/Model/User.php:898 src/Security/Authentication.php:224 msgid "" "We encountered a problem while logging in with the OpenID you provided. " "Please check the correct spelling of the ID." msgstr "" -#: src/Model/User.php:843 src/Security/Authentication.php:224 +#: src/Model/User.php:898 src/Security/Authentication.php:224 msgid "The error message was:" msgstr "" -#: src/Model/User.php:849 +#: src/Model/User.php:904 msgid "Please enter the required information." msgstr "" -#: src/Model/User.php:863 +#: src/Model/User.php:918 #, php-format msgid "" "system.username_min_length (%s) and system.username_max_length (%s) are " "excluding each other, swapping values." msgstr "" -#: src/Model/User.php:870 +#: src/Model/User.php:925 #, php-format msgid "Username should be at least %s character." msgid_plural "Username should be at least %s characters." msgstr[0] "" msgstr[1] "" -#: src/Model/User.php:874 +#: src/Model/User.php:929 #, php-format msgid "Username should be at most %s character." msgid_plural "Username should be at most %s characters." msgstr[0] "" msgstr[1] "" -#: src/Model/User.php:882 +#: src/Model/User.php:937 msgid "That doesn't appear to be your full (First Last) name." msgstr "" -#: src/Model/User.php:887 +#: src/Model/User.php:942 msgid "Your email domain is not among those allowed on this site." msgstr "" -#: src/Model/User.php:891 +#: src/Model/User.php:946 msgid "Not a valid email address." msgstr "" -#: src/Model/User.php:894 +#: src/Model/User.php:949 msgid "The nickname was blocked from registration by the nodes admin." msgstr "" -#: src/Model/User.php:898 src/Model/User.php:906 +#: src/Model/User.php:953 src/Model/User.php:961 msgid "Cannot use that email." msgstr "" -#: src/Model/User.php:913 +#: src/Model/User.php:968 msgid "Your nickname can only contain a-z, 0-9 and _." msgstr "" -#: src/Model/User.php:921 src/Model/User.php:978 +#: src/Model/User.php:976 src/Model/User.php:1033 msgid "Nickname is already registered. Please choose another." msgstr "" -#: src/Model/User.php:965 src/Model/User.php:969 +#: src/Model/User.php:1020 src/Model/User.php:1024 msgid "An error occurred during registration. Please try again." msgstr "" -#: src/Model/User.php:992 +#: src/Model/User.php:1047 msgid "An error occurred creating your default profile. Please try again." msgstr "" -#: src/Model/User.php:999 +#: src/Model/User.php:1054 msgid "An error occurred creating your self contact. Please try again." msgstr "" -#: src/Model/User.php:1004 +#: src/Model/User.php:1059 msgid "Friends" msgstr "" -#: src/Model/User.php:1008 +#: src/Model/User.php:1063 msgid "" "An error occurred creating your default contact group. Please try again." msgstr "" -#: src/Model/User.php:1199 +#: src/Model/User.php:1254 #, php-format msgid "" "\n" @@ -5098,7 +5098,7 @@ msgid "" "\t\t\tthe administrator of %2$s has set up an account for you." msgstr "" -#: src/Model/User.php:1202 +#: src/Model/User.php:1257 #, php-format msgid "" "\n" @@ -5135,12 +5135,12 @@ msgid "" "\t\tThank you and welcome to %4$s." msgstr "" -#: src/Model/User.php:1235 src/Model/User.php:1342 +#: src/Model/User.php:1290 src/Model/User.php:1397 #, php-format msgid "Registration details for %s" msgstr "" -#: src/Model/User.php:1255 +#: src/Model/User.php:1310 #, php-format msgid "" "\n" @@ -5156,12 +5156,12 @@ msgid "" "\t\t" msgstr "" -#: src/Model/User.php:1274 +#: src/Model/User.php:1329 #, php-format msgid "Registration at %s" msgstr "" -#: src/Model/User.php:1298 +#: src/Model/User.php:1353 #, php-format msgid "" "\n" @@ -5170,7 +5170,7 @@ msgid "" "\t\t\t" msgstr "" -#: src/Model/User.php:1306 +#: src/Model/User.php:1361 #, php-format msgid "" "\n" @@ -7201,7 +7201,7 @@ msgstr "" msgid "Deny" msgstr "" -#: src/Module/Api/Mastodon/Apps.php:47 src/Module/Api/Mastodon/Apps.php:58 +#: src/Module/Api/Mastodon/Apps.php:58 msgid "Missing parameters" msgstr "" @@ -8882,15 +8882,15 @@ msgstr "" msgid "Show all" msgstr "" -#: src/Module/OAuth/Authorize.php:49 +#: src/Module/OAuth/Authorize.php:51 msgid "Unsupported or missing response type" msgstr "" -#: src/Module/OAuth/Authorize.php:54 src/Module/OAuth/Token.php:55 +#: src/Module/OAuth/Authorize.php:56 src/Module/OAuth/Token.php:57 msgid "Incomplete request data" msgstr "" -#: src/Module/OAuth/Token.php:79 +#: src/Module/OAuth/Token.php:81 msgid "Unsupported or missing grant type" msgstr "" @@ -10585,20 +10585,20 @@ msgstr "" msgid "Contact information and Social Networks" msgstr "" -#: src/Security/Authentication.php:210 src/Security/Authentication.php:262 +#: src/Security/Authentication.php:210 msgid "Login failed." msgstr "" -#: src/Security/Authentication.php:273 +#: src/Security/Authentication.php:251 msgid "Login failed. Please check your credentials." msgstr "" -#: src/Security/Authentication.php:392 +#: src/Security/Authentication.php:370 #, php-format msgid "Welcome %s" msgstr "" -#: src/Security/Authentication.php:393 +#: src/Security/Authentication.php:371 msgid "Please upload a profile photo." msgstr "" diff --git a/view/templates/admin/features.tpl b/view/templates/admin/features.tpl index 46a7abea26..42058d5caf 100644 --- a/view/templates/admin/features.tpl +++ b/view/templates/admin/features.tpl @@ -15,7 +15,7 @@ {{/foreach}} -
+
diff --git a/view/templates/album_edit.tpl b/view/templates/album_edit.tpl index b6f24ec3b2..dd4459fe9e 100644 --- a/view/templates/album_edit.tpl +++ b/view/templates/album_edit.tpl @@ -1,10 +1,10 @@
-
+ - - + +
@@ -12,4 +12,4 @@
-
+
diff --git a/view/templates/birthdays_reminder.tpl b/view/templates/birthdays_reminder.tpl index 6aa51d4702..5fb75a993d 100644 --- a/view/templates/birthdays_reminder.tpl +++ b/view/templates/birthdays_reminder.tpl @@ -1,7 +1,7 @@ {{if $count}} -