Enable/Disable users
This commit is contained in:
@@ -36,6 +36,21 @@ class User extends \Kanboard\Core\Base
|
||||
return $this->user->remove($user_id);
|
||||
}
|
||||
|
||||
public function disableUser($user_id)
|
||||
{
|
||||
return $this->user->disable($user_id);
|
||||
}
|
||||
|
||||
public function enableUser($user_id)
|
||||
{
|
||||
return $this->user->enable($user_id);
|
||||
}
|
||||
|
||||
public function isActiveUser($user_id)
|
||||
{
|
||||
return $this->user->isActive($user_id);
|
||||
}
|
||||
|
||||
public function createUser($username, $password, $name = '', $email = '', $role = Role::APP_USER)
|
||||
{
|
||||
$values = array(
|
||||
|
||||
@@ -65,6 +65,7 @@ class DatabaseAuth extends Base implements PasswordAuthenticationProviderInterfa
|
||||
->eq('username', $this->username)
|
||||
->eq('disable_login_form', 0)
|
||||
->eq('is_ldap_user', 0)
|
||||
->eq('is_active', 1)
|
||||
->findOne();
|
||||
|
||||
if (! empty($user) && password_verify($this->password, $user['password'])) {
|
||||
@@ -83,7 +84,7 @@ class DatabaseAuth extends Base implements PasswordAuthenticationProviderInterfa
|
||||
*/
|
||||
public function isValidSession()
|
||||
{
|
||||
return $this->user->exists($this->userSession->getId());
|
||||
return $this->user->isActive($this->userSession->getId());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,7 +24,7 @@ class Projectuser extends Base
|
||||
$project_ids = $this->projectPermission->getActiveProjectIds($this->userSession->getId());
|
||||
}
|
||||
|
||||
return array($user_id, $project_ids, $this->user->getList(true));
|
||||
return array($user_id, $project_ids, $this->user->getActiveUsersList(true));
|
||||
}
|
||||
|
||||
private function role($role, $action, $title, $title_user)
|
||||
@@ -33,7 +33,7 @@ class Projectuser extends Base
|
||||
|
||||
$query = $this->projectPermission->getQueryByRole($project_ids, $role)->callback(array($this->project, 'applyColumnStats'));
|
||||
|
||||
if ($user_id !== UserModel::EVERYBODY_ID) {
|
||||
if ($user_id !== UserModel::EVERYBODY_ID && isset($users[$user_id])) {
|
||||
$query->eq(UserModel::TABLE.'.id', $user_id);
|
||||
$title = t($title_user, $users[$user_id]);
|
||||
}
|
||||
@@ -59,7 +59,7 @@ class Projectuser extends Base
|
||||
|
||||
$query = $this->taskFinder->getProjectUserOverviewQuery($project_ids, $is_active);
|
||||
|
||||
if ($user_id !== UserModel::EVERYBODY_ID) {
|
||||
if ($user_id !== UserModel::EVERYBODY_ID && isset($users[$user_id])) {
|
||||
$query->eq(TaskModel::TABLE.'.owner_id', $user_id);
|
||||
$title = t($title_user, $users[$user_id]);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,8 @@ class User extends Base
|
||||
$this->helper->layout->app('user/index', array(
|
||||
'title' => t('Users').' ('.$paginator->getTotal().')',
|
||||
'paginator' => $paginator,
|
||||
)));
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -404,30 +405,4 @@ class User extends Base
|
||||
'user' => $user,
|
||||
)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a user
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function remove()
|
||||
{
|
||||
$user = $this->getUser();
|
||||
|
||||
if ($this->request->getStringParam('confirmation') === 'yes') {
|
||||
$this->checkCSRFParam();
|
||||
|
||||
if ($this->user->remove($user['id'])) {
|
||||
$this->flash->success(t('User removed successfully.'));
|
||||
} else {
|
||||
$this->flash->failure(t('Unable to remove this user.'));
|
||||
}
|
||||
|
||||
$this->response->redirect($this->helper->url->to('user', 'index'));
|
||||
}
|
||||
|
||||
$this->response->html($this->helper->layout->user('user/remove', array(
|
||||
'user' => $user,
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
111
app/Controller/UserStatus.php
Normal file
111
app/Controller/UserStatus.php
Normal file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Controller;
|
||||
|
||||
/**
|
||||
* User Status Controller
|
||||
*
|
||||
* @package controller
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class UserStatus extends Base
|
||||
{
|
||||
/**
|
||||
* Confirm remove a user
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function confirmRemove()
|
||||
{
|
||||
$user = $this->getUser();
|
||||
|
||||
$this->response->html($this->helper->layout->user('user_status/remove', array(
|
||||
'user' => $user,
|
||||
)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a user
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function remove()
|
||||
{
|
||||
$user = $this->getUser();
|
||||
$this->checkCSRFParam();
|
||||
|
||||
if ($this->user->remove($user['id'])) {
|
||||
$this->flash->success(t('User removed successfully.'));
|
||||
} else {
|
||||
$this->flash->failure(t('Unable to remove this user.'));
|
||||
}
|
||||
|
||||
$this->response->redirect($this->helper->url->to('user', 'index'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm enable a user
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function confirmEnable()
|
||||
{
|
||||
$user = $this->getUser();
|
||||
|
||||
$this->response->html($this->helper->layout->user('user_status/enable', array(
|
||||
'user' => $user,
|
||||
)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable a user
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function enable()
|
||||
{
|
||||
$user = $this->getUser();
|
||||
$this->checkCSRFParam();
|
||||
|
||||
if ($this->user->enable($user['id'])) {
|
||||
$this->flash->success(t('User activated successfully.'));
|
||||
} else {
|
||||
$this->flash->failure(t('Unable to enable this user.'));
|
||||
}
|
||||
|
||||
$this->response->redirect($this->helper->url->to('user', 'index'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm disable a user
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function confirmDisable()
|
||||
{
|
||||
$user = $this->getUser();
|
||||
|
||||
$this->response->html($this->helper->layout->user('user_status/disable', array(
|
||||
'user' => $user,
|
||||
)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable a user
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function disable()
|
||||
{
|
||||
$user = $this->getUser();
|
||||
$this->checkCSRFParam();
|
||||
|
||||
if ($this->user->disable($user['id'])) {
|
||||
$this->flash->success(t('User disabled successfully.'));
|
||||
} else {
|
||||
$this->flash->failure(t('Unable to disable this user.'));
|
||||
}
|
||||
|
||||
$this->response->redirect($this->helper->url->to('user', 'index'));
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,7 @@ class UserProfile extends Base
|
||||
$this->groupSync->synchronize($profile['id'], $user->getExternalGroupIds());
|
||||
}
|
||||
|
||||
if (! empty($profile)) {
|
||||
if (! empty($profile) && $profile['is_active'] == 1) {
|
||||
$this->userSession->initialize($profile);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -106,6 +106,7 @@ class ProjectGroupRole extends Base
|
||||
->join(GroupMember::TABLE, 'user_id', 'id', User::TABLE)
|
||||
->join(self::TABLE, 'group_id', 'group_id', GroupMember::TABLE)
|
||||
->eq(self::TABLE.'.project_id', $project_id)
|
||||
->eq(User::TABLE.'.is_active', 1)
|
||||
->in(self::TABLE.'.role', array(Role::PROJECT_MANAGER, Role::PROJECT_MEMBER))
|
||||
->asc(User::TABLE.'.username')
|
||||
->findAll();
|
||||
|
||||
@@ -107,7 +107,8 @@ class ProjectPermission extends Base
|
||||
*/
|
||||
public function isAssignable($project_id, $user_id)
|
||||
{
|
||||
return in_array($this->projectUserRole->getUserRole($project_id, $user_id), array(Role::PROJECT_MEMBER, Role::PROJECT_MANAGER));
|
||||
return $this->user->isActive($user_id) &&
|
||||
in_array($this->projectUserRole->getUserRole($project_id, $user_id), array(Role::PROJECT_MEMBER, Role::PROJECT_MANAGER));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -152,13 +152,14 @@ class ProjectUserRole extends Base
|
||||
public function getAssignableUsers($project_id)
|
||||
{
|
||||
if ($this->projectPermission->isEverybodyAllowed($project_id)) {
|
||||
return $this->user->getList();
|
||||
return $this->user->getActiveUsersList();
|
||||
}
|
||||
|
||||
$userMembers = $this->db->table(self::TABLE)
|
||||
->columns(User::TABLE.'.id', User::TABLE.'.username', User::TABLE.'.name')
|
||||
->join(User::TABLE, 'id', 'user_id')
|
||||
->eq('project_id', $project_id)
|
||||
->eq(User::TABLE.'.is_active', 1)
|
||||
->eq(self::TABLE.'.project_id', $project_id)
|
||||
->in(self::TABLE.'.role', array(Role::PROJECT_MANAGER, Role::PROJECT_MEMBER))
|
||||
->findAll();
|
||||
|
||||
|
||||
@@ -40,6 +40,18 @@ class User extends Base
|
||||
return $this->db->table(self::TABLE)->eq('id', $user_id)->exists();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the user is active
|
||||
*
|
||||
* @access public
|
||||
* @param integer $user_id User id
|
||||
* @return boolean
|
||||
*/
|
||||
public function isActive($user_id)
|
||||
{
|
||||
return $this->db->table(self::TABLE)->eq('id', $user_id)->eq('is_active', 1)->exists();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get query to fetch all users
|
||||
*
|
||||
@@ -193,9 +205,9 @@ class User extends Base
|
||||
* @param boolean $prepend Prepend "All users"
|
||||
* @return array
|
||||
*/
|
||||
public function getList($prepend = false)
|
||||
public function getActiveUsersList($prepend = false)
|
||||
{
|
||||
$users = $this->db->table(self::TABLE)->columns('id', 'username', 'name')->findAll();
|
||||
$users = $this->db->table(self::TABLE)->eq('is_active', 1)->columns('id', 'username', 'name')->findAll();
|
||||
$listing = $this->prepareList($users);
|
||||
|
||||
if ($prepend) {
|
||||
@@ -280,6 +292,30 @@ class User extends Base
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable a specific user
|
||||
*
|
||||
* @access public
|
||||
* @param integer $user_id
|
||||
* @return boolean
|
||||
*/
|
||||
public function disable($user_id)
|
||||
{
|
||||
return $this->db->table(self::TABLE)->eq('id', $user_id)->update(array('is_active' => 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable a specific user
|
||||
*
|
||||
* @access public
|
||||
* @param integer $user_id
|
||||
* @return boolean
|
||||
*/
|
||||
public function enable($user_id)
|
||||
{
|
||||
return $this->db->table(self::TABLE)->eq('id', $user_id)->update(array('is_active' => 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a specific user
|
||||
*
|
||||
|
||||
@@ -6,7 +6,12 @@ use PDO;
|
||||
use Kanboard\Core\Security\Token;
|
||||
use Kanboard\Core\Security\Role;
|
||||
|
||||
const VERSION = 104;
|
||||
const VERSION = 105;
|
||||
|
||||
function version_105(PDO $pdo)
|
||||
{
|
||||
$pdo->exec("ALTER TABLE users ADD COLUMN is_active TINYINT(1) DEFAULT 1");
|
||||
}
|
||||
|
||||
function version_104(PDO $pdo)
|
||||
{
|
||||
|
||||
@@ -6,7 +6,12 @@ use PDO;
|
||||
use Kanboard\Core\Security\Token;
|
||||
use Kanboard\Core\Security\Role;
|
||||
|
||||
const VERSION = 84;
|
||||
const VERSION = 85;
|
||||
|
||||
function version_85(PDO $pdo)
|
||||
{
|
||||
$pdo->exec("ALTER TABLE users ADD COLUMN is_active BOOLEAN DEFAULT '1'");
|
||||
}
|
||||
|
||||
function version_84(PDO $pdo)
|
||||
{
|
||||
|
||||
@@ -6,7 +6,12 @@ use Kanboard\Core\Security\Token;
|
||||
use Kanboard\Core\Security\Role;
|
||||
use PDO;
|
||||
|
||||
const VERSION = 96;
|
||||
const VERSION = 97;
|
||||
|
||||
function version_97(PDO $pdo)
|
||||
{
|
||||
$pdo->exec("ALTER TABLE users ADD COLUMN is_active INTEGER DEFAULT 1");
|
||||
}
|
||||
|
||||
function version_96(PDO $pdo)
|
||||
{
|
||||
|
||||
@@ -134,7 +134,8 @@ class AuthenticationProvider implements ServiceProviderInterface
|
||||
$acl->add('Projectuser', '*', Role::APP_MANAGER);
|
||||
$acl->add('Twofactor', 'disable', Role::APP_ADMIN);
|
||||
$acl->add('UserImport', '*', Role::APP_ADMIN);
|
||||
$acl->add('User', array('index', 'create', 'save', 'authentication', 'remove'), Role::APP_ADMIN);
|
||||
$acl->add('User', array('index', 'create', 'save', 'authentication'), Role::APP_ADMIN);
|
||||
$acl->add('UserStatus', '*', Role::APP_ADMIN);
|
||||
|
||||
return $acl;
|
||||
}
|
||||
|
||||
@@ -157,7 +157,6 @@ class RouteProvider implements ServiceProviderInterface
|
||||
$container['route']->addRoute('user/:user_id/accounts', 'user', 'external');
|
||||
$container['route']->addRoute('user/:user_id/integrations', 'user', 'integrations');
|
||||
$container['route']->addRoute('user/:user_id/authentication', 'user', 'authentication');
|
||||
$container['route']->addRoute('user/:user_id/remove', 'user', 'remove');
|
||||
$container['route']->addRoute('user/:user_id/2fa', 'twofactor', 'index');
|
||||
|
||||
// Groups
|
||||
|
||||
27
app/Template/user/dropdown.php
Normal file
27
app/Template/user/dropdown.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<div class="dropdown">
|
||||
<a href="#" class="dropdown-menu dropdown-menu-link-icon"><i class="fa fa-cog fa-fw"></i><i class="fa fa-caret-down"></i></a>
|
||||
<ul>
|
||||
<li>
|
||||
<i class="fa fa-user fa-fw"></i>
|
||||
<?= $this->url->link(t('View profile'), 'user', 'show', array('user_id' => $user['id'])) ?>
|
||||
</li>
|
||||
<?php if ($user['is_active'] == 1 && $this->user->hasAccess('UserStatus', 'disable') && ! $this->user->isCurrentUser($user['id'])): ?>
|
||||
<li>
|
||||
<i class="fa fa-times fa-fw"></i>
|
||||
<?= $this->url->link(t('Disable'), 'UserStatus', 'confirmDisable', array('user_id' => $user['id']), false, 'popover') ?>
|
||||
</li>
|
||||
<?php endif ?>
|
||||
<?php if ($user['is_active'] == 0 && $this->user->hasAccess('UserStatus', 'enable') && ! $this->user->isCurrentUser($user['id'])): ?>
|
||||
<li>
|
||||
<i class="fa fa-check-square-o fa-fw"></i>
|
||||
<?= $this->url->link(t('Enable'), 'UserStatus', 'confirmEnable', array('user_id' => $user['id']), false, 'popover') ?>
|
||||
</li>
|
||||
<?php endif ?>
|
||||
<?php if ($this->user->hasAccess('UserStatus', 'remove') && ! $this->user->isCurrentUser($user['id'])): ?>
|
||||
<li>
|
||||
<i class="fa fa-trash-o fa-fw"></i>
|
||||
<?= $this->url->link(t('Remove'), 'UserStatus', 'confirmRemove', array('user_id' => $user['id']), false, 'popover') ?>
|
||||
</li>
|
||||
<?php endif ?>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -12,23 +12,21 @@
|
||||
<?php if ($paginator->isEmpty()): ?>
|
||||
<p class="alert"><?= t('No user') ?></p>
|
||||
<?php else: ?>
|
||||
<table>
|
||||
<table class="table-stripped">
|
||||
<tr>
|
||||
<th><?= $paginator->order(t('Id'), 'id') ?></th>
|
||||
<th><?= $paginator->order(t('Username'), 'username') ?></th>
|
||||
<th><?= $paginator->order(t('Name'), 'name') ?></th>
|
||||
<th><?= $paginator->order(t('Email'), 'email') ?></th>
|
||||
<th><?= $paginator->order(t('Role'), 'role') ?></th>
|
||||
<th><?= $paginator->order(t('Two factor authentication'), 'twofactor_activated') ?></th>
|
||||
<th><?= $paginator->order(t('Notifications'), 'notifications_enabled') ?></th>
|
||||
<th><?= $paginator->order(t('Account type'), 'is_ldap_user') ?></th>
|
||||
<th class="column-18"><?= $paginator->order(t('Username'), 'username') ?></th>
|
||||
<th class="column-18"><?= $paginator->order(t('Name'), 'name') ?></th>
|
||||
<th class="column-15"><?= $paginator->order(t('Email'), 'email') ?></th>
|
||||
<th class="column-15"><?= $paginator->order(t('Role'), 'role') ?></th>
|
||||
<th class="column-10"><?= $paginator->order(t('Two Factor'), 'twofactor_activated') ?></th>
|
||||
<th class="column-10"><?= $paginator->order(t('Account type'), 'is_ldap_user') ?></th>
|
||||
<th class="column-10"><?= $paginator->order(t('Status'), 'is_active') ?></th>
|
||||
<th class="column-5"><?= t('Actions') ?></th>
|
||||
</tr>
|
||||
<?php foreach ($paginator->getCollection() as $user): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<?= $this->url->link('#'.$user['id'], 'user', 'show', array('user_id' => $user['id'])) ?>
|
||||
</td>
|
||||
<td>
|
||||
<?= '#'.$user['id'] ?>
|
||||
<?= $this->url->link($this->e($user['username']), 'user', 'show', array('user_id' => $user['id'])) ?>
|
||||
</td>
|
||||
<td>
|
||||
@@ -44,14 +42,17 @@
|
||||
<?= $user['twofactor_activated'] ? t('Yes') : t('No') ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($user['notifications_enabled'] == 1): ?>
|
||||
<?= t('Enabled') ?>
|
||||
<?= $user['is_ldap_user'] ? t('Remote') : t('Local') ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($user['is_active'] == 1): ?>
|
||||
<?= t('Active') ?>
|
||||
<?php else: ?>
|
||||
<?= t('Disabled') ?>
|
||||
<?= t('Inactive') ?>
|
||||
<?php endif ?>
|
||||
</td>
|
||||
<td>
|
||||
<?= $user['is_ldap_user'] ? t('Remote') : t('Local') ?>
|
||||
<?= $this->render('user/dropdown', array('user' => $user)) ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<li><?= t('Username:') ?> <strong><?= $this->e($user['username']) ?></strong></li>
|
||||
<li><?= t('Name:') ?> <strong><?= $this->e($user['name']) ?: t('None') ?></strong></li>
|
||||
<li><?= t('Email:') ?> <strong><?= $this->e($user['email']) ?: t('None') ?></strong></li>
|
||||
<li><?= t('Status:') ?> <strong><?= $user['is_active'] ? t('Active') : t('Inactive') ?></strong></li>
|
||||
</ul>
|
||||
|
||||
<div class="page-header">
|
||||
|
||||
@@ -76,11 +76,5 @@
|
||||
<?php endif ?>
|
||||
|
||||
<?= $this->hook->render('template:user:sidebar:actions', array('user' => $user)) ?>
|
||||
|
||||
<?php if ($this->user->hasAccess('user', 'remove') && ! $this->user->isCurrentUser($user['id'])): ?>
|
||||
<li <?= $this->app->checkMenuSelection('user', 'remove') ?>>
|
||||
<?= $this->url->link(t('Remove'), 'user', 'remove', array('user_id' => $user['id'])) ?>
|
||||
</li>
|
||||
<?php endif ?>
|
||||
</ul>
|
||||
</div>
|
||||
13
app/Template/user_status/disable.php
Normal file
13
app/Template/user_status/disable.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<div class="page-header">
|
||||
<h2><?= t('Disable user') ?></h2>
|
||||
</div>
|
||||
|
||||
<div class="confirm">
|
||||
<p class="alert alert-info"><?= t('Do you really want to disable this user: "%s"?', $user['name'] ?: $user['username']) ?></p>
|
||||
|
||||
<div class="form-actions">
|
||||
<?= $this->url->link(t('Yes'), 'UserStatus', 'disable', array('user_id' => $user['id']), true, 'btn btn-red') ?>
|
||||
<?= t('or') ?>
|
||||
<?= $this->url->link(t('cancel'), 'user', 'index', array(), false, 'close-popover') ?>
|
||||
</div>
|
||||
</div>
|
||||
13
app/Template/user_status/enable.php
Normal file
13
app/Template/user_status/enable.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<div class="page-header">
|
||||
<h2><?= t('Enable user') ?></h2>
|
||||
</div>
|
||||
|
||||
<div class="confirm">
|
||||
<p class="alert alert-info"><?= t('Do you really want to enable this user: "%s"?', $user['name'] ?: $user['username']) ?></p>
|
||||
|
||||
<div class="form-actions">
|
||||
<?= $this->url->link(t('Yes'), 'UserStatus', 'enable', array('user_id' => $user['id']), true, 'btn btn-red') ?>
|
||||
<?= t('or') ?>
|
||||
<?= $this->url->link(t('cancel'), 'user', 'index', array(), false, 'close-popover') ?>
|
||||
</div>
|
||||
</div>
|
||||
@@ -6,8 +6,8 @@
|
||||
<p class="alert alert-info"><?= t('Do you really want to remove this user: "%s"?', $user['name'] ?: $user['username']) ?></p>
|
||||
|
||||
<div class="form-actions">
|
||||
<?= $this->url->link(t('Yes'), 'user', 'remove', array('user_id' => $user['id'], 'confirmation' => 'yes'), true, 'btn btn-red') ?>
|
||||
<?= $this->url->link(t('Yes'), 'UserStatus', 'remove', array('user_id' => $user['id']), true, 'btn btn-red') ?>
|
||||
<?= t('or') ?>
|
||||
<?= $this->url->link(t('cancel'), 'user', 'show', array('user_id' => $user['id'])) ?>
|
||||
<?= $this->url->link(t('cancel'), 'user', 'index', array(), false, 'close-popover') ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user