Centralize config.admin_email management in Model\User

This commit is contained in:
Hypolite Petovan 2022-11-12 12:01:22 -05:00
parent cbe8d463b1
commit fe547b7851
11 changed files with 134 additions and 134 deletions

View File

@ -27,6 +27,7 @@ use Friendica\App\BaseURL;
use Friendica\Capabilities\ICanCreateResponses; use Friendica\Capabilities\ICanCreateResponses;
use Friendica\Core\Config\Factory\Config; use Friendica\Core\Config\Factory\Config;
use Friendica\Core\Session\Capability\IHandleUserSessions; use Friendica\Core\Session\Capability\IHandleUserSessions;
use Friendica\Model\User;
use Friendica\Module\Maintenance; use Friendica\Module\Maintenance;
use Friendica\Security\Authentication; use Friendica\Security\Authentication;
use Friendica\Core\Config\ValueObject\Cache; use Friendica\Core\Config\ValueObject\Cache;
@ -164,14 +165,16 @@ class App
* Check if current user has admin role. * Check if current user has admin role.
* *
* @return bool true if user is an admin * @return bool true if user is an admin
* @throws Exception
*/ */
public function isSiteAdmin(): bool public function isSiteAdmin(): bool
{ {
$admin_email = $this->config->get('config', 'admin_email'); return
$this->session->getLocalUserId()
$adminlist = explode(',', str_replace(' ', '', $admin_email)); && $this->database->exists('user', [
'uid' => $this->getLoggedInUserId(),
return $this->session->getLocalUserId() && $admin_email && $this->database->exists('user', ['uid' => $this->getLoggedInUserId(), 'email' => $adminlist]); 'email' => User::getAdminEmailList()
]);
} }
/** /**
@ -259,8 +262,8 @@ class App
/** /**
* Set workerqueue information * Set workerqueue information
* *
* @param array $queue * @param array $queue
* @return void * @return void
*/ */
public function setQueue(array $queue) public function setQueue(array $queue)
{ {

View File

@ -26,6 +26,7 @@ use Friendica\App\Mode;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\Database\DBStructure; use Friendica\Database\DBStructure;
use Friendica\DI; use Friendica\DI;
use Friendica\Model\User;
use Friendica\Network\HTTPException\InternalServerErrorException; use Friendica\Network\HTTPException\InternalServerErrorException;
use Friendica\Util\DateTimeFormat; use Friendica\Util\DateTimeFormat;
use Friendica\Util\Strings; use Friendica\Util\Strings;
@ -148,7 +149,7 @@ class Update
} }
DI::config()->set('system', 'maintenance', 1); DI::config()->set('system', 'maintenance', 1);
// run the pre_update_nnnn functions in update.php // run the pre_update_nnnn functions in update.php
for ($version = $stored + 1; $version <= $current; $version++) { for ($version = $stored + 1; $version <= $current; $version++) {
Logger::notice('Execute pre update.', ['version' => $version]); Logger::notice('Execute pre update.', ['version' => $version]);
@ -289,30 +290,16 @@ class Update
* @return void * @return void
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/ */
private static function updateFailed(int $update_id, string $error_message) { private static function updateFailed(int $update_id, string $error_message)
//send the administrators an e-mail {
$condition = ['email' => explode(',', str_replace(' ', '', DI::config()->get('config', 'admin_email'))), 'parent-uid' => 0]; $adminEmails = User::getAdminListForEmailing(['uid', 'language', 'email']);
$adminlist = DBA::select('user', ['uid', 'language', 'email'], $condition, ['order' => ['uid']]); if (!$adminEmails) {
// No valid result?
if (!DBA::isResult($adminlist)) {
Logger::warning('Cannot notify administrators .', ['update' => $update_id, 'message' => $error_message]); Logger::warning('Cannot notify administrators .', ['update' => $update_id, 'message' => $error_message]);
// Don't continue
return; return;
} }
$sent = []; foreach($adminEmails as $admin) {
$l10n = DI::l10n()->withLang($admin['language'] ?: 'en');
// every admin could had different language
while ($admin = DBA::fetch($adminlist)) {
if (in_array($admin['email'], $sent)) {
continue;
}
$sent[] = $admin['email'];
$lang = $admin['language'] ?? 'en';
$l10n = DI::l10n()->withLang($lang);
$preamble = Strings::deindent($l10n->t(" $preamble = Strings::deindent($l10n->t("
The friendica developers released update %s recently, The friendica developers released update %s recently,
@ -343,35 +330,20 @@ class Update
*/ */
private static function updateSuccessful(int $from_build, int $to_build) private static function updateSuccessful(int $from_build, int $to_build)
{ {
//send the administrators an e-mail foreach(User::getAdminListForEmailing(['uid', 'language', 'email']) as $admin) {
$condition = ['email' => explode(',', str_replace(' ', '', DI::config()->get('config', 'admin_email'))), 'parent-uid' => 0]; $l10n = DI::l10n()->withLang($admin['language'] ?: 'en');
$adminlist = DBA::select('user', ['uid', 'language', 'email'], $condition, ['order' => ['uid']]);
if (DBA::isResult($adminlist)) { $preamble = Strings::deindent($l10n->t('
$sent = []; The friendica database was successfully updated from %s to %s.',
$from_build, $to_build));
// every admin could had different language $email = DI::emailer()
while ($admin = DBA::fetch($adminlist)) { ->newSystemMail()
if (in_array($admin['email'], $sent)) { ->withMessage($l10n->t('[Friendica Notify] Database update'), $preamble)
continue; ->forUser($admin)
} ->withRecipient($admin['email'])
$sent[] = $admin['email']; ->build();
DI::emailer()->send($email);
$lang = (($admin['language']) ? $admin['language'] : 'en');
$l10n = DI::l10n()->withLang($lang);
$preamble = Strings::deindent($l10n->t('
The friendica database was successfully updated from %s to %s.',
$from_build, $to_build));
$email = DI::emailer()
->newSystemMail()
->withMessage($l10n->t('[Friendica Notify] Database update'), $preamble)
->forUser($admin)
->withRecipient($admin['email'])
->build();
DI::emailer()->send($email);
}
} }
Logger::debug('Database structure update successful.'); Logger::debug('Database structure update successful.');

View File

@ -164,25 +164,16 @@ class Nodeinfo
* *
* @param IManageConfigValues $config Configuration instance * @param IManageConfigValues $config Configuration instance
* @return array Organization information * @return array Organization information
* @throws \Exception
*/ */
public static function getOrganization(IManageConfigValues $config): array public static function getOrganization(IManageConfigValues $config): array
{ {
$organization = [ $administrator = User::getFirstAdmin(['username', 'email', 'nickname']);
'name' => null,
'contact' => null, return [
'account' => null 'name' => $administrator['username'] ?? null,
'contact' => $administrator['email'] ?? null,
'account' => $administrator['nickname'] ?? '' ? DI::baseUrl()->get() . '/profile/' . $administrator['nickname'] : null,
]; ];
if (!empty($config->get('config', 'admin_email'))) {
$adminList = explode(',', str_replace(' ', '', $config->get('config', 'admin_email')));
$organization['contact'] = $adminList[0];
$administrator = User::getByEmail($adminList[0], ['username', 'nickname']);
if (!empty($administrator)) {
$organization['name'] = $administrator['username'];
$organization['account'] = DI::baseUrl()->get() . '/profile/' . $administrator['nickname'];
}
}
return $organization;
} }
} }

View File

@ -381,17 +381,15 @@ class User
* *
* @param array $fields * @param array $fields
* @return array user * @return array user
* @throws Exception
*/ */
public static function getFirstAdmin(array $fields = []) : array public static function getFirstAdmin(array $fields = []) : array
{ {
if (!empty(DI::config()->get('config', 'admin_nickname'))) { if (!empty(DI::config()->get('config', 'admin_nickname'))) {
return self::getByNickname(DI::config()->get('config', 'admin_nickname'), $fields); return self::getByNickname(DI::config()->get('config', 'admin_nickname'), $fields);
} elseif (!empty(DI::config()->get('config', 'admin_email'))) {
$adminList = explode(',', str_replace(' ', '', DI::config()->get('config', 'admin_email')));
return self::getByEmail($adminList[0], $fields);
} else {
return [];
} }
return self::getAdminList()[0] ?? [];
} }
/** /**
@ -1054,11 +1052,8 @@ class User
// Disallow somebody creating an account using openid that uses the admin email address, // Disallow somebody creating an account using openid that uses the admin email address,
// since openid bypasses email verification. We'll allow it if there is not yet an admin account. // since openid bypasses email verification. We'll allow it if there is not yet an admin account.
if (DI::config()->get('config', 'admin_email') && strlen($openid_url)) { if (strlen($openid_url) && in_array(strtolower($email), self::getAdminEmailList())) {
$adminlist = explode(',', str_replace(' ', '', strtolower(DI::config()->get('config', 'admin_email')))); throw new Exception(DI::l10n()->t('Cannot use that email.'));
if (in_array(strtolower($email), $adminlist)) {
throw new Exception(DI::l10n()->t('Cannot use that email.'));
}
} }
$nickname = $data['nickname'] = strtolower($nickname); $nickname = $data['nickname'] = strtolower($nickname);
@ -1783,4 +1778,64 @@ class User
return DBA::selectToArray('owner-view', [], $condition, $param); return DBA::selectToArray('owner-view', [], $condition, $param);
} }
/**
* Returns a list of lowercase admin email addresses from the comma-separated list in the config
*
* @return array
*/
public static function getAdminEmailList(): array
{
$adminEmails = strtolower(str_replace(' ', '', DI::config()->get('config', 'admin_email')));
if (!$adminEmails) {
return [];
}
return explode(',', $adminEmails);
}
/**
* Returns the complete list of admin user accounts
*
* @param array $fields
* @return array
* @throws Exception
*/
public static function getAdminList(array $fields = []): array
{
$condition = [
'email' => self::getAdminEmailList(),
'parent-uid' => 0,
'blocked' => 0,
'verified' => true,
'account_removed' => false,
'account_expired' => false,
];
return DBA::selectToArray('user', $fields, $condition, ['order' => ['uid']]);
}
/**
* Return a list of admin user accounts where each unique email address appears only once.
*
* This method is meant for admin notifications that do not need to be sent multiple times to the same email address.
*
* @param array $fields
* @return array
* @throws Exception
*/
public static function getAdminListForEmailing(array $fields = []): array
{
return array_filter(self::getAdminList($fields), function ($user) {
static $emails = [];
if (in_array($user['email'], $emails)) {
return false;
}
$emails[] = $user['email'];
return true;
});
}
} }

View File

@ -23,6 +23,7 @@ namespace Friendica\Module\Api\GNUSocial\GNUSocial;
use Friendica\App; use Friendica\App;
use Friendica\DI; use Friendica\DI;
use Friendica\Model\User;
use Friendica\Module\BaseApi; use Friendica\Module\BaseApi;
use Friendica\Module\Register; use Friendica\Module\Register;
@ -42,7 +43,7 @@ class Config extends BaseApi
'logo' => DI::baseUrl() . '/images/friendica-64.png', 'logo' => DI::baseUrl() . '/images/friendica-64.png',
'fancy' => true, 'fancy' => true,
'language' => DI::config()->get('system', 'language'), 'language' => DI::config()->get('system', 'language'),
'email' => DI::config()->get('config', 'admin_email'), 'email' => implode(',', User::getAdminEmailList()),
'broughtby' => '', 'broughtby' => '',
'broughtbyurl' => '', 'broughtbyurl' => '',
'timezone' => DI::config()->get('system', 'default_timezone'), 'timezone' => DI::config()->get('system', 'default_timezone'),

View File

@ -113,7 +113,7 @@ abstract class BaseUsers extends BaseModeration
protected function setupUserCallback(): \Closure protected function setupUserCallback(): \Closure
{ {
$adminlist = explode(',', str_replace(' ', '', DI::config()->get('config', 'admin_email'))); $adminlist = User::getAdminEmailList();
return function ($user) use ($adminlist) { return function ($user) use ($adminlist) {
$page_types = [ $page_types = [
User::PAGE_FLAGS_NORMAL => $this->t('Normal Account Page'), User::PAGE_FLAGS_NORMAL => $this->t('Normal Account Page'),

View File

@ -352,7 +352,7 @@ class Register extends BaseModule
DI::baseUrl()->redirect(); DI::baseUrl()->redirect();
} }
} elseif (intval(DI::config()->get('config', 'register_policy')) === self::APPROVE) { } elseif (intval(DI::config()->get('config', 'register_policy')) === self::APPROVE) {
if (!strlen(DI::config()->get('config', 'admin_email'))) { if (!User::getAdminEmailList()) {
DI::sysmsg()->addNotice(DI::l10n()->t('Your registration can not be processed.')); DI::sysmsg()->addNotice(DI::l10n()->t('Your registration can not be processed.'));
DI::baseUrl()->redirect(); DI::baseUrl()->redirect();
} }
@ -387,34 +387,23 @@ class Register extends BaseModule
DI::sysmsg()->addInfo(DI::l10n()->t('Your registration is pending approval by the site owner.')); DI::sysmsg()->addInfo(DI::l10n()->t('Your registration is pending approval by the site owner.'));
DI::baseUrl()->redirect(); DI::baseUrl()->redirect();
} }
return;
} }
private function sendNotification(array $user, string $event) private function sendNotification(array $user, string $event)
{ {
// send email to admins foreach (User::getAdminListForEmailing(['uid', 'language', 'email']) as $admin) {
$admins_stmt = DBA::select(
'user',
['uid', 'language', 'email'],
['email' => explode(',', str_replace(' ', '', DI::config()->get('config', 'admin_email')))]
);
// send notification to admins
while ($admin = DBA::fetch($admins_stmt)) {
DI::notify()->createFromArray([ DI::notify()->createFromArray([
'type' => Model\Notification\Type::SYSTEM, 'type' => Model\Notification\Type::SYSTEM,
'event' => $event, 'event' => $event,
'uid' => $admin['uid'], 'uid' => $admin['uid'],
'link' => DI::baseUrl()->get(true) . '/moderation/users/', 'link' => DI::baseUrl()->get(true) . '/moderation/users/',
'source_name' => $user['username'], 'source_name' => $user['username'],
'source_mail' => $user['email'], 'source_mail' => $user['email'],
'source_nick' => $user['nickname'], 'source_nick' => $user['nickname'],
'source_link' => DI::baseUrl()->get(true) . '/moderation/users/', 'source_link' => DI::baseUrl()->get(true) . '/moderation/users/',
'source_photo' => User::getAvatarUrl($user, Proxy::SIZE_THUMB), 'source_photo' => User::getAvatarUrl($user, Proxy::SIZE_THUMB),
'show_in_notification_page' => false 'show_in_notification_page' => false
]); ]);
} }
DBA::close($admins_stmt);
} }
} }

View File

@ -113,12 +113,9 @@ class Account extends BaseSettings
$err .= DI::l10n()->t('Invalid email.'); $err .= DI::l10n()->t('Invalid email.');
} }
// ensure new email is not the admin mail // ensure new email is not the admin mail
if (DI::config()->get('config', 'admin_email')) { if (in_array(strtolower($email), User::getAdminEmailList())) {
$adminlist = explode(",", str_replace(" ", "", strtolower(DI::config()->get('config', 'admin_email')))); $err .= DI::l10n()->t('Cannot change to that email.');
if (in_array(strtolower($email), $adminlist)) { $email = $user['email'];
$err .= DI::l10n()->t('Cannot change to that email.');
$email = $user['email'];
}
} }
} }

