Merge branch 'fix-message-button' of https://github.com/very-ape/friendica into fix-message-button

This commit is contained in:
very-ape 2021-05-22 15:32:08 -07:00
commit b2bc911eb2
8 changed files with 149 additions and 105 deletions

View file

@ -1 +1 @@
2021.06-dev
2021.06-rc

View file

@ -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);

View file

@ -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/)

View file

@ -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'));

View file

@ -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 = [])
{

View file

@ -19,7 +19,7 @@
*
*/
namespace Friendica\Module\Api\Mastodon\Conversation;
namespace Friendica\Module\Api\Mastodon\Conversations;
use Friendica\Core\System;
use Friendica\Database\DBA;

View file

@ -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 ]],

View file

@ -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 <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\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 ""
"<a href=\"%1$s\" target=\"_blank\" rel=\"noopener noreferrer\">%2$s</a> %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 ""