Add user backend provider system
This commit is contained in:
@@ -69,6 +69,10 @@ class ProjectPermissionController extends BaseController
|
||||
$project = $this->getProject();
|
||||
$values = $this->request->getValues();
|
||||
|
||||
if (empty($values['user_id']) && ! empty($values['external_id']) && ! empty($values['external_id_column'])) {
|
||||
$values['user_id'] = $this->userModel->getOrCreateExternalUserId($values['username'], $values['name'], $values['external_id_column'], $values['external_id']);
|
||||
}
|
||||
|
||||
if (empty($values['user_id'])) {
|
||||
$this->flash->failure(t('User not found.'));
|
||||
} elseif ($this->projectUserRoleModel->addUser($values['project_id'], $values['user_id'], $values['role'])) {
|
||||
|
||||
@@ -2,9 +2,6 @@
|
||||
|
||||
namespace Kanboard\Controller;
|
||||
|
||||
use Kanboard\Filter\UserNameFilter;
|
||||
use Kanboard\Model\UserModel;
|
||||
|
||||
/**
|
||||
* User Ajax Controller
|
||||
*
|
||||
@@ -21,13 +18,8 @@ class UserAjaxController extends BaseController
|
||||
public function autocomplete()
|
||||
{
|
||||
$search = $this->request->getStringParam('term');
|
||||
$filter = $this->userQuery->withFilter(new UserNameFilter($search));
|
||||
$filter->getQuery()
|
||||
->eq(UserModel::TABLE.'.is_active', 1)
|
||||
->asc(UserModel::TABLE.'.name')
|
||||
->asc(UserModel::TABLE.'.username');
|
||||
|
||||
$this->response->json($filter->format($this->userAutoCompleteFormatter));
|
||||
$users = $this->userManager->find($search);
|
||||
$this->response->json($this->userAutoCompleteFormatter->withUsers($users)->format());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,7 +7,7 @@ use Pimple\Container;
|
||||
/**
|
||||
* Base Class
|
||||
*
|
||||
* @package core
|
||||
* @package Kanboard\Core
|
||||
* @author Frederic Guillot
|
||||
*
|
||||
* @property \Kanboard\Analytic\TaskDistributionAnalytic $taskDistributionAnalytic
|
||||
@@ -22,6 +22,7 @@ use Pimple\Container;
|
||||
* @property \Kanboard\Core\Cache\BaseCache $cacheDriver
|
||||
* @property \Kanboard\Core\Event\EventManager $eventManager
|
||||
* @property \Kanboard\Core\Group\GroupManager $groupManager
|
||||
* @property \Kanboard\Core\User\UserManager $userManager
|
||||
* @property \Kanboard\Core\Http\Client $httpClient
|
||||
* @property \Kanboard\Core\Http\OAuth2 $oauth
|
||||
* @property \Kanboard\Core\Http\RememberMeCookie $rememberMeCookie
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Kanboard\Core\Group;
|
||||
/**
|
||||
* Group Backend Provider Interface
|
||||
*
|
||||
* @package group
|
||||
* @package Kanboard\Core\Group
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
interface GroupBackendProviderInterface
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Kanboard\Core\Group;
|
||||
/**
|
||||
* Group Manager
|
||||
*
|
||||
* @package group
|
||||
* @package Kanboard\Core\Group
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class GroupManager
|
||||
@@ -13,10 +13,10 @@ class GroupManager
|
||||
/**
|
||||
* List of backend providers
|
||||
*
|
||||
* @access private
|
||||
* @access protected
|
||||
* @var array
|
||||
*/
|
||||
private $providers = array();
|
||||
protected $providers = array();
|
||||
|
||||
/**
|
||||
* Register a new group backend provider
|
||||
@@ -52,11 +52,11 @@ class GroupManager
|
||||
/**
|
||||
* Remove duplicated groups
|
||||
*
|
||||
* @access private
|
||||
* @access protected
|
||||
* @param array $groups
|
||||
* @return GroupProviderInterface[]
|
||||
*/
|
||||
private function removeDuplicates(array $groups)
|
||||
protected function removeDuplicates(array $groups)
|
||||
{
|
||||
$result = array();
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Kanboard\Core\Group;
|
||||
/**
|
||||
* Group Provider Interface
|
||||
*
|
||||
* @package group
|
||||
* @package Kanboard\Core\Group
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
interface GroupProviderInterface
|
||||
|
||||
21
app/Core/User/UserBackendProviderInterface.php
Normal file
21
app/Core/User/UserBackendProviderInterface.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Core\User;
|
||||
|
||||
/**
|
||||
* User Backend Provider Interface
|
||||
*
|
||||
* @package Kanboard\Core\User
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
interface UserBackendProviderInterface
|
||||
{
|
||||
/**
|
||||
* Find a user from a search query
|
||||
*
|
||||
* @access public
|
||||
* @param string $input
|
||||
* @return UserProviderInterface[]
|
||||
*/
|
||||
public function find($input);
|
||||
}
|
||||
71
app/Core/User/UserManager.php
Normal file
71
app/Core/User/UserManager.php
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Core\User;
|
||||
|
||||
/**
|
||||
* User Manager
|
||||
*
|
||||
* @package Kanboard\Core\User
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class UserManager
|
||||
{
|
||||
/**
|
||||
* List of backend providers
|
||||
*
|
||||
* @access protected
|
||||
* @var array
|
||||
*/
|
||||
protected $providers = array();
|
||||
|
||||
/**
|
||||
* Register a new group backend provider
|
||||
*
|
||||
* @access public
|
||||
* @param UserBackendProviderInterface $provider
|
||||
* @return $this
|
||||
*/
|
||||
public function register(UserBackendProviderInterface $provider)
|
||||
{
|
||||
$this->providers[] = $provider;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a group from a search query
|
||||
*
|
||||
* @access public
|
||||
* @param string $input
|
||||
* @return UserProviderInterface[]
|
||||
*/
|
||||
public function find($input)
|
||||
{
|
||||
$groups = array();
|
||||
|
||||
foreach ($this->providers as $provider) {
|
||||
$groups = array_merge($groups, $provider->find($input));
|
||||
}
|
||||
|
||||
return $this->removeDuplicates($groups);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove duplicated users
|
||||
*
|
||||
* @access protected
|
||||
* @param array $users
|
||||
* @return UserProviderInterface[]
|
||||
*/
|
||||
protected function removeDuplicates(array $users)
|
||||
{
|
||||
$result = array();
|
||||
|
||||
foreach ($users as $user) {
|
||||
if (! isset($result[$user->getUsername()])) {
|
||||
$result[$user->getUsername()] = $user;
|
||||
}
|
||||
}
|
||||
|
||||
return array_values($result);
|
||||
}
|
||||
}
|
||||
@@ -4,12 +4,11 @@ namespace Kanboard\Formatter;
|
||||
|
||||
use Kanboard\Core\Filter\FormatterInterface;
|
||||
use Kanboard\Core\Group\GroupProviderInterface;
|
||||
use PicoDb\Table;
|
||||
|
||||
/**
|
||||
* Auto-complete formatter for groups
|
||||
*
|
||||
* @package formatter
|
||||
* @package Kanboard\Formatter
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class GroupAutoCompleteFormatter extends BaseFormatter implements FormatterInterface
|
||||
|
||||
@@ -2,37 +2,59 @@
|
||||
|
||||
namespace Kanboard\Formatter;
|
||||
|
||||
use Kanboard\Model\UserModel;
|
||||
use Kanboard\Core\User\UserProviderInterface;
|
||||
use Kanboard\Core\Filter\FormatterInterface;
|
||||
|
||||
/**
|
||||
* Auto-complete formatter for user filter
|
||||
* Auto-complete formatter for users
|
||||
*
|
||||
* @package formatter
|
||||
* @package Kanboard\Formatter
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class UserAutoCompleteFormatter extends BaseFormatter implements FormatterInterface
|
||||
{
|
||||
/**
|
||||
* Format the tasks for the ajax auto-completion
|
||||
* Users found
|
||||
*
|
||||
* @access protected
|
||||
* @var UserProviderInterface[]
|
||||
*/
|
||||
protected $users;
|
||||
|
||||
/**
|
||||
* Set users
|
||||
*
|
||||
* @access public
|
||||
* @param UserProviderInterface[] $users
|
||||
* @return $this
|
||||
*/
|
||||
public function withUsers(array $users)
|
||||
{
|
||||
$this->users = $users;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the users for the ajax auto-completion
|
||||
*
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function format()
|
||||
{
|
||||
$users = $this->query->columns(UserModel::TABLE.'.id', UserModel::TABLE.'.username', UserModel::TABLE.'.name')->findAll();
|
||||
$result = array();
|
||||
|
||||
foreach ($users as &$user) {
|
||||
if (empty($user['name'])) {
|
||||
$user['value'] = $user['username'].' (#'.$user['id'].')';
|
||||
$user['label'] = $user['username'];
|
||||
} else {
|
||||
$user['value'] = $user['name'].' (#'.$user['id'].')';
|
||||
$user['label'] = $user['name'].' ('.$user['username'].')';
|
||||
}
|
||||
foreach ($this->users as $user) {
|
||||
$result[] = array(
|
||||
'id' => $user->getInternalId(),
|
||||
'username' => $user->getUsername(),
|
||||
'external_id' => $user->getExternalId(),
|
||||
'external_id_column' => $user->getExternalIdColumn(),
|
||||
'value' => $user->getName() === '' ? $user->getUsername() : $user->getName(),
|
||||
'label' => $user->getName() === '' ? $user->getUsername() : $user->getName().' ('.$user->getUsername().')',
|
||||
);
|
||||
}
|
||||
|
||||
return $users;
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,4 +376,20 @@ class UserModel extends Base
|
||||
->eq('id', $user_id)
|
||||
->save(array('token' => ''));
|
||||
}
|
||||
|
||||
public function getOrCreateExternalUserId($username, $name, $externalIdColumn, $externalId)
|
||||
{
|
||||
$userId = $this->db->table(self::TABLE)->eq($externalIdColumn, $externalId)->findOneColumn('id');
|
||||
|
||||
if (empty($userId)) {
|
||||
$userId = $this->create(array(
|
||||
'username' => $username,
|
||||
'name' => $name,
|
||||
'is_ldap_user' => 1,
|
||||
$externalIdColumn => $externalId,
|
||||
));
|
||||
}
|
||||
|
||||
return $userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ class GroupProvider implements ServiceProviderInterface
|
||||
*/
|
||||
public function register(Container $container)
|
||||
{
|
||||
$container['groupManager'] = new GroupManager;
|
||||
$container['groupManager'] = new GroupManager();
|
||||
|
||||
if (DB_GROUP_PROVIDER) {
|
||||
$container['groupManager']->register(new DatabaseBackendGroupProvider($container));
|
||||
|
||||
35
app/ServiceProvider/UserProvider.php
Normal file
35
app/ServiceProvider/UserProvider.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\ServiceProvider;
|
||||
|
||||
use Kanboard\Core\User\UserManager;
|
||||
use Kanboard\User\DatabaseBackendUserProvider;
|
||||
use Pimple\Container;
|
||||
use Pimple\ServiceProviderInterface;
|
||||
|
||||
/**
|
||||
* User Provider
|
||||
*
|
||||
* @package Kanboard\ServiceProvider
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class UserProvider implements ServiceProviderInterface
|
||||
{
|
||||
/**
|
||||
* Register providers
|
||||
*
|
||||
* @access public
|
||||
* @param \Pimple\Container $container
|
||||
* @return \Pimple\Container
|
||||
*/
|
||||
public function register(Container $container)
|
||||
{
|
||||
$container['userManager'] = new UserManager();
|
||||
|
||||
if (DB_USER_PROVIDER) {
|
||||
$container['userManager']->register(new DatabaseBackendUserProvider($container));
|
||||
}
|
||||
|
||||
return $container;
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,7 @@
|
||||
'placeholder="'.t('Enter group name...').'"',
|
||||
'title="'.t('Enter group name...').'"',
|
||||
'data-dst-field="group_id"',
|
||||
'data-dst-extra-field="external_id"',
|
||||
'data-dst-extra-fields="external_id"',
|
||||
'data-search-url="'.$this->url->href('GroupAjaxController', 'autocomplete').'"',
|
||||
),
|
||||
'autocomplete') ?>
|
||||
|
||||
@@ -34,15 +34,19 @@
|
||||
<?= $this->form->csrf() ?>
|
||||
<?= $this->form->hidden('project_id', array('project_id' => $project['id'])) ?>
|
||||
<?= $this->form->hidden('user_id', $values) ?>
|
||||
<?= $this->form->hidden('username', $values) ?>
|
||||
<?= $this->form->hidden('external_id', $values) ?>
|
||||
<?= $this->form->hidden('external_id_column', $values) ?>
|
||||
|
||||
<?= $this->form->label(t('Name'), 'name') ?>
|
||||
<?= $this->form->text('name', $values, $errors, array(
|
||||
'required',
|
||||
'placeholder="'.t('Enter user name...').'"',
|
||||
'title="'.t('Enter user name...').'"',
|
||||
'data-dst-field="user_id"',
|
||||
'data-search-url="'.$this->url->href('UserAjaxController', 'autocomplete').'"',
|
||||
),
|
||||
'required',
|
||||
'placeholder="'.t('Enter user name...').'"',
|
||||
'title="'.t('Enter user name...').'"',
|
||||
'data-dst-field="user_id"',
|
||||
'data-dst-extra-fields="external_id,external_id_column,username"',
|
||||
'data-search-url="'.$this->url->href('UserAjaxController', 'autocomplete').'"',
|
||||
),
|
||||
'autocomplete') ?>
|
||||
|
||||
<?= $this->form->select('role', $roles, $values, $errors) ?>
|
||||
|
||||
43
app/User/DatabaseBackendUserProvider.php
Normal file
43
app/User/DatabaseBackendUserProvider.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\User;
|
||||
|
||||
use Kanboard\Core\Base;
|
||||
use Kanboard\Core\User\UserBackendProviderInterface;
|
||||
use Kanboard\Filter\UserNameFilter;
|
||||
use Kanboard\Model\UserModel;
|
||||
|
||||
/**
|
||||
* Database Backend User Provider
|
||||
*
|
||||
* @package Kanboard\User
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class DatabaseBackendUserProvider extends Base implements UserBackendProviderInterface
|
||||
{
|
||||
/**
|
||||
* Find a group from a search query
|
||||
*
|
||||
* @access public
|
||||
* @param string $input
|
||||
* @return DatabaseUserProvider[]
|
||||
*/
|
||||
public function find($input)
|
||||
{
|
||||
$result = array();
|
||||
|
||||
$users = $this->userQuery->withFilter(new UserNameFilter($input))
|
||||
->getQuery()
|
||||
->columns(UserModel::TABLE.'.id', UserModel::TABLE.'.username', UserModel::TABLE.'.name')
|
||||
->eq(UserModel::TABLE.'.is_active', 1)
|
||||
->asc(UserModel::TABLE.'.name')
|
||||
->asc(UserModel::TABLE.'.username')
|
||||
->findAll();
|
||||
|
||||
foreach ($users as $user) {
|
||||
$result[] = new DatabaseUserProvider($user);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -83,7 +83,7 @@ class DatabaseUserProvider implements UserProviderInterface
|
||||
*/
|
||||
public function getRole()
|
||||
{
|
||||
return '';
|
||||
return empty($this->user['role']) ? '' : $this->user['role'];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,7 +94,7 @@ class DatabaseUserProvider implements UserProviderInterface
|
||||
*/
|
||||
public function getUsername()
|
||||
{
|
||||
return '';
|
||||
return empty($this->user['username']) ? '' : $this->user['username'];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,7 +105,7 @@ class DatabaseUserProvider implements UserProviderInterface
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return '';
|
||||
return empty($this->user['name']) ? '' : $this->user['name'];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -116,7 +116,7 @@ class DatabaseUserProvider implements UserProviderInterface
|
||||
*/
|
||||
public function getEmail()
|
||||
{
|
||||
return '';
|
||||
return empty($this->user['email']) ? '' : $this->user['email'];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -42,6 +42,7 @@ $container->register(new Kanboard\ServiceProvider\NotificationProvider());
|
||||
$container->register(new Kanboard\ServiceProvider\ClassProvider());
|
||||
$container->register(new Kanboard\ServiceProvider\EventDispatcherProvider());
|
||||
$container->register(new Kanboard\ServiceProvider\GroupProvider());
|
||||
$container->register(new Kanboard\ServiceProvider\UserProvider());
|
||||
$container->register(new Kanboard\ServiceProvider\RouteProvider());
|
||||
$container->register(new Kanboard\ServiceProvider\ActionProvider());
|
||||
$container->register(new Kanboard\ServiceProvider\ExternalLinkProvider());
|
||||
|
||||
@@ -56,6 +56,7 @@ defined('DB_SSL_CA') or define('DB_SSL_CA', null);
|
||||
|
||||
// Database backend group provider
|
||||
defined('DB_GROUP_PROVIDER') or define('DB_GROUP_PROVIDER', true);
|
||||
defined('DB_USER_PROVIDER') or define('DB_USER_PROVIDER', true);
|
||||
|
||||
// LDAP configuration
|
||||
defined('LDAP_AUTH') or define('LDAP_AUTH', false);
|
||||
|
||||
Reference in New Issue
Block a user