View File

@ -85,14 +85,8 @@ class RemoveMe extends BaseSettings
} }
// send notification to admins so that they can clean up the backups // send notification to admins so that they can clean up the backups
$admin_mails = explode(',', $this->config->get('config', 'admin_email')); foreach (User::getAdminListForEmailing(['uid', 'language', 'email']) as $admin) {
foreach ($admin_mails as $mail) { $l10n = $this->l10n->withLang($admin['language'] ?: 'en');
$admin = $this->database->selectFirst('user', ['uid', 'language', 'email', 'username'], ['email' => trim($mail)]);
if (!$admin) {
continue;
}
$l10n = $this->l10n->withLang($admin['language']);
$email = $this->emailer $email = $this->emailer
->newSystemMail() ->newSystemMail()

View File

@ -86,7 +86,7 @@ class Instance extends BaseDataTransferObject
$this->uri = $baseUrl->get(); $this->uri = $baseUrl->get();
$this->title = $config->get('config', 'sitename'); $this->title = $config->get('config', 'sitename');
$this->short_description = $this->description = $config->get('config', 'info'); $this->short_description = $this->description = $config->get('config', 'info');
$this->email = $config->get('config', 'admin_email'); $this->email = implode(',', User::getAdminEmailList());
$this->version = '2.8.0 (compatible; Friendica ' . App::VERSION . ')'; $this->version = '2.8.0 (compatible; Friendica ' . App::VERSION . ')';
$this->urls = null; // Not supported $this->urls = null; // Not supported
$this->stats = new Stats($config, $database); $this->stats = new Stats($config, $database);
@ -98,13 +98,10 @@ class Instance extends BaseDataTransferObject
$this->invites_enabled = false; $this->invites_enabled = false;
$this->contact_account = []; $this->contact_account = [];
if (!empty($config->get('config', 'admin_email'))) { $administrator = User::getFirstAdmin(['nickname']);
$adminList = explode(',', str_replace(' ', '', $config->get('config', 'admin_email'))); if ($administrator) {
$administrator = User::getByEmail($adminList[0], ['nickname']); $adminContact = $database->selectFirst('contact', ['uri-id'], ['nick' => $administrator['nickname'], 'self' => true]);
if (!empty($administrator)) { $this->contact_account = DI::mstdnAccount()->createFromUriId($adminContact['uri-id']);
$adminContact = $database->selectFirst('contact', ['id'], ['nick' => $administrator['nickname'], 'self' => true]);
$this->contact_account = DI::mstdnAccount()->createFromContactId($adminContact['id']);
}
} }
} }
} }

