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}}