Add user backend provider system

This commit is contained in:
Frederic Guillot
2017-11-09 15:09:54 -08:00
parent 95b2a36886
commit 44aa24bab1
23 changed files with 273 additions and 50 deletions

View File

@@ -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'])) {

View File

@@ -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());
}
/**

View File

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

View File

@@ -5,7 +5,7 @@ namespace Kanboard\Core\Group;
/**
* Group Backend Provider Interface
*
* @package group
* @package Kanboard\Core\Group
* @author Frederic Guillot
*/
interface GroupBackendProviderInterface

View File

@@ -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();

View File

@@ -5,7 +5,7 @@ namespace Kanboard\Core\Group;
/**
* Group Provider Interface
*
* @package group
* @package Kanboard\Core\Group
* @author Frederic Guillot
*/
interface GroupProviderInterface

View 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);
}

View 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);
}
}

View File

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

View File

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

View File

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

View File

@@ -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));

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

View File

@@ -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') ?>

View File

@@ -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) ?>

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

View File

@@ -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'];
}
/**

View File

@@ -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());

View File

@@ -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);