View File

@ -1710,7 +1710,7 @@ class Transmitter
} }
$data['attachment'] = self::createAttachmentList($item); $data['attachment'] = self::createAttachmentList($item);
$data['tag'] = self::createTagList($item, $data['quoteUrl'] ?? ''); $data['tag'] = self::createTagList($item, $data['quoteUrl'] ?? '');
if (empty($data['location']) && (!empty($item['coord']) || !empty($item['location']))) { if (empty($data['location']) && (!empty($item['coord']) || !empty($item['location']))) {
$data['location'] = self::createLocation($item); $data['location'] = self::createLocation($item);
@ -2073,13 +2073,14 @@ class Transmitter
} }
if (empty($uid)) { if (empty($uid)) {
// Fetch the list of administrators
$admin_mail = explode(',', str_replace(' ', '', DI::config()->get('config', 'admin_email')));
// We need to use some user as a sender. It doesn't care who it will send. We will use an administrator account. // We need to use some user as a sender. It doesn't care who it will send. We will use an administrator account.
$condition = ['verified' => true, 'blocked' => false, 'account_removed' => false, 'account_expired' => false, 'email' => $admin_mail]; $admin = User::getFirstAdmin(['uid']);
$first_user = DBA::selectFirst('user', ['uid'], $condition); if (!$admin) {
$uid = $first_user['uid']; Logger::warning('No available admin user for transmission', ['target' => $target]);
return false;
}
$uid = $admin['uid'];
} }
$condition = ['verb' => Activity::FOLLOW, 'uid' => 0, 'parent-uri' => $object, $condition = ['verb' => Activity::FOLLOW, 'uid' => 0, 'parent-uri' => $object,