Add project owner

This commit is contained in:
Frederic Guillot 2016-01-24 16:29:14 -05:00
parent 203754649e
commit 4fa38bf417
41 changed files with 293 additions and 89 deletions

View File

@ -1,3 +1,10 @@
Version 1.0.25 (unreleased)
--------------
New features:
* Add project owner (Directly Responsible Individual)
Version 1.0.24
--------------

View File

@ -248,7 +248,7 @@ abstract class Base extends \Kanboard\Core\Base
protected function getProject($project_id = 0)
{
$project_id = $this->request->getIntegerParam('project_id', $project_id);
$project = $this->project->getById($project_id);
$project = $this->project->getByIdWithOwner($project_id);
if (empty($project)) {
$this->flash->failure(t('Project not found.'));
@ -308,6 +308,29 @@ abstract class Base extends \Kanboard\Core\Base
'board_selector' => $board_selector,
'filters' => $filters,
'title' => $project['name'],
'description' => $this->getProjectDescription($project),
);
}
/**
* Get project description
*
* @access protected
* @param array &$project
* @return string
*/
protected function getProjectDescription(array &$project) {
if ($project['owner_id'] > 0) {
$description = t('Project owner: ').'**'.$this->template->e($project['owner_name'] ?: $project['owner_username']).'**'.PHP_EOL.PHP_EOL;
if (! empty($project['description'])) {
$description .= '***'.PHP_EOL.PHP_EOL;
$description .= $project['description'];
}
} else {
$description = $project['description'];
}
return $description;
}
}

View File

@ -54,7 +54,6 @@ class Board extends Base
'users_list' => $this->projectUserRole->getAssignableUsersList($params['project']['id'], false),
'custom_filters_list' => $this->customFilter->getAll($params['project']['id'], $this->userSession->getId()),
'swimlanes' => $this->taskFilter->search($params['filters']['search'])->getBoard($params['project']['id']),
'description' => $params['project']['description'],
'board_private_refresh_interval' => $this->config->get('board_private_refresh_interval'),
'board_highlight_period' => $this->config->get('board_highlight_period'),
) + $params));

View File

@ -29,7 +29,7 @@ class Project extends Base
->setUrl('project', 'index')
->setMax(20)
->setOrder('name')
->setQuery($this->project->getQueryProjectDetails($project_ids))
->setQuery($this->project->getQueryColumnStats($project_ids))
->calculate();
$this->response->html($this->template->layout('project/index', array(
@ -145,6 +145,7 @@ class Project extends Base
'values' => empty($values) ? $project : $values,
'errors' => $errors,
'project' => $project,
'owners' => $this->projectUserRole->getAssignableUsersList($project['id'], true),
'title' => t('Edit project')
)));
}

View File

@ -131,4 +131,17 @@ class Projectuser extends Base
{
$this->tasks(TaskModel::STATUS_CLOSED, 'closed', t('Closed tasks'), 'Closed tasks assigned to "%s"');
}
/**
* Users tooltip
*/
public function users()
{
$project = $this->getProject();
return $this->response->html($this->template->render('project_user/tooltip_users', array(
'users' => $this->projectUserRole->getAllUsersGroupedByRole($project['id']),
'roles' => $this->role->getProjectRoles(),
)));
}
}

View File

