diff --git a/src/Module/Admin/BaseUsers.php b/src/Module/Admin/BaseUsers.php new file mode 100644 index 0000000000..97b10f41fb --- /dev/null +++ b/src/Module/Admin/BaseUsers.php @@ -0,0 +1,129 @@ +. + * + */ + +namespace Friendica\Module\Admin; + +use Friendica\Core\Renderer; +use Friendica\Database\DBA; +use Friendica\DI; +use Friendica\Model\Register; +use Friendica\Model\User; +use Friendica\Module\BaseAdmin; +use Friendica\Util\Temporal; + +abstract class BaseUsers extends BaseAdmin +{ + /** + * Get the users admin tabs menu + * + * @param string $selectedTab + * @return string HTML + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + */ + protected static function getTabsHTML(string $selectedTab) + { + $active = DBA::count('user', ['blocked' => false, 'verified' => true, 'account_removed' => false]); + $pending = Register::getPendingCount(); + $blocked = DBA::count('user', ['blocked' => true, 'verified' => true]); + $deleted = DBA::count('user', ['account_removed' => true]); + + $tabs = [ + [ + 'label' => DI::l10n()->t('All') . ' (' . DBA::count('user') . ')', + 'url' => 'admin/users', + 'sel' => !$selectedTab || $selectedTab == 'all' ? 'active' : '', + 'title' => DI::l10n()->t('List of all users'), + 'id' => 'admin-users-all', + 'accesskey' => 'a', + ], + [ + 'label' => DI::l10n()->t('Active') . ' (' . $active . ')', + 'url' => 'admin/users/active', + 'sel' => $selectedTab == 'active' ? 'active' : '', + 'title' => DI::l10n()->t('List of active accounts'), + 'id' => 'admin-users-active', + 'accesskey' => 'k', + ], + [ + 'label' => DI::l10n()->t('Pending') . ($pending ? ' (' . $pending . ')' : ''), + 'url' => 'admin/users/pending', + 'sel' => $selectedTab == 'pending' ? 'active' : '', + 'title' => DI::l10n()->t('List of pending registrations'), + 'id' => 'admin-users-pending', + 'accesskey' => 'p', + ], + [ + 'label' => DI::l10n()->t('Blocked') . ($blocked ? ' (' . $blocked . ')' : ''), + 'url' => 'admin/users/blocked', + 'sel' => $selectedTab == 'blocked' ? 'active' : '', + 'title' => DI::l10n()->t('List of blocked users'), + 'id' => 'admin-users-blocked', + 'accesskey' => 'b', + ], + [ + 'label' => DI::l10n()->t('Deleted') . ($deleted ? ' (' . $deleted . ')' : ''), + 'url' => 'admin/users/deleted', + 'sel' => $selectedTab == 'deleted' ? 'active' : '', + 'title' => DI::l10n()->t('List of pending user deletions'), + 'id' => 'admin-users-deleted', + 'accesskey' => 'd', + ], + ]; + + $tpl = Renderer::getMarkupTemplate('common_tabs.tpl'); + return Renderer::replaceMacros($tpl, ['$tabs' => $tabs]); + } + + protected static function setupUserCallback() { + $adminlist = explode(',', str_replace(' ', '', DI::config()->get('config', 'admin_email'))); + return function ($user) use ($adminlist) { + $page_types = [ + User::PAGE_FLAGS_NORMAL => DI::l10n()->t('Normal Account Page'), + User::PAGE_FLAGS_SOAPBOX => DI::l10n()->t('Soapbox Page'), + User::PAGE_FLAGS_COMMUNITY => DI::l10n()->t('Public Forum'), + User::PAGE_FLAGS_FREELOVE => DI::l10n()->t('Automatic Friend Page'), + User::PAGE_FLAGS_PRVGROUP => DI::l10n()->t('Private Forum') + ]; + $account_types = [ + User::ACCOUNT_TYPE_PERSON => DI::l10n()->t('Personal Page'), + User::ACCOUNT_TYPE_ORGANISATION => DI::l10n()->t('Organisation Page'), + User::ACCOUNT_TYPE_NEWS => DI::l10n()->t('News Page'), + User::ACCOUNT_TYPE_COMMUNITY => DI::l10n()->t('Community Forum'), + User::ACCOUNT_TYPE_RELAY => DI::l10n()->t('Relay'), + ]; + + $user['page_flags_raw'] = $user['page-flags']; + $user['page_flags'] = $page_types[$user['page-flags']]; + + $user['account_type_raw'] = ($user['page_flags_raw'] == 0) ? $user['account-type'] : -1; + $user['account_type'] = ($user['page_flags_raw'] == 0) ? $account_types[$user['account-type']] : ''; + + $user['register_date'] = Temporal::getRelativeDate($user['register_date']); + $user['login_date'] = Temporal::getRelativeDate($user['login_date']); + $user['lastitem_date'] = Temporal::getRelativeDate($user['last-item']); + $user['is_admin'] = in_array($user['email'], $adminlist); + $user['is_deletable'] = (intval($user['uid']) != local_user()); + $user['deleted'] = ($user['account_removed'] ? Temporal::getRelativeDate($user['account_expires_on']) : False); + + return $user; + }; + } +} diff --git a/src/Module/Admin/Users.php b/src/Module/Admin/Users.php deleted file mode 100644 index f38c24d979..0000000000 --- a/src/Module/Admin/Users.php +++ /dev/null @@ -1,286 +0,0 @@ -. - * - */ - -namespace Friendica\Module\Admin; - -use Friendica\Content\Pager; -use Friendica\Core\Renderer; -use Friendica\Database\DBA; -use Friendica\DI; -use Friendica\Model\Register; -use Friendica\Model\User; -use Friendica\Module\BaseAdmin; -use Friendica\Util\Temporal; - -class Users extends BaseAdmin -{ - public static function post(array $parameters = []) - { - self::checkAdminAccess(); - - self::checkFormSecurityTokenRedirectOnError('/admin/users', 'admin_users'); - - $pending = $_POST['pending'] ?? []; - $users = $_POST['user'] ?? []; - $nu_name = $_POST['new_user_name'] ?? ''; - $nu_nickname = $_POST['new_user_nickname'] ?? ''; - $nu_email = $_POST['new_user_email'] ?? ''; - $nu_language = DI::config()->get('system', 'language'); - - if ($nu_name !== '' && $nu_email !== '' && $nu_nickname !== '') { - try { - User::createMinimal($nu_name, $nu_email, $nu_nickname, $nu_language); - } catch (\Exception $ex) { - notice($ex->getMessage()); - return; - } - } - - if (!empty($_POST['page_users_block'])) { - foreach ($users as $uid) { - User::block($uid); - } - info(DI::l10n()->tt('%s user blocked', '%s users blocked', count($users))); - } - - if (!empty($_POST['page_users_unblock'])) { - foreach ($users as $uid) { - User::block($uid, false); - } - info(DI::l10n()->tt('%s user unblocked', '%s users unblocked', count($users))); - } - - if (!empty($_POST['page_users_delete'])) { - foreach ($users as $uid) { - if (local_user() != $uid) { - User::remove($uid); - } else { - notice(DI::l10n()->t('You can\'t remove yourself')); - } - } - - info(DI::l10n()->tt('%s user deleted', '%s users deleted', count($users))); - } - - if (!empty($_POST['page_users_approve'])) { - foreach ($pending as $hash) { - User::allow($hash); - } - info(DI::l10n()->tt('%s user approved', '%s users approved', count($pending))); - } - - if (!empty($_POST['page_users_deny'])) { - foreach ($pending as $hash) { - User::deny($hash); - } - info(DI::l10n()->tt('%s registration revoked', '%s registrations revoked', count($pending))); - } - - DI::baseUrl()->redirect('admin/users'); - } - - public static function content(array $parameters = []) - { - parent::content($parameters); - - $action = $parameters['action'] ?? ''; - $uid = $parameters['uid'] ?? 0; - - if ($uid) { - $user = User::getById($uid, ['username', 'blocked']); - if (!DBA::isResult($user)) { - notice(DI::l10n()->t('User not found')); - DI::baseUrl()->redirect('admin/users'); - return ''; // NOTREACHED - } - } - - switch ($action) { - case 'delete': - if (local_user() != $uid) { - self::checkFormSecurityTokenRedirectOnError('/admin/users', 'admin_users', 't'); - // delete user - User::remove($uid); - - notice(DI::l10n()->t('User "%s" deleted', $user['username'])); - } else { - notice(DI::l10n()->t('You can\'t remove yourself')); - } - break; - case 'block': - self::checkFormSecurityTokenRedirectOnError('/admin/users', 'admin_users', 't'); - User::block($uid); - notice(DI::l10n()->t('User "%s" blocked', $user['username'])); - break; - case 'unblock': - self::checkFormSecurityTokenRedirectOnError('/admin/users', 'admin_users', 't'); - User::block($uid, false); - notice(DI::l10n()->t('User "%s" unblocked', $user['username'])); - break; - case 'allow': - self::checkFormSecurityTokenRedirectOnError('/admin/users', 'admin_users', 't'); - User::allow(Register::getPendingForUser($uid)['hash'] ?? ''); - notice(DI::l10n()->t('Account approved.')); - break; - case 'deny': - self::checkFormSecurityTokenRedirectOnError('/admin/users', 'admin_users', 't'); - User::deny(Register::getPendingForUser($uid)['hash'] ?? ''); - notice(DI::l10n()->t('Registration revoked')); - break; - default: - /* get pending */ - $pending = Register::getPending(); - - $pager = new Pager(DI::l10n(), DI::args()->getQueryString(), 100); - - $valid_orders = [ - 'name', - 'email', - 'register_date', - 'login_date', - 'last-item', - 'page-flags' - ]; - - $order = 'name'; - $order_direction = '+'; - if (!empty($_GET['o'])) { - $new_order = $_GET['o']; - if ($new_order[0] === '-') { - $order_direction = '-'; - $new_order = substr($new_order, 1); - } - - if (in_array($new_order, $valid_orders)) { - $order = $new_order; - } - } - - $users = User::getList($pager->getStart(), $pager->getItemsPerPage(), 'all', $order, ($order_direction == '-')); - - $adminlist = explode(',', str_replace(' ', '', DI::config()->get('config', 'admin_email'))); - $_setup_users = function ($e) use ($adminlist) { - $page_types = [ - User::PAGE_FLAGS_NORMAL => DI::l10n()->t('Normal Account Page'), - User::PAGE_FLAGS_SOAPBOX => DI::l10n()->t('Soapbox Page'), - User::PAGE_FLAGS_COMMUNITY => DI::l10n()->t('Public Forum'), - User::PAGE_FLAGS_FREELOVE => DI::l10n()->t('Automatic Friend Page'), - User::PAGE_FLAGS_PRVGROUP => DI::l10n()->t('Private Forum') - ]; - $account_types = [ - User::ACCOUNT_TYPE_PERSON => DI::l10n()->t('Personal Page'), - User::ACCOUNT_TYPE_ORGANISATION => DI::l10n()->t('Organisation Page'), - User::ACCOUNT_TYPE_NEWS => DI::l10n()->t('News Page'), - User::ACCOUNT_TYPE_COMMUNITY => DI::l10n()->t('Community Forum'), - User::ACCOUNT_TYPE_RELAY => DI::l10n()->t('Relay'), - ]; - - $e['page_flags_raw'] = $e['page-flags']; - $e['page-flags'] = $page_types[$e['page-flags']]; - - $e['account_type_raw'] = ($e['page_flags_raw'] == 0) ? $e['account-type'] : -1; - $e['account-type'] = ($e['page_flags_raw'] == 0) ? $account_types[$e['account-type']] : ''; - - $e['register_date'] = Temporal::getRelativeDate($e['register_date']); - $e['login_date'] = Temporal::getRelativeDate($e['login_date']); - $e['lastitem_date'] = Temporal::getRelativeDate($e['last-item']); - $e['is_admin'] = in_array($e['email'], $adminlist); - $e['is_deletable'] = (intval($e['uid']) != local_user()); - $e['deleted'] = ($e['account_removed'] ? Temporal::getRelativeDate($e['account_expires_on']) : False); - - return $e; - }; - - $tmp_users = array_map($_setup_users, $users); - - // Get rid of dashes in key names, Smarty3 can't handle them - // and extracting deleted users - - $deleted = []; - $users = []; - foreach ($tmp_users as $user) { - foreach ($user as $k => $v) { - $newkey = str_replace('-', '_', $k); - $user[$newkey] = $v; - } - - if ($user['deleted']) { - $deleted[] = $user; - } else { - $users[] = $user; - } - } - - $th_users = array_map(null, [DI::l10n()->t('Name'), DI::l10n()->t('Email'), DI::l10n()->t('Register date'), DI::l10n()->t('Last login'), DI::l10n()->t('Last public item'), DI::l10n()->t('Type')], $valid_orders); - - $t = Renderer::getMarkupTemplate('admin/users.tpl'); - $o = Renderer::replaceMacros($t, [ - // strings // - '$title' => DI::l10n()->t('Administration'), - '$page' => DI::l10n()->t('Users'), - '$submit' => DI::l10n()->t('Add User'), - '$select_all' => DI::l10n()->t('select all'), - '$h_pending' => DI::l10n()->t('User registrations waiting for confirm'), - '$h_deleted' => DI::l10n()->t('User waiting for permanent deletion'), - '$th_pending' => [DI::l10n()->t('Request date'), DI::l10n()->t('Name'), DI::l10n()->t('Email')], - '$no_pending' => DI::l10n()->t('No registrations.'), - '$pendingnotetext' => DI::l10n()->t('Note from the user'), - '$approve' => DI::l10n()->t('Approve'), - '$deny' => DI::l10n()->t('Deny'), - '$delete' => DI::l10n()->t('Delete'), - '$block' => DI::l10n()->t('Block'), - '$blocked' => DI::l10n()->t('User blocked'), - '$unblock' => DI::l10n()->t('Unblock'), - '$siteadmin' => DI::l10n()->t('Site admin'), - '$accountexpired' => DI::l10n()->t('Account expired'), - - '$h_users' => DI::l10n()->t('Users'), - '$h_newuser' => DI::l10n()->t('New User'), - '$th_deleted' => [DI::l10n()->t('Name'), DI::l10n()->t('Email'), DI::l10n()->t('Register date'), DI::l10n()->t('Last login'), DI::l10n()->t('Last public item'), DI::l10n()->t('Permanent deletion')], - '$th_users' => $th_users, - '$order_users' => $order, - '$order_direction_users' => $order_direction, - - '$confirm_delete_multi' => DI::l10n()->t('Selected users will be deleted!\n\nEverything these users had posted on this site will be permanently deleted!\n\nAre you sure?'), - '$confirm_delete' => DI::l10n()->t('The user {0} will be deleted!\n\nEverything this user has posted on this site will be permanently deleted!\n\nAre you sure?'), - - '$form_security_token' => self::getFormSecurityToken('admin_users'), - - // values // - '$baseurl' => DI::baseUrl()->get(true), - - '$pending' => $pending, - 'deleted' => $deleted, - '$users' => $users, - '$newusername' => ['new_user_name', DI::l10n()->t('Name'), '', DI::l10n()->t('Name of the new user.')], - '$newusernickname' => ['new_user_nickname', DI::l10n()->t('Nickname'), '', DI::l10n()->t('Nickname of the new user.')], - '$newuseremail' => ['new_user_email', DI::l10n()->t('Email'), '', DI::l10n()->t('Email address of the new user.'), '', '', 'email'], - ]); - - $o .= $pager->renderFull(DBA::count('user')); - - return $o; - } - - DI::baseUrl()->redirect('admin/users'); - return ''; - } -} diff --git a/src/Module/Admin/Users/Active.php b/src/Module/Admin/Users/Active.php new file mode 100644 index 0000000000..1a12ad786c --- /dev/null +++ b/src/Module/Admin/Users/Active.php @@ -0,0 +1,164 @@ +. + * + */ + +namespace Friendica\Module\Admin\Users; + +use Friendica\Content\Pager; +use Friendica\Core\Renderer; +use Friendica\Database\DBA; +use Friendica\DI; +use Friendica\Model\User; +use Friendica\Module\Admin\BaseUsers; + +class Active extends BaseUsers +{ + public static function post(array $parameters = []) + { + self::checkAdminAccess(); + + self::checkFormSecurityTokenRedirectOnError(DI::baseUrl()->get(true), 'admin_users_active'); + + $users = $_POST['user'] ?? []; + + if (!empty($_POST['page_users_block'])) { + foreach ($users as $uid) { + User::block($uid); + } + info(DI::l10n()->tt('%s user blocked', '%s users blocked', count($users))); + } + + if (!empty($_POST['page_users_delete'])) { + foreach ($users as $uid) { + if (local_user() != $uid) { + User::remove($uid); + } else { + notice(DI::l10n()->t('You can\'t remove yourself')); + } + } + + info(DI::l10n()->tt('%s user deleted', '%s users deleted', count($users))); + } + + DI::baseUrl()->redirect(DI::args()->getQueryString()); + } + + public static function content(array $parameters = []) + { + parent::content($parameters); + + $action = $parameters['action'] ?? ''; + $uid = $parameters['uid'] ?? 0; + + if ($uid) { + $user = User::getById($uid, ['username', 'blocked']); + if (!DBA::isResult($user)) { + notice(DI::l10n()->t('User not found')); + DI::baseUrl()->redirect('admin/users'); + return ''; // NOTREACHED + } + } + + switch ($action) { + case 'delete': + if (local_user() != $uid) { + self::checkFormSecurityTokenRedirectOnError('admin/users/active', 'admin_users_active', 't'); + // delete user + User::remove($uid); + + notice(DI::l10n()->t('User "%s" deleted', $user['username'])); + } else { + notice(DI::l10n()->t('You can\'t remove yourself')); + } + + DI::baseUrl()->redirect('admin/users'); + break; + case 'block': + self::checkFormSecurityTokenRedirectOnError('admin/users/active', 'admin_users_active', 't'); + User::block($uid); + notice(DI::l10n()->t('User "%s" blocked', $user['username'])); + DI::baseUrl()->redirect(DI::baseUrl()->get(true)); + break; + } + $pager = new Pager(DI::l10n(), DI::args()->getQueryString(), 100); + + $valid_orders = [ + 'name', + 'email', + 'register_date', + 'login_date', + 'last-item', + 'page-flags' + ]; + + $order = 'name'; + $order_direction = '+'; + if (!empty($_GET['o'])) { + $new_order = $_GET['o']; + if ($new_order[0] === '-') { + $order_direction = '-'; + $new_order = substr($new_order, 1); + } + + if (in_array($new_order, $valid_orders)) { + $order = $new_order; + } + } + + $users = User::getList($pager->getStart(), $pager->getItemsPerPage(), 'active', $order, ($order_direction == '-')); + + $users = array_map(self::setupUserCallback(), $users); + + $th_users = array_map(null, [DI::l10n()->t('Name'), DI::l10n()->t('Email'), DI::l10n()->t('Register date'), DI::l10n()->t('Last login'), DI::l10n()->t('Last public item'), DI::l10n()->t('Type')], $valid_orders); + + $count = DBA::count('user', ['blocked' => false, 'account_removed' => false]); + + $t = Renderer::getMarkupTemplate('admin/users/active.tpl'); + return self::getTabsHTML('active') . Renderer::replaceMacros($t, [ + // strings // + '$title' => DI::l10n()->t('Administration'), + '$page' => DI::l10n()->t('Active Accounts'), + '$select_all' => DI::l10n()->t('select all'), + '$delete' => DI::l10n()->t('Delete'), + '$block' => DI::l10n()->t('Block'), + '$blocked' => DI::l10n()->t('User blocked'), + '$siteadmin' => DI::l10n()->t('Site admin'), + '$accountexpired' => DI::l10n()->t('Account expired'), + '$h_newuser' => DI::l10n()->t('Create a new user'), + + '$th_users' => $th_users, + '$order_users' => $order, + '$order_direction_users' => $order_direction, + + '$confirm_delete_multi' => DI::l10n()->t('Selected users will be deleted!\n\nEverything these users had posted on this site will be permanently deleted!\n\nAre you sure?'), + '$confirm_delete' => DI::l10n()->t('The user {0} will be deleted!\n\nEverything this user has posted on this site will be permanently deleted!\n\nAre you sure?'), + + '$form_security_token' => self::getFormSecurityToken('admin_users_active'), + + // values // + '$baseurl' => DI::baseUrl()->get(true), + '$query_string' => DI::baseUrl()->get(true), + + '$users' => $users, + '$count' => $count, + '$pager' => $pager->renderFull($count), + ]); + } +} diff --git a/src/Module/Admin/Users/Blocked.php b/src/Module/Admin/Users/Blocked.php new file mode 100644 index 0000000000..872ac0fa9e --- /dev/null +++ b/src/Module/Admin/Users/Blocked.php @@ -0,0 +1,164 @@ +. + * + */ + +namespace Friendica\Module\Admin\Users; + +use Friendica\Content\Pager; +use Friendica\Core\Renderer; +use Friendica\Database\DBA; +use Friendica\DI; +use Friendica\Model\User; +use Friendica\Module\Admin\BaseUsers; +use Friendica\Util\Temporal; + +class Blocked extends BaseUsers +{ + public static function post(array $parameters = []) + { + self::checkAdminAccess(); + + self::checkFormSecurityTokenRedirectOnError('/admin/users/blocked', 'admin_users_blocked'); + + $users = $_POST['user'] ?? []; + + if (!empty($_POST['page_users_unblock'])) { + foreach ($users as $uid) { + User::block($uid, false); + } + info(DI::l10n()->tt('%s user unblocked', '%s users unblocked', count($users))); + } + + if (!empty($_POST['page_users_delete'])) { + foreach ($users as $uid) { + if (local_user() != $uid) { + User::remove($uid); + } else { + notice(DI::l10n()->t('You can\'t remove yourself')); + } + } + + info(DI::l10n()->tt('%s user deleted', '%s users deleted', count($users))); + } + + DI::baseUrl()->redirect('admin/users/blocked'); + } + + public static function content(array $parameters = []) + { + parent::content($parameters); + + $action = $parameters['action'] ?? ''; + $uid = $parameters['uid'] ?? 0; + + if ($uid) { + $user = User::getById($uid, ['username', 'blocked']); + if (!DBA::isResult($user)) { + notice(DI::l10n()->t('User not found')); + DI::baseUrl()->redirect('admin/users'); + return ''; // NOTREACHED + } + } + + switch ($action) { + case 'delete': + if (local_user() != $uid) { + self::checkFormSecurityTokenRedirectOnError('/admin/users/blocked', 'admin_users_blocked', 't'); + // delete user + User::remove($uid); + + notice(DI::l10n()->t('User "%s" deleted', $user['username'])); + } else { + notice(DI::l10n()->t('You can\'t remove yourself')); + } + DI::baseUrl()->redirect('admin/users/blocked'); + break; + case 'unblock': + self::checkFormSecurityTokenRedirectOnError('/admin/users/blocked', 'admin_users_blocked', 't'); + User::block($uid, false); + notice(DI::l10n()->t('User "%s" unblocked', $user['username'])); + DI::baseUrl()->redirect('admin/users/blocked'); + break; + } + + $pager = new Pager(DI::l10n(), DI::args()->getQueryString(), 100); + + $valid_orders = [ + 'name', + 'email', + 'register_date', + 'login_date', + 'last-item', + 'page-flags' + ]; + + $order = 'name'; + $order_direction = '+'; + if (!empty($_GET['o'])) { + $new_order = $_GET['o']; + if ($new_order[0] === '-') { + $order_direction = '-'; + $new_order = substr($new_order, 1); + } + + if (in_array($new_order, $valid_orders)) { + $order = $new_order; + } + } + + $users = User::getList($pager->getStart(), $pager->getItemsPerPage(), 'blocked', $order, ($order_direction == '-')); + + $users = array_map(self::setupUserCallback(), $users); + + $th_users = array_map(null, [DI::l10n()->t('Name'), DI::l10n()->t('Email'), DI::l10n()->t('Register date'), DI::l10n()->t('Last login'), DI::l10n()->t('Last public item'), DI::l10n()->t('Type')], $valid_orders); + + $count = DBA::count('user', ['blocked' => true, 'verified' => true]); + + $t = Renderer::getMarkupTemplate('admin/users/blocked.tpl'); + return self::getTabsHTML('blocked') . Renderer::replaceMacros($t, [ + // strings // + '$title' => DI::l10n()->t('Administration'), + '$page' => DI::l10n()->t('Blocked Users'), + '$select_all' => DI::l10n()->t('select all'), + '$delete' => DI::l10n()->t('Delete'), + '$blocked' => DI::l10n()->t('User blocked'), + '$unblock' => DI::l10n()->t('Unblock'), + '$siteadmin' => DI::l10n()->t('Site admin'), + '$accountexpired' => DI::l10n()->t('Account expired'), + + '$th_users' => $th_users, + '$order_users' => $order, + '$order_direction_users' => $order_direction, + + '$confirm_delete_multi' => DI::l10n()->t('Selected users will be deleted!\n\nEverything these users had posted on this site will be permanently deleted!\n\nAre you sure?'), + '$confirm_delete' => DI::l10n()->t('The user {0} will be deleted!\n\nEverything this user has posted on this site will be permanently deleted!\n\nAre you sure?'), + + '$form_security_token' => self::getFormSecurityToken('admin_users_blocked'), + + // values // + '$baseurl' => DI::baseUrl()->get(true), + '$query_string' => DI::args()->getQueryString(), + + '$users' => $users, + '$count' => $count, + '$pager' => $pager->renderFull($count) + ]); + } +} diff --git a/src/Module/Admin/Users/Create.php b/src/Module/Admin/Users/Create.php new file mode 100644 index 0000000000..f5c9b3a4ad --- /dev/null +++ b/src/Module/Admin/Users/Create.php @@ -0,0 +1,76 @@ +. + * + */ + +namespace Friendica\Module\Admin\Users; + +use Friendica\Core\Renderer; +use Friendica\DI; +use Friendica\Model\User; +use Friendica\Module\Admin\BaseUsers; + +class Create extends BaseUsers +{ + public static function post(array $parameters = []) + { + self::checkAdminAccess(); + + self::checkFormSecurityTokenRedirectOnError('/admin/users/create', 'admin_users_create'); + + $nu_name = $_POST['new_user_name'] ?? ''; + $nu_nickname = $_POST['new_user_nickname'] ?? ''; + $nu_email = $_POST['new_user_email'] ?? ''; + $nu_language = DI::config()->get('system', 'language'); + + if ($nu_name !== '' && $nu_email !== '' && $nu_nickname !== '') { + try { + User::createMinimal($nu_name, $nu_email, $nu_nickname, $nu_language); + DI::baseUrl()->redirect('admin/users'); + } catch (\Exception $ex) { + notice($ex->getMessage()); + } + } + + DI::baseUrl()->redirect('admin/users/create'); + } + + public static function content(array $parameters = []) + { + parent::content($parameters); + + $t = Renderer::getMarkupTemplate('admin/users/create.tpl'); + return self::getTabsHTML('all') . Renderer::replaceMacros($t, [ + // strings // + '$title' => DI::l10n()->t('Administration'), + '$page' => DI::l10n()->t('New User'), + '$submit' => DI::l10n()->t('Add User'), + + '$form_security_token' => self::getFormSecurityToken('admin_users_create'), + + // values // + '$baseurl' => DI::baseUrl()->get(true), + '$query_string' => DI::args()->getQueryString(), + + '$newusername' => ['new_user_name', DI::l10n()->t('Name'), '', DI::l10n()->t('Name of the new user.')], + '$newusernickname' => ['new_user_nickname', DI::l10n()->t('Nickname'), '', DI::l10n()->t('Nickname of the new user.')], + '$newuseremail' => ['new_user_email', DI::l10n()->t('Email'), '', DI::l10n()->t('Email address of the new user.'), '', '', 'email'], + ]); + } +} diff --git a/src/Module/Admin/Users/Deleted.php b/src/Module/Admin/Users/Deleted.php new file mode 100644 index 0000000000..1615848ce7 --- /dev/null +++ b/src/Module/Admin/Users/Deleted.php @@ -0,0 +1,101 @@ +. + * + */ + +namespace Friendica\Module\Admin\Users; + +use Friendica\Content\Pager; +use Friendica\Core\Renderer; +use Friendica\Database\DBA; +use Friendica\DI; +use Friendica\Model\Register; +use Friendica\Model\User; +use Friendica\Module\Admin\BaseUsers; +use Friendica\Module\BaseAdmin; +use Friendica\Util\Temporal; + +class Deleted extends BaseUsers +{ + public static function post(array $parameters = []) + { + self::checkAdminAccess(); + + self::checkFormSecurityTokenRedirectOnError('/admin/users/deleted', 'admin_users_deleted'); + + // @TODO: Implement user deletion cancellation + + DI::baseUrl()->redirect('admin/users/deleted'); + } + + public static function content(array $parameters = []) + { + parent::content($parameters); + + $pager = new Pager(DI::l10n(), DI::args()->getQueryString(), 100); + + $valid_orders = [ + 'name', + 'email', + 'register_date', + 'login_date', + 'last-item', + 'page-flags' + ]; + + $order = 'name'; + $order_direction = '+'; + if (!empty($_GET['o'])) { + $new_order = $_GET['o']; + if ($new_order[0] === '-') { + $order_direction = '-'; + $new_order = substr($new_order, 1); + } + + if (in_array($new_order, $valid_orders)) { + $order = $new_order; + } + } + + $users = User::getList($pager->getStart(), $pager->getItemsPerPage(), 'removed', $order, ($order_direction == '-')); + + $users = array_map(self::setupUserCallback(), $users); + + $count = DBA::count('user', ['account_removed' => true]); + + $t = Renderer::getMarkupTemplate('admin/users/deleted.tpl'); + return self::getTabsHTML('deleted') . Renderer::replaceMacros($t, [ + // strings // + '$title' => DI::l10n()->t('Administration'), + '$page' => DI::l10n()->t('Users awaiting permanent deletion'), + + '$th_deleted' => [DI::l10n()->t('Name'), DI::l10n()->t('Email'), DI::l10n()->t('Register date'), DI::l10n()->t('Last login'), DI::l10n()->t('Last public item'), DI::l10n()->t('Permanent deletion')], + + '$form_security_token' => self::getFormSecurityToken('admin_users_deleted'), + + // values // + '$baseurl' => DI::baseUrl()->get(true), + '$query_string' => DI::args()->getQueryString(), + + '$users' => $users, + '$count' => $count, + '$pager' => $pager->renderFull($count), + ]); + } +} diff --git a/src/Module/Admin/Users/Index.php b/src/Module/Admin/Users/Index.php new file mode 100644 index 0000000000..cc453a0731 --- /dev/null +++ b/src/Module/Admin/Users/Index.php @@ -0,0 +1,181 @@ +. + * + */ + +namespace Friendica\Module\Admin\Users; + +use Friendica\Content\Pager; +use Friendica\Core\Renderer; +use Friendica\Database\DBA; +use Friendica\DI; +use Friendica\Model\User; +use Friendica\Module\Admin\BaseUsers; + +class Index extends BaseUsers +{ + public static function post(array $parameters = []) + { + self::checkAdminAccess(); + + self::checkFormSecurityTokenRedirectOnError('admin/users', 'admin_users'); + + $users = $_POST['user'] ?? []; + + if (!empty($_POST['page_users_block'])) { + foreach ($users as $uid) { + User::block($uid); + } + info(DI::l10n()->tt('%s user blocked', '%s users blocked', count($users))); + } + + if (!empty($_POST['page_users_unblock'])) { + foreach ($users as $uid) { + User::block($uid, false); + } + info(DI::l10n()->tt('%s user unblocked', '%s users unblocked', count($users))); + } + + if (!empty($_POST['page_users_delete'])) { + foreach ($users as $uid) { + if (local_user() != $uid) { + User::remove($uid); + } else { + notice(DI::l10n()->t('You can\'t remove yourself')); + } + } + + info(DI::l10n()->tt('%s user deleted', '%s users deleted', count($users))); + } + + DI::baseUrl()->redirect(DI::args()->getQueryString()); + } + + public static function content(array $parameters = []) + { + parent::content($parameters); + + $action = $parameters['action'] ?? ''; + $uid = $parameters['uid'] ?? 0; + + if ($uid) { + $user = User::getById($uid, ['username', 'blocked']); + if (!DBA::isResult($user)) { + notice(DI::l10n()->t('User not found')); + DI::baseUrl()->redirect('admin/users'); + return ''; // NOTREACHED + } + } + + switch ($action) { + case 'delete': + if (local_user() != $uid) { + self::checkFormSecurityTokenRedirectOnError(DI::baseUrl()->get(true), 'admin_users', 't'); + // delete user + User::remove($uid); + + notice(DI::l10n()->t('User "%s" deleted', $user['username'])); + } else { + notice(DI::l10n()->t('You can\'t remove yourself')); + } + + DI::baseUrl()->redirect('admin/users'); + break; + case 'block': + self::checkFormSecurityTokenRedirectOnError('admin/users', 'admin_users', 't'); + User::block($uid); + notice(DI::l10n()->t('User "%s" blocked', $user['username'])); + DI::baseUrl()->redirect(DI::baseUrl()->get(true)); + break; + case 'unblock': + self::checkFormSecurityTokenRedirectOnError('admin/users', 'admin_users', 't'); + User::block($uid, false); + notice(DI::l10n()->t('User "%s" unblocked', $user['username'])); + DI::baseUrl()->redirect('admin/users'); + break; + } + $pager = new Pager(DI::l10n(), DI::args()->getQueryString(), 100); + + $valid_orders = [ + 'name', + 'email', + 'register_date', + 'login_date', + 'last-item', + 'page-flags' + ]; + + $order = 'name'; + $order_direction = '+'; + if (!empty($_GET['o'])) { + $new_order = $_GET['o']; + if ($new_order[0] === '-') { + $order_direction = '-'; + $new_order = substr($new_order, 1); + } + + if (in_array($new_order, $valid_orders)) { + $order = $new_order; + } + } + + $users = User::getList($pager->getStart(), $pager->getItemsPerPage(), 'all', $order, ($order_direction == '-')); + + $users = array_map(self::setupUserCallback(), $users); + + $th_users = array_map(null, [DI::l10n()->t('Name'), DI::l10n()->t('Email'), DI::l10n()->t('Register date'), DI::l10n()->t('Last login'), DI::l10n()->t('Last public item'), DI::l10n()->t('Type')], $valid_orders); + + $count = DBA::count('user'); + + $t = Renderer::getMarkupTemplate('admin/users/index.tpl'); + return self::getTabsHTML('all') . Renderer::replaceMacros($t, [ + // strings // + '$title' => DI::l10n()->t('Administration'), + '$page' => DI::l10n()->t('Users'), + '$select_all' => DI::l10n()->t('select all'), + '$h_deleted' => DI::l10n()->t('User waiting for permanent deletion'), + '$delete' => DI::l10n()->t('Delete'), + '$block' => DI::l10n()->t('Block'), + '$blocked' => DI::l10n()->t('User blocked'), + '$unblock' => DI::l10n()->t('Unblock'), + '$siteadmin' => DI::l10n()->t('Site admin'), + '$accountexpired' => DI::l10n()->t('Account expired'), + + '$h_users' => DI::l10n()->t('Users'), + '$h_newuser' => DI::l10n()->t('Create a new user'), + '$th_deleted' => [DI::l10n()->t('Name'), DI::l10n()->t('Email'), DI::l10n()->t('Register date'), DI::l10n()->t('Last login'), DI::l10n()->t('Last public item'), DI::l10n()->t('Permanent deletion')], + '$th_users' => $th_users, + '$order_users' => $order, + '$order_direction_users' => $order_direction, + + '$confirm_delete_multi' => DI::l10n()->t('Selected users will be deleted!\n\nEverything these users had posted on this site will be permanently deleted!\n\nAre you sure?'), + '$confirm_delete' => DI::l10n()->t('The user {0} will be deleted!\n\nEverything this user has posted on this site will be permanently deleted!\n\nAre you sure?'), + + '$form_security_token' => self::getFormSecurityToken('admin_users'), + + // values // + '$baseurl' => DI::baseUrl()->get(true), + '$query_string' => DI::baseUrl()->get(true), + + '$users' => $users, + '$count' => $count, + '$pager' => $pager->renderFull($count), + ]); + } +} diff --git a/src/Module/Admin/Users/Pending.php b/src/Module/Admin/Users/Pending.php new file mode 100644 index 0000000000..1a1efe3ef6 --- /dev/null +++ b/src/Module/Admin/Users/Pending.php @@ -0,0 +1,121 @@ +. + * + */ + +namespace Friendica\Module\Admin\Users; + +use Friendica\Content\Pager; +use Friendica\Core\Renderer; +use Friendica\Database\DBA; +use Friendica\DI; +use Friendica\Model\Register; +use Friendica\Model\User; +use Friendica\Module\Admin\BaseUsers; +use Friendica\Module\BaseAdmin; +use Friendica\Util\Temporal; + +class Pending extends BaseUsers +{ + public static function post(array $parameters = []) + { + self::checkAdminAccess(); + + self::checkFormSecurityTokenRedirectOnError('/admin/users/pending', 'admin_users_pending'); + + $pending = $_POST['pending'] ?? []; + + if (!empty($_POST['page_users_approve'])) { + foreach ($pending as $hash) { + User::allow($hash); + } + info(DI::l10n()->tt('%s user approved', '%s users approved', count($pending))); + } + + if (!empty($_POST['page_users_deny'])) { + foreach ($pending as $hash) { + User::deny($hash); + } + info(DI::l10n()->tt('%s registration revoked', '%s registrations revoked', count($pending))); + } + + DI::baseUrl()->redirect('admin/users/pending'); + } + + public static function content(array $parameters = []) + { + parent::content($parameters); + + $action = $parameters['action'] ?? ''; + $uid = $parameters['uid'] ?? 0; + + if ($uid) { + $user = User::getById($uid, ['username', 'blocked']); + if (!DBA::isResult($user)) { + notice(DI::l10n()->t('User not found')); + DI::baseUrl()->redirect('admin/users'); + return ''; // NOTREACHED + } + } + + switch ($action) { + case 'allow': + self::checkFormSecurityTokenRedirectOnError('/admin/users/pending', 'admin_users_pending', 't'); + User::allow(Register::getPendingForUser($uid)['hash'] ?? ''); + notice(DI::l10n()->t('Account approved.')); + DI::baseUrl()->redirect('admin/users/pending'); + break; + case 'deny': + self::checkFormSecurityTokenRedirectOnError('/admin/users/pending', 'admin_users_pending', 't'); + User::deny(Register::getPendingForUser($uid)['hash'] ?? ''); + notice(DI::l10n()->t('Registration revoked')); + DI::baseUrl()->redirect('admin/users/pending'); + break; + } + + $pager = new Pager(DI::l10n(), DI::args()->getQueryString(), 100); + + $pending = Register::getPending($pager->getStart(), $pager->getItemsPerPage()); + + $count = Register::getPendingCount(); + + $t = Renderer::getMarkupTemplate('admin/users/pending.tpl'); + return self::getTabsHTML('pending') . Renderer::replaceMacros($t, [ + // strings // + '$title' => DI::l10n()->t('Administration'), + '$page' => DI::l10n()->t('User registrations awaiting review'), + '$select_all' => DI::l10n()->t('select all'), + '$th_pending' => [DI::l10n()->t('Request date'), DI::l10n()->t('Name'), DI::l10n()->t('Email')], + '$no_pending' => DI::l10n()->t('No registrations.'), + '$pendingnotetext' => DI::l10n()->t('Note from the user'), + '$approve' => DI::l10n()->t('Approve'), + '$deny' => DI::l10n()->t('Deny'), + + '$form_security_token' => self::getFormSecurityToken('admin_users_pending'), + + // values // + '$baseurl' => DI::baseUrl()->get(true), + '$query_string' => DI::args()->getQueryString(), + + '$pending' => $pending, + '$count' => $count, + '$pager' => $pager->renderFull($count), + ]); + } +} diff --git a/static/routes.config.php b/static/routes.config.php index 8466aec672..f0627b6126 100644 --- a/static/routes.config.php +++ b/static/routes.config.php @@ -110,7 +110,12 @@ return [ '/tos' => [Module\Admin\Tos::class, [R::GET, R::POST]], - '/users[/{action}/{uid}]' => [Module\Admin\Users::class, [R::GET, R::POST]], + '/users[/{action}/{uid}]' => [Module\Admin\Users\Index::class, [R::GET, R::POST]], + '/users/active[/{action}/{uid}]' => [Module\Admin\Users\Active::class, [R::GET, R::POST]], + '/users/pending[/{action}/{uid}]' => [Module\Admin\Users\Pending::class, [R::GET, R::POST]], + '/users/blocked[/{action}/{uid}]' => [Module\Admin\Users\Blocked::class, [R::GET, R::POST]], + '/users/deleted' => [Module\Admin\Users\Deleted::class, [R::GET ]], + '/users/create' => [Module\Admin\Users\Create::class, [R::GET, R::POST]], ], '/amcd' => [Module\AccountManagementControlDocument::class, [R::GET]], '/acctlink' => [Module\Acctlink::class, [R::GET]], diff --git a/view/templates/admin/users.tpl b/view/templates/admin/users.tpl deleted file mode 100644 index d2850519ab..0000000000 --- a/view/templates/admin/users.tpl +++ /dev/null @@ -1,179 +0,0 @@ - -
- {{foreach $th_deleted as $th}} - | {{$th}} | - {{/foreach}} -|||||
---|---|---|---|---|---|---|
- | {{$u.name}} | -{{$u.email}} | -{{$u.register_date}} | -{{$u.login_date}} | -{{$u.lastitem_date}} | -{{$u.deleted}} | -
+ {{$h_newuser}} +
++ {{$h_newuser}} +
++ {{$h_newuser}} +
+ ++ {{$h_newuser}} +
+ +- {{foreach $th_deleted as $th}} - | {{$th}} | - {{/foreach}} -|||||
---|---|---|---|---|---|---|
- | {{$u.name}} | -{{$u.email}} | -{{$u.register_date}} | -{{$u.login_date}} | -{{$u.lastitem_date}} | -{{$u.deleted}} | -
+ {{$h_newuser}} +
+