From 616edd060097acd0fa2f05fccca3e8cc662cf156 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Wed, 9 Oct 2019 22:17:09 -0400 Subject: [PATCH 1/4] Move mod/delegate to src/Module/Settings/Delegation - Move templates/delegate to templates/settings/delegation --- doc/Forums.md | 2 +- doc/de/Forums.md | 2 +- mod/delegate.php | 191 ------------------------- mod/settings.php | 4 +- src/Content/Nav.php | 2 +- src/Module/BaseSettingsModule.php | 4 +- src/Module/Settings/Delegation.php | 175 ++++++++++++++++++++++ static/routes.config.php | 1 + view/templates/delegate.tpl | 55 ------- view/templates/settings/delegation.tpl | 48 +++++++ 10 files changed, 231 insertions(+), 253 deletions(-) delete mode 100644 mod/delegate.php create mode 100644 src/Module/Settings/Delegation.php delete mode 100644 view/templates/delegate.tpl create mode 100644 view/templates/settings/delegation.tpl diff --git a/doc/Forums.md b/doc/Forums.md index add1601c50..03657b6afe 100644 --- a/doc/Forums.md +++ b/doc/Forums.md @@ -40,7 +40,7 @@ You are not required to do this, but the alternative is to log out and log back This could get cumbersome if you manage several different forums/identities. You may also appoint a delegate to manage your forum. -Do this by visiting the [Delegation Setup Page](delegate). +Do this by visiting the [Delegation Setup Page](settings/delegation). This will provide you with a list of contacts on this system under "Potential Delegates". Selecting one or more persons will give them access to manage your forum. They will be able to edit contacts, profiles, and all content for this account/page. diff --git a/doc/de/Forums.md b/doc/de/Forums.md index ec3ad1400c..a6ddf2efde 100644 --- a/doc/de/Forums.md +++ b/doc/de/Forums.md @@ -38,7 +38,7 @@ Du musst das nicht machen, die Alternative ist allerdings, Dich immer wieder aus Und das kann umständlich sein, wenn Du mehrere verschiedene Foren/Identitäten verwaltest. Du kannst ebenso jemanden wählen, der Dein Forum verwaltet. -Mach das, indem Du die [Delegations-Setup-Seite](/delegate) besuchst. +Mach das, indem Du die [Delegations-Setup-Seite](/settings/delegation) besuchst. Dort wird Dir eine Liste an "Potentiellen Bevollmächtigen" angezeigt. Die Auswahl einer oder mehrerer Personen gibt diesen die Möglichkeit, Dein Forum zu verwalten. Sie können Kontakte, Profile und alle Inhalte Deines Accounts/deiner Seite bearbeiten. diff --git a/mod/delegate.php b/mod/delegate.php deleted file mode 100644 index 4560784515..0000000000 --- a/mod/delegate.php +++ /dev/null @@ -1,191 +0,0 @@ -user) && !empty($a->user['uid']) && $a->user['uid'] != local_user()) { - notice(L10n::t('Permission denied.') . EOL); - return; - } - - BaseModule::checkFormSecurityTokenRedirectOnError('/delegate', 'delegate'); - - $parent_uid = defaults($_POST, 'parent_user', 0); - $parent_password = defaults($_POST, 'parent_password', ''); - - if ($parent_uid != 0) { - $user = DBA::selectFirst('user', ['nickname'], ['uid' => $parent_uid]); - if (!DBA::isResult($user)) { - notice(L10n::t('Parent user not found.') . EOL); - return; - } - - $success = User::authenticate($user['nickname'], trim($parent_password)); - if (!$success) { - notice(L10n::t('Permission denied.') . EOL); - return; - } - } - - DBA::update('user', ['parent-uid' => $parent_uid], ['uid' => local_user()]); -} - -function delegate_content(App $a) -{ - if (!local_user()) { - notice(L10n::t('Permission denied.') . EOL); - return; - } - - if ($a->argc > 2 && $a->argv[1] === 'add' && intval($a->argv[2])) { - // delegated admins can view but not change delegation permissions - if (!empty($_SESSION['submanage'])) { - $a->internalRedirect('delegate'); - } - - $user_id = $a->argv[2]; - - $user = DBA::selectFirst('user', ['nickname'], ['uid' => $user_id]); - if (DBA::isResult($user)) { - $condition = [ - 'uid' => local_user(), - 'nurl' => Strings::normaliseLink(System::baseUrl() . '/profile/' . $user['nickname']) - ]; - if (DBA::exists('contact', $condition)) { - DBA::insert('manage', ['uid' => $user_id, 'mid' => local_user()]); - } - } - $a->internalRedirect('delegate'); - } - - if ($a->argc > 2 && $a->argv[1] === 'remove' && intval($a->argv[2])) { - // delegated admins can view but not change delegation permissions - if (!empty($_SESSION['submanage'])) { - $a->internalRedirect('delegate'); - } - - DBA::delete('manage', ['uid' => $a->argv[2], 'mid' => local_user()]); - $a->internalRedirect('delegate'); - } - - // find everybody that currently has delegated management to this account/page - $delegates = []; - $r = q("SELECT * FROM `user` WHERE `uid` IN (SELECT `uid` FROM `manage` WHERE `mid` = %d)", - intval(local_user()) - ); - if (DBA::isResult($r)) { - $delegates = $r; - } - - $uids = []; - foreach ($delegates as $rr) { - $uids[] = $rr['uid']; - } - - // find every contact who might be a candidate for delegation - $potentials = []; - - $r = q("SELECT `nurl` - FROM `contact` - WHERE `self` = 0 - AND SUBSTRING_INDEX(`nurl`, '/', 3) = '%s' - AND `uid` = %d - AND `network` = '%s' ", - DBA::escape(Strings::normaliseLink(System::baseUrl())), - intval(local_user()), - DBA::escape(Protocol::DFRN) - ); - if (DBA::isResult($r)) { - $nicknames = []; - foreach ($r as $rr) { - $nicknames[] = "'" . DBA::escape(basename($rr['nurl'])) . "'"; - } - - $nicks = implode(',', $nicknames); - - // get user records for all potential page delegates who are not already delegates or managers - $r = q("SELECT `uid`, `username`, `nickname` FROM `user` WHERE `nickname` IN ($nicks)"); - if (DBA::isResult($r)) { - foreach ($r as $rr) { - if (!in_array($rr['uid'], $uids)) { - $potentials[] = $rr; - } - } - } - } - - settings_init($a); - - $user = DBA::selectFirst('user', ['parent-uid', 'email'], ['uid' => local_user()]); - - $parent_user = null; - - if (DBA::isResult($user)) { - if (!DBA::exists('user', ['parent-uid' => local_user()])) { - $parent_uid = $user['parent-uid']; - $parents = [0 => L10n::t('No parent user')]; - - $fields = ['uid', 'username', 'nickname']; - $condition = ['email' => $user['email'], 'verified' => true, 'blocked' => false, 'parent-uid' => 0]; - $parent_users = DBA::select('user', $fields, $condition); - while ($parent = DBA::fetch($parent_users)) { - if ($parent['uid'] != local_user()) { - $parents[$parent['uid']] = sprintf('%s (%s)', $parent['username'], $parent['nickname']); - } - } - $parent_user = ['parent_user', '', $parent_uid, '', $parents]; - } - } - - if (!is_null($parent_user)) { - $parent_password = ['parent_password', L10n::t('Parent Password:'), '', L10n::t('Please enter the password of the parent account to legitimize your request.')]; - } else { - $parent_password = ''; - } - - $o = Renderer::replaceMacros(Renderer::getMarkupTemplate('delegate.tpl'), [ - '$form_security_token' => BaseModule::getFormSecurityToken('delegate'), - '$parent_header' => L10n::t('Parent User'), - '$parent_user' => $parent_user, - '$parent_password' => $parent_password, - '$parent_desc' => L10n::t('Parent users have total control about this account, including the account settings. Please double check whom you give this access.'), - '$submit' => L10n::t('Save Settings'), - '$header' => L10n::t('Delegate Page Management'), - '$delegates_header' => L10n::t('Delegates'), - '$base' => System::baseUrl(), - '$desc' => L10n::t('Delegates are able to manage all aspects of this account/page except for basic account settings. Please do not delegate your personal account to anybody that you do not trust completely.'), - '$head_delegates' => L10n::t('Existing Page Delegates'), - '$delegates' => $delegates, - '$head_potentials' => L10n::t('Potential Delegates'), - '$potentials' => $potentials, - '$remove' => L10n::t('Remove'), - '$add' => L10n::t('Add'), - '$none' => L10n::t('No entries.') - ]); - - - return $o; -} diff --git a/mod/settings.php b/mod/settings.php index cdc43ac222..0d519e5a07 100644 --- a/mod/settings.php +++ b/mod/settings.php @@ -115,8 +115,8 @@ function settings_init(App $a) $tabs[] = [ 'label' => L10n::t('Delegations'), - 'url' => 'delegate', - 'selected' => (($a->argc == 1) && ($a->argv[0] === 'delegate')?'active':''), + 'url' => 'settings/delegation', + 'selected' => (($a->argc > 1) && ($a->argv[1] === 'delegation')?'active':''), 'accesskey' => 'd', ]; diff --git a/src/Content/Nav.php b/src/Content/Nav.php index 8140c5f3c1..e81214cee0 100644 --- a/src/Content/Nav.php +++ b/src/Content/Nav.php @@ -260,7 +260,7 @@ class Nav $nav['manage'] = ['manage', L10n::t('Manage'), '', L10n::t('Manage other pages')]; } - $nav['delegations'] = ['delegate', L10n::t('Delegations'), '', L10n::t('Delegate Page Management')]; + $nav['delegations'] = ['settings/delegation', L10n::t('Delegations'), '', L10n::t('Delegate Page Management')]; $nav['settings'] = ['settings', L10n::t('Settings'), '', L10n::t('Account settings')]; diff --git a/src/Module/BaseSettingsModule.php b/src/Module/BaseSettingsModule.php index fdf3c81664..4c9173db79 100644 --- a/src/Module/BaseSettingsModule.php +++ b/src/Module/BaseSettingsModule.php @@ -73,8 +73,8 @@ class BaseSettingsModule extends BaseModule $tabs[] = [ 'label' => L10n::t('Delegations'), - 'url' => 'delegate', - 'selected' => (($a->argc == 1) && ($a->argv[0] === 'delegate') ? 'active' : ''), + 'url' => 'settings/delegation', + 'selected' => (($a->argc > 1) && ($a->argv[1] === 'delegation') ? 'active' : ''), 'accesskey' => 'd', ]; diff --git a/src/Module/Settings/Delegation.php b/src/Module/Settings/Delegation.php new file mode 100644 index 0000000000..4e077b9be6 --- /dev/null +++ b/src/Module/Settings/Delegation.php @@ -0,0 +1,175 @@ +user['uid']) && self::getApp()->user['uid'] != local_user()) { + throw new HTTPException\ForbiddenException(L10n::t('Permission denied.')); + } + + BaseModule::checkFormSecurityTokenRedirectOnError('settings/delegation', 'delegate'); + + $parent_uid = $_POST['parent_user'] ?? 0; + $parent_password = $_POST['parent_password'] ?? ''; + + if ($parent_uid != 0) { + $user = DBA::selectFirst('user', ['nickname'], ['uid' => $parent_uid]); + if (!DBA::isResult($user)) { + notice(L10n::t('Parent user not found.')); + return; + } + + try { + User::getIdFromPasswordAuthentication($user['nickname'], $parent_password); + info(L10n::t('Delegation successfully granted.')); + } catch (\Throwable $ex) { + notice(L10n::t('Parent user password doesn\'t match.')); + return; + } + } else { + info(L10n::t('Delegation successfully revoked.')); + } + + DBA::update('user', ['parent-uid' => $parent_uid], ['uid' => local_user()]); + } + + public static function content() + { + parent::content(); + + if (!local_user()) { + throw new HTTPException\ForbiddenException(L10n::t('Permission denied.')); + } + + /** @var Arguments $args */ + $args = self::getClass(Arguments::class); + + $action = $args->get(2); + $user_id = $args->get(3); + if ($action === 'add' && $user_id) { + if (Session::get('submanage')) { + notice(L10n::t('Delegated administrators can view but not change delegation permissions.')); + self::getApp()->internalRedirect('settings/delegation'); + } + + $user = DBA::selectFirst('user', ['nickname'], ['uid' => $user_id]); + if (DBA::isResult($user)) { + $condition = [ + 'uid' => local_user(), + 'nurl' => Strings::normaliseLink(System::baseUrl() . '/profile/' . $user['nickname']) + ]; + if (DBA::exists('contact', $condition)) { + DBA::insert('manage', ['uid' => $user_id, 'mid' => local_user()]); + } + } else { + notice(L10n::t('Delegate user not found.')); + } + + self::getApp()->internalRedirect('settings/delegation'); + } + + if ($action === 'remove' && $user_id) { + if (Session::get('submanage')) { + notice(L10n::t('Delegated administrators can view but not change delegation permissions.')); + self::getApp()->internalRedirect('settings/delegation'); + } + + DBA::delete('manage', ['uid' => $user_id, 'mid' => local_user()]); + self::getApp()->internalRedirect('settings/delegation'); + } + + // find everybody that currently has delegated management to this account/page + $delegates = DBA::selectToArray('user', [], ['`uid` IN (SELECT `uid` FROM `manage` WHERE `mid` = ?)', local_user()]); + + $uids = []; + foreach ($delegates as $user) { + $uids[] = $user['uid']; + } + + // find every contact who might be a candidate for delegation + $potentials = []; + + $contacts = DBA::selectToArray( + 'contact', + ['nurl'], + [ + "`self` = 0 AND SUBSTRING_INDEX(`nurl`, '/', 3) = ? AND `uid` = ? AND `network` = ?", + Strings::normaliseLink(System::baseUrl()), + local_user(), + Protocol::DFRN, + ] + ); + if ($contacts) { + $nicknames = []; + foreach ($contacts as $contact) { + $nicknames[] = "'" . DBA::escape(basename($contact['nurl'])) . "'"; + } + + // get user records for all potential page delegates who are not already delegates or managers + $potentialDelegateUsers = DBA::selectToArray('user', ['uid', 'username', 'nickname'], ['nickname' => $nicknames]); + foreach ($potentialDelegateUsers as $user) { + if (!in_array($user['uid'], $uids)) { + $potentials[] = $user; + } + } + } + + $parent_user = null; + $parent_password = null; + $user = DBA::selectFirst('user', ['parent-uid', 'email'], ['uid' => local_user()]); + if (DBA::isResult($user) && !DBA::exists('user', ['parent-uid' => local_user()])) { + $parent_uid = $user['parent-uid']; + $parents = [0 => L10n::t('No parent user')]; + + $fields = ['uid', 'username', 'nickname']; + $condition = ['email' => $user['email'], 'verified' => true, 'blocked' => false, 'parent-uid' => 0]; + $parent_users = DBA::selectToArray('user', $fields, $condition); + foreach($parent_users as $parent) { + if ($parent['uid'] != local_user()) { + $parents[$parent['uid']] = sprintf('%s (%s)', $parent['username'], $parent['nickname']); + } + } + + $parent_user = ['parent_user', '', $parent_uid, '', $parents]; + $parent_password = ['parent_password', L10n::t('Parent Password:'), '', L10n::t('Please enter the password of the parent account to legitimize your request.')]; + } + + $o = Renderer::replaceMacros(Renderer::getMarkupTemplate('settings/delegation.tpl'), [ + '$form_security_token' => BaseModule::getFormSecurityToken('delegate'), + '$parent_header' => L10n::t('Parent User'), + '$parent_user' => $parent_user, + '$parent_password' => $parent_password, + '$parent_desc' => L10n::t('Parent users have total control about this account, including the account settings. Please double check whom you give this access.'), + '$submit' => L10n::t('Save Settings'), + '$header' => L10n::t('Delegate Page Management'), + '$delegates_header' => L10n::t('Delegates'), + '$base' => System::baseUrl(), + '$desc' => L10n::t('Delegates are able to manage all aspects of this account/page except for basic account settings. Please do not delegate your personal account to anybody that you do not trust completely.'), + '$head_delegates' => L10n::t('Existing Page Delegates'), + '$delegates' => $delegates, + '$head_potentials' => L10n::t('Potential Delegates'), + '$potentials' => $potentials, + '$remove' => L10n::t('Remove'), + '$add' => L10n::t('Add'), + '$none' => L10n::t('No entries.') + ]); + + return $o; + } +} diff --git a/static/routes.config.php b/static/routes.config.php index 73ac54991f..23a6bf9982 100644 --- a/static/routes.config.php +++ b/static/routes.config.php @@ -199,6 +199,7 @@ return [ '/app_specific' => [Module\Settings\TwoFactor\AppSpecific::class, [R::GET, R::POST]], '/verify' => [Module\Settings\TwoFactor\Verify::class, [R::GET, R::POST]], ], + '/delegation[/{action}/{user_id}]' => [Module\Settings\Delegation::class, [R::GET, R::POST]], ], '/randprof' => [Module\RandomProfile::class, [R::GET]], diff --git a/view/templates/delegate.tpl b/view/templates/delegate.tpl deleted file mode 100644 index 0a875515d6..0000000000 --- a/view/templates/delegate.tpl +++ /dev/null @@ -1,55 +0,0 @@ -

{{$header}}

- -{{if $parent_user}} -

{{$parent_header}}

-
{{$parent_desc}}
-
-
- -{{include file="field_select.tpl" field=$parent_user}} -{{include file="field_password.tpl" field=$parent_password}} -
-
-
-{{/if}} - -

{{$delegates_header}}

- -
{{$desc nofilter}}
- -

{{$head_delegates}}

- -{{if $delegates}} -{{foreach $delegates as $x}} - -
- - - -
- -{{/foreach}} -
-{{else}} -{{$none}} -{{/if}} -
- - -

{{$head_potentials}}

-{{if $potentials}} -{{foreach $potentials as $x}} - -
- - - -
- -{{/foreach}} -
-{{else}} -{{$none}} -{{/if}} -
- diff --git a/view/templates/settings/delegation.tpl b/view/templates/settings/delegation.tpl new file mode 100644 index 0000000000..9e7242de67 --- /dev/null +++ b/view/templates/settings/delegation.tpl @@ -0,0 +1,48 @@ +

{{$header}}

+ +{{if $parent_user}} +

{{$parent_header}}

+
{{$parent_desc}}
+
+
+ + {{include file="field_select.tpl" field=$parent_user}} + {{include file="field_password.tpl" field=$parent_password}} +
+
+
+{{/if}} + +

{{$delegates_header}}

+ +
{{$desc nofilter}}
+ +

{{$head_delegates}}

+ +{{if $delegates}} + {{foreach $delegates as $x}} +
+ + + +
+ {{/foreach}} +
+{{else}} + {{$none}} +{{/if}} +
+ +

{{$head_potentials}}

+{{if $potentials}} + {{foreach $potentials as $x}} +
+ + + +
+ {{/foreach}} +
+{{else}} + {{$none}} +{{/if}} From cc0cf2b8ce8c758293460a93806e1b3007ad5d12 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Thu, 10 Oct 2019 04:10:29 -0400 Subject: [PATCH 2/4] Improve parent user password check in Module/Settings/Delegation --- src/Module/Settings/Delegation.php | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/Module/Settings/Delegation.php b/src/Module/Settings/Delegation.php index 4e077b9be6..5cb2f399ca 100644 --- a/src/Module/Settings/Delegation.php +++ b/src/Module/Settings/Delegation.php @@ -29,17 +29,11 @@ class Delegation extends BaseSettingsModule $parent_password = $_POST['parent_password'] ?? ''; if ($parent_uid != 0) { - $user = DBA::selectFirst('user', ['nickname'], ['uid' => $parent_uid]); - if (!DBA::isResult($user)) { - notice(L10n::t('Parent user not found.')); - return; - } - try { - User::getIdFromPasswordAuthentication($user['nickname'], $parent_password); + User::getIdFromPasswordAuthentication($parent_uid, $parent_password); info(L10n::t('Delegation successfully granted.')); - } catch (\Throwable $ex) { - notice(L10n::t('Parent user password doesn\'t match.')); + } catch (\Exception $ex) { + notice(L10n::t('Parent user not found, unavailable or password doesn\'t match.')); return; } } else { From 3cd916d7aa8bcca743849f2db7ba0183028857ea Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Thu, 10 Oct 2019 04:10:57 -0400 Subject: [PATCH 3/4] Use Model\User::getById when possible in Module\Settings\Delegation --- src/Module/Settings/Delegation.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Module/Settings/Delegation.php b/src/Module/Settings/Delegation.php index 5cb2f399ca..247d16de03 100644 --- a/src/Module/Settings/Delegation.php +++ b/src/Module/Settings/Delegation.php @@ -62,7 +62,7 @@ class Delegation extends BaseSettingsModule self::getApp()->internalRedirect('settings/delegation'); } - $user = DBA::selectFirst('user', ['nickname'], ['uid' => $user_id]); + $user = User::getById($user_id, ['nickname']); if (DBA::isResult($user)) { $condition = [ 'uid' => local_user(), @@ -126,7 +126,7 @@ class Delegation extends BaseSettingsModule $parent_user = null; $parent_password = null; - $user = DBA::selectFirst('user', ['parent-uid', 'email'], ['uid' => local_user()]); + $user = User::getById(local_user(), ['parent-uid', 'email']); if (DBA::isResult($user) && !DBA::exists('user', ['parent-uid' => local_user()])) { $parent_uid = $user['parent-uid']; $parents = [0 => L10n::t('No parent user')]; From 43567bcf0e6138b83fa35d69c3182ae3e25a77eb Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Thu, 10 Oct 2019 04:17:37 -0400 Subject: [PATCH 4/4] Add documentation comments to Module\Settings\Delegation --- src/Module/Settings/Delegation.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Module/Settings/Delegation.php b/src/Module/Settings/Delegation.php index 247d16de03..f7edc72c94 100644 --- a/src/Module/Settings/Delegation.php +++ b/src/Module/Settings/Delegation.php @@ -15,6 +15,9 @@ use Friendica\Module\BaseSettingsModule; use Friendica\Network\HTTPException; use Friendica\Util\Strings; +/** + * Account delegation settings module + */ class Delegation extends BaseSettingsModule { public static function post() @@ -54,8 +57,10 @@ class Delegation extends BaseSettingsModule /** @var Arguments $args */ $args = self::getClass(Arguments::class); + // @TODO Replace with router-provided arguments $action = $args->get(2); $user_id = $args->get(3); + if ($action === 'add' && $user_id) { if (Session::get('submanage')) { notice(L10n::t('Delegated administrators can view but not change delegation permissions.'));