@ -686,7 +686,6 @@ return array(
'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => 'Uzmi sliku ekrana i pritisni CTRL+V ili ⌘+V da zalijepiš ovdje.',
'Screenshot uploaded successfully.' => 'Slika ekrana uspješno dodana.',
'SEK - Swedish Krona' => 'SEK - Švedska kruna',
'The project identifier is an optional alphanumeric code used to identify your project.' => 'Identifikator projekta je opcionalni alfanumerički kod koji se koristi za identifikaciju projekta.',
'Identifier' => 'Identifikator',
'Disable two factor authentication' => 'Onemogući faktor-dva autentifikaciju',
'Do you really want to disable the two factor authentication for this user: "%s"?' => 'Da li zaista želiš onemogućiti faktor-dva autentifikaciju: "%s"?',
@ -1104,4 +1103,10 @@ return array(
// 'No plugin has registered a project notification method. You can still configure individual notifications in your user profile.' => '',
// 'My dashboard' => '',
// 'My profile' => '',
// 'Project owner: ' => '',
// 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '',
// 'Project owner' => '',
// 'Those dates are useful for the project Gantt chart.' => '',
// 'Private projects do not have users and groups management.' => '',
// 'There is no project member.' => '',
);

View File

@ -686,7 +686,6 @@ return array(
'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => 'Nimm einen Screenshot auf und drücke STRG+V oder ⌘+V um ihn hier einzufügen.',
'Screenshot uploaded successfully.' => 'Screenshot erfolgreich hochgeladen.',
'SEK - Swedish Krona' => 'SEK - Schwedische Kronen',
'The project identifier is an optional alphanumeric code used to identify your project.' => 'Identifikátor projektu je volitelný alfanumerický kód používaný k identifikaci vašeho projektu.',
'Identifier' => 'Identifikator',
'Disable two factor authentication' => 'Zrušit dvou stupňovou autorizaci',
'Do you really want to disable the two factor authentication for this user: "%s"?' => 'Willst du wirklich für folgenden Nutzer die Zwei-Faktor-Authentifizierung deaktivieren: "%s"?',
@ -1104,4 +1103,10 @@ return array(
// 'No plugin has registered a project notification method. You can still configure individual notifications in your user profile.' => '',
// 'My dashboard' => '',
// 'My profile' => '',
// 'Project owner: ' => '',
// 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '',
// 'Project owner' => '',
// 'Those dates are useful for the project Gantt chart.' => '',
// 'Private projects do not have users and groups management.' => '',
// 'There is no project member.' => '',
);

View File

@ -686,7 +686,6 @@ return array(
// 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => '',
// 'Screenshot uploaded successfully.' => '',
// 'SEK - Swedish Krona' => '',
// 'The project identifier is an optional alphanumeric code used to identify your project.' => '',
// 'Identifier' => '',
// 'Disable two factor authentication' => '',
// 'Do you really want to disable the two factor authentication for this user: "%s"?' => '',
@ -1104,4 +1103,10 @@ return array(
// 'No plugin has registered a project notification method. You can still configure individual notifications in your user profile.' => '',
// 'My dashboard' => '',
// 'My profile' => '',
// 'Project owner: ' => '',
// 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '',
// 'Project owner' => '',
// 'Those dates are useful for the project Gantt chart.' => '',
// 'Private projects do not have users and groups management.' => '',
// 'There is no project member.' => '',
);

View File

@ -686,7 +686,6 @@ return array(
'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => 'Nimm einen Screenshot auf und drücke STRG+V oder ⌘+V um ihn hier einzufügen.',
'Screenshot uploaded successfully.' => 'Screenshot erfolgreich hochgeladen.',
'SEK - Swedish Krona' => 'SEK - Schwedische Kronen',
'The project identifier is an optional alphanumeric code used to identify your project.' => 'Der Projektidentifikator ist ein optionaler alphanumerischer Code, der das Projekt identifiziert.',
'Identifier' => 'Identifikator',
'Disable two factor authentication' => 'Deaktiviere Zwei-Faktor-Authentifizierung',
'Do you really want to disable the two factor authentication for this user: "%s"?' => 'Willst du wirklich für folgenden Nutzer die Zwei-Faktor-Authentifizierung deaktivieren: "%s"?',
@ -1104,4 +1103,10 @@ return array(
// 'No plugin has registered a project notification method. You can still configure individual notifications in your user profile.' => '',
// 'My dashboard' => '',
// 'My profile' => '',
// 'Project owner: ' => '',
// 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '',
// 'Project owner' => '',
// 'Those dates are useful for the project Gantt chart.' => '',
// 'Private projects do not have users and groups management.' => '',
// 'There is no project member.' => '',
);

View File

@ -686,7 +686,6 @@ return array(
'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => 'Capture un patallazo y pulse CTRL+V o ⌘+V para pegar aquí.',
'Screenshot uploaded successfully.' => 'Pantallazo cargado con éxito',
'SEK - Swedish Krona' => 'SEK - Corona sueca',
'The project identifier is an optional alphanumeric code used to identify your project.' => 'El identificador del proyecto us un código opcional alfanumérico que se usa para identificar su proyecto.',
'Identifier' => 'Identificador',
'Disable two factor authentication' => 'Desactivar la autenticación de dos factores',
'Do you really want to disable the two factor authentication for this user: "%s"?' => '¿Realmentes quiere desactuvar la autenticación de dos factores para este usuario: "%s?"',
@ -1104,4 +1103,10 @@ return array(
// 'No plugin has registered a project notification method. You can still configure individual notifications in your user profile.' => '',
// 'My dashboard' => '',
// 'My profile' => '',
// 'Project owner: ' => '',
// 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '',
// 'Project owner' => '',
// 'Those dates are useful for the project Gantt chart.' => '',
// 'Private projects do not have users and groups management.' => '',
// 'There is no project member.' => '',
);

View File

@ -686,7 +686,6 @@ return array(
// 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => '',
// 'Screenshot uploaded successfully.' => '',
// 'SEK - Swedish Krona' => '',
// 'The project identifier is an optional alphanumeric code used to identify your project.' => '',
// 'Identifier' => '',
// 'Disable two factor authentication' => '',
// 'Do you really want to disable the two factor authentication for this user: "%s"?' => '',
@ -1104,4 +1103,10 @@ return array(
// 'No plugin has registered a project notification method. You can still configure individual notifications in your user profile.' => '',
// 'My dashboard' => '',
// 'My profile' => '',
// 'Project owner: ' => '',
// 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '',
// 'Project owner' => '',
// 'Those dates are useful for the project Gantt chart.' => '',
// 'Private projects do not have users and groups management.' => '',
// 'There is no project member.' => '',
);

View File

@ -688,7 +688,6 @@ return array(
'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => 'Prenez une capture d\'écran et appuyez sur CTRL+V ou ⌘+V pour coller ici.',
'Screenshot uploaded successfully.' => 'Capture d\'écran téléchargée avec succès.',
'SEK - Swedish Krona' => 'SEK - Couronne suédoise',
'The project identifier is an optional alphanumeric code used to identify your project.' => 'L\'identificateur du projet est un code alpha-numérique optionnel pour identifier votre projet.',
'Identifier' => 'Identificateur',
'Disable two factor authentication' => 'Désactiver l\'authentification à deux facteurs',
'Do you really want to disable the two factor authentication for this user: "%s"?' => 'Voulez-vous vraiment désactiver l\'authentification à deux facteurs pour cet utilisateur : « %s » ?',
@ -701,7 +700,7 @@ return array(
'Score' => 'Complexité',
'The identifier must be unique' => 'L\'identifiant doit être unique',
'This linked task id doesn\'t exists' => 'L\'identifiant de la task liée n\'existe pas',
'This value must be alphanumeric' => 'Cette valeur doit être alpha-numérique',
'This value must be alphanumeric' => 'Cette valeur doit être alphanumérique',
'Edit recurrence' => 'Modifier la récurrence',
'Generate recurrent task' => 'Générer une tâche récurrente',
'Trigger to generate recurrent task' => 'Déclencheur pour générer la tâche récurrente',
@ -1107,4 +1106,10 @@ return array(
'No plugin has registered a project notification method. You can still configure individual notifications in your user profile.' => 'Aucun plugin n\'a enregistré une méthode de notification de projet. Vous pouvez toujours configurer les notifications individuelles dans votre profil d\'utilisateur.',
'My dashboard' => 'Mon tableau de bord',
'My profile' => 'Mon profile',
'Project owner: ' => 'Responsable du projet : ',
'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => 'L\'identifiant du projet est optionnel et doit être alphanumérique, example: MONPROJET.',
'Project owner' => 'Responsable du projet',
'Those dates are useful for the project Gantt chart.' => 'Ces dates sont utiles pour le diagramme de Gantt des projets.',
'Private projects do not have users and groups management.' => 'Les projets privés n\'ont pas de gestion d\'utilisateurs et de groupes.',
'There is no project member.' => 'Il y a aucun membre du projet.',
);

View File

@ -686,7 +686,6 @@ return array(
// 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => '',
// 'Screenshot uploaded successfully.' => '',
// 'SEK - Swedish Krona' => '',
// 'The project identifier is an optional alphanumeric code used to identify your project.' => '',
// 'Identifier' => '',
// 'Disable two factor authentication' => '',
// 'Do you really want to disable the two factor authentication for this user: "%s"?' => '',
@ -1104,4 +1103,10 @@ return array(
// 'No plugin has registered a project notification method. You can still configure individual notifications in your user profile.' => '',
// 'My dashboard' => '',
// 'My profile' => '',
// 'Project owner: ' => '',
// 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '',
// 'Project owner' => '',
// 'Those dates are useful for the project Gantt chart.' => '',
// 'Private projects do not have users and groups management.' => '',
// 'There is no project member.' => '',
);

View File

@ -686,7 +686,6 @@ return array(
'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => 'Mengambil screenshot dan tekan CTRL + V atau ⌘ + V untuk paste di sini.',
'Screenshot uploaded successfully.' => 'Screenshot berhasil diunggah.',
'SEK - Swedish Krona' => 'SEK - Krona Swedia',
'The project identifier is an optional alphanumeric code used to identify your project.' => 'Identifier proyek adalah kode alfanumerik opsional digunakan untuk mengidentifikasi proyek Anda.',
'Identifier' => 'Identifier',
'Disable two factor authentication' => 'Matikan dua faktor otentifikasi',
'Do you really want to disable the two factor authentication for this user: "%s"?' => 'Apakah anda yakin akan mematikan dua faktor otentifikasi untuk pengguna ini : « %s » ?',
@ -1104,4 +1103,10 @@ return array(
// 'No plugin has registered a project notification method. You can still configure individual notifications in your user profile.' => '',
// 'My dashboard' => '',
// 'My profile' => '',
// 'Project owner: ' => '',
// 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '',
// 'Project owner' => '',
// 'Those dates are useful for the project Gantt chart.' => '',
// 'Private projects do not have users and groups management.' => '',
// 'There is no project member.' => '',
);

View File

@ -686,7 +686,6 @@ return array(
// 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => '',
// 'Screenshot uploaded successfully.' => '',
// 'SEK - Swedish Krona' => '',
// 'The project identifier is an optional alphanumeric code used to identify your project.' => '',
// 'Identifier' => '',
// 'Disable two factor authentication' => '',
// 'Do you really want to disable the two factor authentication for this user: "%s"?' => '',
@ -1104,4 +1103,10 @@ return array(
// 'No plugin has registered a project notification method. You can still configure individual notifications in your user profile.' => '',
// 'My dashboard' => '',
// 'My profile' => '',
// 'Project owner: ' => '',
// 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '',
// 'Project owner' => '',
// 'Those dates are useful for the project Gantt chart.' => '',
// 'Private projects do not have users and groups management.' => '',
// 'There is no project member.' => '',
);

View File

@ -686,7 +686,6 @@ return array(
// 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => '',
// 'Screenshot uploaded successfully.' => '',
// 'SEK - Swedish Krona' => '',
// 'The project identifier is an optional alphanumeric code used to identify your project.' => '',
// 'Identifier' => '',
// 'Disable two factor authentication' => '',
// 'Do you really want to disable the two factor authentication for this user: "%s"?' => '',
@ -1104,4 +1103,10 @@ return array(
// 'No plugin has registered a project notification method. You can still configure individual notifications in your user profile.' => '',
// 'My dashboard' => '',
// 'My profile' => '',
// 'Project owner: ' => '',
// 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '',
// 'Project owner' => '',
// 'Those dates are useful for the project Gantt chart.' => '',
// 'Private projects do not have users and groups management.' => '',
// 'There is no project member.' => '',
);

View File

@ -686,7 +686,6 @@ return array(
// 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => '',
'Screenshot uploaded successfully.' => 'Screenshot berhasil diunggah.',
'SEK - Swedish Krona' => 'SEK - Krona Swedia',
'The project identifier is an optional alphanumeric code used to identify your project.' => 'Identifier projek adalah kode alfanumerik opsional digunakan untuk mengidentifikasi projek Anda.',
'Identifier' => 'Identifier',
'Disable two factor authentication' => 'Matikan dua faktor otentifikasi',
'Do you really want to disable the two factor authentication for this user: "%s"?' => 'Apakah anda yakin akan mematikan dua faktor otentifikasi untuk pengguna ini : « %s » ?',
@ -1104,4 +1103,10 @@ return array(
// 'No plugin has registered a project notification method. You can still configure individual notifications in your user profile.' => '',
// 'My dashboard' => '',
// 'My profile' => '',
// 'Project owner: ' => '',
// 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '',
// 'Project owner' => '',
// 'Those dates are useful for the project Gantt chart.' => '',
// 'Private projects do not have users and groups management.' => '',
// 'There is no project member.' => '',
);

View File

@ -686,7 +686,6 @@ return array(
// 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => '',
'Screenshot uploaded successfully.' => 'Skjermbilde opplastet',
// 'SEK - Swedish Krona' => '',
'The project identifier is an optional alphanumeric code used to identify your project.' => 'Prosjektkoden er en alfanumerisk kode som kan brukes for å identifisere prosjektet',
'Identifier' => 'Prosjektkode',
// 'Disable two factor authentication' => '',
// 'Do you really want to disable the two factor authentication for this user: "%s"?' => '',
@ -1104,4 +1103,10 @@ return array(
// 'No plugin has registered a project notification method. You can still configure individual notifications in your user profile.' => '',
// 'My dashboard' => '',
// 'My profile' => '',
// 'Project owner: ' => '',
// 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '',
// 'Project owner' => '',
// 'Those dates are useful for the project Gantt chart.' => '',
// 'Private projects do not have users and groups management.' => '',
// 'There is no project member.' => '',
);

View File

@ -686,7 +686,6 @@ return array(
// 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => '',
// 'Screenshot uploaded successfully.' => '',
// 'SEK - Swedish Krona' => '',
// 'The project identifier is an optional alphanumeric code used to identify your project.' => '',
// 'Identifier' => '',
// 'Disable two factor authentication' => '',
// 'Do you really want to disable the two factor authentication for this user: "%s"?' => '',
@ -1104,4 +1103,10 @@ return array(
// 'No plugin has registered a project notification method. You can still configure individual notifications in your user profile.' => '',
// 'My dashboard' => '',
// 'My profile' => '',
// 'Project owner: ' => '',
// 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '',
// 'Project owner' => '',
// 'Those dates are useful for the project Gantt chart.' => '',
// 'Private projects do not have users and groups management.' => '',
// 'There is no project member.' => '',
);

View File

@ -686,7 +686,6 @@ return array(
'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => 'Zrób zrzut ekranu i wciśnij CTRL+V by dodać go tutaj.',
'Screenshot uploaded successfully.' => 'Zrzut ekranu dodany.',
'SEK - Swedish Krona' => 'SEK - Korona szwedzka',
'The project identifier is an optional alphanumeric code used to identify your project.' => 'Identyfikator projektu to opcjonalny kod alfanumeryczny do identyfikacji projektu.',
'Identifier' => 'Identyfikator',
'Disable two factor authentication' => 'Wyłącz uwierzytelnianie dwuetapowe',
'Do you really want to disable the two factor authentication for this user: "%s"?' => 'Czy na pewno chcesz wyłączyć uwierzytelnianie dwuetapowe dla tego użytkownika: "%s"?',
@ -1104,4 +1103,10 @@ return array(
// 'No plugin has registered a project notification method. You can still configure individual notifications in your user profile.' => '',
// 'My dashboard' => '',
// 'My profile' => '',
// 'Project owner: ' => '',
// 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '',
// 'Project owner' => '',
// 'Those dates are useful for the project Gantt chart.' => '',
// 'Private projects do not have users and groups management.' => '',
// 'There is no project member.' => '',
);

View File

@ -686,7 +686,6 @@ return array(
'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => 'Tire uma captura de tela e pressione CTRL + V ou ⌘ + V para colar aqui.',
'Screenshot uploaded successfully.' => 'Captura de tela enviada com sucesso.',
'SEK - Swedish Krona' => 'SEK - Coroa sueca',
'The project identifier is an optional alphanumeric code used to identify your project.' => 'O identificador de projeto é um código alfanumérico opcional utilizado para identificar o seu projeto.',
'Identifier' => 'Identificador',
'Disable two factor authentication' => 'Desativar autenticação em duas etapas',
'Do you really want to disable the two factor authentication for this user: "%s"?' => 'Você realmente deseja desativar a autenticação em duas etapas para este usuário: "%s"?',
@ -1104,4 +1103,10 @@ return array(
// 'No plugin has registered a project notification method. You can still configure individual notifications in your user profile.' => '',
// 'My dashboard' => '',
// 'My profile' => '',
// 'Project owner: ' => '',
// 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '',
// 'Project owner' => '',
// 'Those dates are useful for the project Gantt chart.' => '',
// 'Private projects do not have users and groups management.' => '',
// 'There is no project member.' => '',
);

View File

@ -686,7 +686,6 @@ return array(
'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => 'Tire um screenshot e pressione CTRL + V ou ⌘ + V para colar aqui.',
'Screenshot uploaded successfully.' => 'Screenshot enviada com sucesso.',
'SEK - Swedish Krona' => 'SEK - Coroa sueca',
'The project identifier is an optional alphanumeric code used to identify your project.' => 'O identificador de projecto é um código alfanumérico opcional utilizado para identificar o seu projecto.',
'Identifier' => 'Identificador',
'Disable two factor authentication' => 'Desactivar autenticação com dois factores',
'Do you really want to disable the two factor authentication for this user: "%s"?' => 'Tem a certeza que quer desactivar a autenticação com dois factores para esse utilizador: "%s"?',
@ -1104,4 +1103,10 @@ return array(
// 'No plugin has registered a project notification method. You can still configure individual notifications in your user profile.' => '',
// 'My dashboard' => '',
// 'My profile' => '',
// 'Project owner: ' => '',
// 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '',
// 'Project owner' => '',
// 'Those dates are useful for the project Gantt chart.' => '',
// 'Private projects do not have users and groups management.' => '',
// 'There is no project member.' => '',
);

View File

@ -686,7 +686,6 @@ return array(
'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => 'Сделайте скриншот и нажмите CTRL+V или ⌘+V для вложения',
'Screenshot uploaded successfully.' => 'Скриншет успешно загружен',
'SEK - Swedish Krona' => 'SEK - Шведская крона',
'The project identifier is an optional alphanumeric code used to identify your project.' => 'Идентификатор проекта - это опциональный буквенно-цифровой код использующийся для идентификации проекта',
'Identifier' => 'Идентификатор',
'Disable two factor authentication' => 'Выключить двухфакторную авторизацию',
'Do you really want to disable the two factor authentication for this user: "%s"?' => 'Вы действительно хотите выключить двухфакторную авторизацию для пользователя "%s"?',
@ -1104,4 +1103,10 @@ return array(
// 'No plugin has registered a project notification method. You can still configure individual notifications in your user profile.' => '',
// 'My dashboard' => '',
// 'My profile' => '',
// 'Project owner: ' => '',
// 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '',
// 'Project owner' => '',
// 'Those dates are useful for the project Gantt chart.' => '',
// 'Private projects do not have users and groups management.' => '',
// 'There is no project member.' => '',
);

View File

@ -686,7 +686,6 @@ return array(
// 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => '',
// 'Screenshot uploaded successfully.' => '',
// 'SEK - Swedish Krona' => '',
// 'The project identifier is an optional alphanumeric code used to identify your project.' => '',
// 'Identifier' => '',
// 'Disable two factor authentication' => '',
// 'Do you really want to disable the two factor authentication for this user: "%s"?' => '',
@ -1104,4 +1103,10 @@ return array(
// 'No plugin has registered a project notification method. You can still configure individual notifications in your user profile.' => '',
// 'My dashboard' => '',
// 'My profile' => '',
// 'Project owner: ' => '',
// 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '',
// 'Project owner' => '',
// 'Those dates are useful for the project Gantt chart.' => '',
// 'Private projects do not have users and groups management.' => '',
// 'There is no project member.' => '',
);

View File

@ -686,7 +686,6 @@ return array(
'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => 'Ta en skärmdump och tryck CTRL+V för att klistra in här.',
'Screenshot uploaded successfully.' => 'Skärmdumpen laddades upp.',
'SEK - Swedish Krona' => 'SEK - Svensk Krona',
'The project identifier is an optional alphanumeric code used to identify your project.' => 'Projektidentifieraren är en valbar alfanumerisk kod som används för att identifiera ditt projekt.',
'Identifier' => 'Identifierare',
'Disable two factor authentication' => 'Inaktivera två-faktors autentisering',
'Do you really want to disable the two factor authentication for this user: "%s"?' => 'Vill du verkligen inaktivera två-faktors autentisering för denna användare: "%s"?',
@ -1104,4 +1103,10 @@ return array(
// 'No plugin has registered a project notification method. You can still configure individual notifications in your user profile.' => '',
// 'My dashboard' => '',
// 'My profile' => '',
// 'Project owner: ' => '',
// 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '',
// 'Project owner' => '',
// 'Those dates are useful for the project Gantt chart.' => '',
// 'Private projects do not have users and groups management.' => '',
// 'There is no project member.' => '',
);

View File

@ -686,7 +686,6 @@ return array(
// 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => '',
'Screenshot uploaded successfully.' => 'อัพโหลด screenshot เรียบร้อยแล้ว',
// 'SEK - Swedish Krona' => '',
// 'The project identifier is an optional alphanumeric code used to identify your project.' => '',
// 'Identifier' => '',
// 'Disable two factor authentication' => '',
// 'Do you really want to disable the two factor authentication for this user: "%s"?' => '',
@ -1104,4 +1103,10 @@ return array(
// 'No plugin has registered a project notification method. You can still configure individual notifications in your user profile.' => '',
// 'My dashboard' => '',
// 'My profile' => '',
// 'Project owner: ' => '',
// 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '',
// 'Project owner' => '',
// 'Those dates are useful for the project Gantt chart.' => '',
// 'Private projects do not have users and groups management.' => '',
// 'There is no project member.' => '',
);

View File

@ -686,7 +686,6 @@ return array(
'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => 'Bir ekran görüntüsü alın ve buraya yapıştırmak için CTRL+V veya ⌘+V tuşlarına basın.',
'Screenshot uploaded successfully.' => 'Ekran görüntüsü başarıyla yüklendi',
// 'SEK - Swedish Krona' => '',
'The project identifier is an optional alphanumeric code used to identify your project.' => 'Proje kimliği, projeyi tanımlamak için kullanılan opsiyonel bir alfanumerik koddur.',
'Identifier' => 'Kimlik',
'Disable two factor authentication' => 'İki kademeli doğrulamayı iptal et',
'Do you really want to disable the two factor authentication for this user: "%s"?' => 'Bu kullanıcı için iki kademeli doğrulamayı iptal etmek istediğinize emin misiniz: "%s"?',
@ -1104,4 +1103,10 @@ return array(
// 'No plugin has registered a project notification method. You can still configure individual notifications in your user profile.' => '',
// 'My dashboard' => '',
// 'My profile' => '',
// 'Project owner: ' => '',
// 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '',
// 'Project owner' => '',
// 'Those dates are useful for the project Gantt chart.' => '',
// 'Private projects do not have users and groups management.' => '',
// 'There is no project member.' => '',
);

View File

@ -686,7 +686,6 @@ return array(
// 'Take a screenshot and press CTRL+V or ⌘+V to paste here.' => '',
// 'Screenshot uploaded successfully.' => '',
// 'SEK - Swedish Krona' => '',
// 'The project identifier is an optional alphanumeric code used to identify your project.' => '',
// 'Identifier' => '',
// 'Disable two factor authentication' => '',
// 'Do you really want to disable the two factor authentication for this user: "%s"?' => '',
@ -1104,4 +1103,10 @@ return array(
// 'No plugin has registered a project notification method. You can still configure individual notifications in your user profile.' => '',
// 'My dashboard' => '',
// 'My profile' => '',
// 'Project owner: ' => '',
// 'The project identifier is optional and must be alphanumeric, example: MYPROJECT.' => '',
// 'Project owner' => '',
// 'Those dates are useful for the project Gantt chart.' => '',
// 'Private projects do not have users and groups management.' => '',
// 'There is no project member.' => '',
);

View File

@ -46,6 +46,22 @@ class Project extends Base
return $this->db->table(self::TABLE)->eq('id', $project_id)->findOne();
}
/**
* Get a project by id with owner name
*
* @access public
* @param integer $project_id Project id
* @return array
*/
public function getByIdWithOwner($project_id)
{
return $this->db->table(self::TABLE)
->columns(self::TABLE.'.*', User::TABLE.'.username AS owner_username', User::TABLE.'.name AS owner_name')
->eq(self::TABLE.'.id', $project_id)
->join(User::TABLE, 'id', 'owner_id')
->findOne();
}
/**
* Get a project by the name
*
@ -275,23 +291,6 @@ class Project extends Base
return $projects;
}
/**
* Fetch more information for each project
*
* @access public
* @param array $projects
* @return array
*/
public function applyProjectDetails(array $projects)
{
foreach ($projects as &$project) {
$this->getColumnStats($project);
$project = array_merge($project, $this->projectUserRole->getAllUsersGroupedByRole($project['id']));
}
return $projects;
}
/**
* Get project summary for a list of project
*
@ -307,29 +306,12 @@ class Project extends Base
return $this->db
->table(Project::TABLE)
->in('id', $project_ids)
->columns(self::TABLE.'.*', User::TABLE.'.username AS owner_username', User::TABLE.'.name AS owner_name')
->join(User::TABLE, 'id', 'owner_id')
->in(self::TABLE.'.id', $project_ids)
->callback(array($this, 'applyColumnStats'));
}
/**
* Get project details (users + columns) for a list of project
*
* @access public
* @param array $project_ids List of project id
* @return \PicoDb\Table
*/
public function getQueryProjectDetails(array $project_ids)
{
if (empty($project_ids)) {
return $this->db->table(Project::TABLE)->limit(0);
}
return $this->db
->table(Project::TABLE)
->in('id', $project_ids)
->callback(array($this, 'applyProjectDetails'));
}
/**
* Create a project
*
@ -346,6 +328,7 @@ class Project extends Base
$values['token'] = '';
$values['last_modified'] = time();
$values['is_private'] = empty($values['is_private']) ? 0 : 1;
$values['owner_id'] = $user_id;
if (! empty($values['identifier'])) {
$values['identifier'] = strtoupper($values['identifier']);

View File

@ -6,7 +6,12 @@ use PDO;
use Kanboard\Core\Security\Token;
use Kanboard\Core\Security\Role;
const VERSION = 101;
const VERSION = 102;
function version_102(PDO $pdo)
{
$pdo->exec("ALTER TABLE projects ADD COLUMN owner_id INT DEFAULT 0");
}
function version_101(PDO $pdo)
{

View File

@ -6,7 +6,12 @@ use PDO;
use Kanboard\Core\Security\Token;
use Kanboard\Core\Security\Role;
const VERSION = 81;
const VERSION = 82;
function version_82(PDO $pdo)
{
$pdo->exec("ALTER TABLE projects ADD COLUMN owner_id INTEGER DEFAULT 0");
}
function version_81(PDO $pdo)
{

View File

@ -6,7 +6,12 @@ use Kanboard\Core\Security\Token;
use Kanboard\Core\Security\Role;
use PDO;
const VERSION = 93;
const VERSION = 94;
function version_94(PDO $pdo)
{
$pdo->exec("ALTER TABLE projects ADD COLUMN owner_id INTEGER DEFAULT 0");
}
function version_93(PDO $pdo)
{

View File

@ -11,18 +11,26 @@
<?= $this->form->label(t('Identifier'), 'identifier') ?>
<?= $this->form->text('identifier', $values, $errors, array('maxlength="50"')) ?>
<p class="form-help"><?= t('The project identifier is an optional alphanumeric code used to identify your project.') ?></p>
<p class="form-help"><?= t('The project identifier is optional and must be alphanumeric, example: MYPROJECT.') ?></p>
<?= $this->form->label(t('Project owner'), 'owner_id') ?>
<?= $this->form->select('owner_id', $owners, $values, $errors) ?>
<hr>
<?= $this->form->label(t('Start date'), 'start_date') ?>
<?= $this->form->text('start_date', $values, $errors, array('maxlength="10"'), 'form-date') ?>
<?= $this->form->label(t('End date'), 'end_date') ?>
<?= $this->form->text('end_date', $values, $errors, array('maxlength="10"'), 'form-date') ?>
<p class="form-help"><?= t('Those dates are useful for the project Gantt chart.') ?></p>
<?php if ($this->user->hasProjectAccess('project', 'create', $project['id'])): ?>
<hr>
<?= $this->form->checkbox('is_private', t('Private project'), 1, $project['is_private'] == 1) ?>
<p class="form-help"><?= t('Private projects do not have users and groups management.') ?></p>
<?php endif ?>
<hr>
<?= $this->form->label(t('Description'), 'description') ?>
<div class="form-tabs">

View File

@ -23,9 +23,9 @@
<th class="column-15"><?= $paginator->order(t('Project'), 'name') ?></th>
<th class="column-8"><?= $paginator->order(t('Start date'), 'start_date') ?></th>
<th class="column-8"><?= $paginator->order(t('End date'), 'end_date') ?></th>
<th class="column-15"><?= $paginator->order(t('Owner'), 'owner_id') ?></th>
<?php if ($this->user->hasAccess('projectuser', 'managers')): ?>
<th class="column-12"><?= t('Managers') ?></th>
<th class="column-12"><?= t('Members') ?></th>
<th class="column-10"><?= t('Users') ?></th>
<?php endif ?>
<th><?= t('Columns') ?></th>
</tr>
@ -66,16 +66,15 @@
<td>
<?= $project['end_date'] ?>
</td>
<td>
<?php if ($project['owner_id'] > 0): ?>
<?= $this->e($project['owner_name'] ?: $project['owner_username']) ?>
<?php endif ?>
</td>
<?php if ($this->user->hasAccess('projectuser', 'managers')): ?>
<td>
<?= $this->render('project/roles', array('roles' => $project, 'role' => \Kanboard\Core\Security\Role::PROJECT_MANAGER)) ?>
</td>
<td>
<?php if ($project['is_everybody_allowed'] == 1): ?>
<?= t('Everybody') ?>
<?php else: ?>
<?= $this->render('project/roles', array('roles' => $project, 'role' => \Kanboard\Core\Security\Role::PROJECT_MEMBER)) ?>
<?php endif ?>
<i class="fa fa-users fa-fw"></i>
<a href="#" class="tooltip" title="<?= t('Members') ?>" data-href="<?= $this->url->href('Projectuser', 'users', array('project_id' => $project['id'])) ?>"><?= t('Members') ?></a>
</td>
<?php endif ?>
<td class="dashboard-project-stats">

View File

@ -1,7 +0,0 @@
<?php if (! empty($roles[$role])): ?>
<ul class="no-bullet">
<?php foreach ($roles[$role] as $user_id => $user_name): ?>
<li><?= $this->url->link($this->e($user_name), 'projectuser', 'opens', array('user_id' => $user_id)) ?></li>
<?php endforeach ?>
</ul>
<?php endif ?>

View File

@ -4,6 +4,10 @@
<ul class="listing">
<li><strong><?= $project['is_active'] ? t('Active') : t('Inactive') ?></strong></li>
<?php if ($project['owner_id'] > 0): ?>
<li><?= t('Project owner: ') ?><strong><?= $this->e($project['owner_name'] ?: $project['owner_username']) ?></strong></li>
<?php endif ?>
<?php if ($project['is_private']): ?>
<li><i class="fa fa-lock"></i> <?= t('This project is private') ?></li>
<?php endif ?>

View File

@ -11,6 +11,9 @@
<?php endif ?>
<?php if ($this->user->hasProjectAccess('project', 'edit', $project['id'])): ?>
<li <?= $this->app->checkMenuSelection('project', 'edit') ?>>
<?= $this->url->link(t('Edit project'), 'project', 'edit', array('project_id' => $project['id'])) ?>
</li>
<li <?= $this->app->checkMenuSelection('project', 'share') ?>>
<?= $this->url->link(t('Public access'), 'project', 'share', array('project_id' => $project['id'])) ?>
</li>
@ -20,9 +23,6 @@
<li <?= $this->app->checkMenuSelection('project', 'integrations') ?>>
<?= $this->url->link(t('Integrations'), 'project', 'integrations', array('project_id' => $project['id'])) ?>
</li>
<li <?= $this->app->checkMenuSelection('project', 'edit') ?>>
<?= $this->url->link(t('Edit project'), 'project', 'edit', array('project_id' => $project['id'])) ?>
</li>
<li <?= $this->app->checkMenuSelection('column') ?>>
<?= $this->url->link(t('Columns'), 'column', 'index', array('project_id' => $project['id'])) ?>
</li>

View File

@ -0,0 +1,14 @@
<?php if (empty($users)): ?>
<p><?= t('There is no project member.') ?></p>
<?php else: ?>
<?php foreach ($roles as $role => $role_name): ?>
<?php if (isset($users[$role])): ?>
<strong><?= $role_name ?></strong>
<ul>
<?php foreach ($users[$role] as $user_id => $user): ?>
<li><?= $this->url->link($this->e($user), 'Projectuser', 'opens', array('user_id' => $user_id)) ?></li>
<?php endforeach ?>
</ul>
<?php endif ?>
<?php endforeach ?>
<?php endif ?>

File diff suppressed because one or more lines are too long

View File

@ -55,6 +55,12 @@ nav .active a {
color: #d40000;
}
/* title tooltip */
header h1 .tooltip {
opacity: 0.3;
font-size: 0.6em;
}
/* page header */
.page-header {
margin-bottom: 20px;

View File

@ -281,4 +281,28 @@ class ProjectTest extends Base
$project = $p->getByIdentifier('');
$this->assertFalse($project);
}
public function testThatProjectCreatorAreAlsoOwner()
{
$projectModel = new Project($this->container);
$userModel = new User($this->container);
$this->assertEquals(2, $userModel->create(array('username' => 'user1', 'name' => 'Me')));
$this->assertEquals(1, $projectModel->create(array('name' => 'My project 1'), 2));
$this->assertEquals(2, $projectModel->create(array('name' => 'My project 2')));
$project = $projectModel->getByIdWithOwner(1);
$this->assertNotEmpty($project);
$this->assertSame('My project 1', $project['name']);
$this->assertSame('Me', $project['owner_name']);
$this->assertSame('user1', $project['owner_username']);
$this->assertEquals(2, $project['owner_id']);
$project = $projectModel->getByIdWithOwner(2);
$this->assertNotEmpty($project);
$this->assertSame('My project 2', $project['name']);
$this->assertEquals('', $project['owner_name']);
$this->assertEquals('', $project['owner_username']);
$this->assertEquals(0, $project['owner_id']);
}
}