Add email address field for projects
This commit is contained in:
parent
8eac121888
commit
d5c4c18ea0
|
|
@ -3,6 +3,7 @@ Version 1.0.39 (unreleased)
|
|||
|
||||
Improvements:
|
||||
|
||||
* Add email address field for projects
|
||||
* Improve forget password behaviour (notify the user that an email has been sent or not)
|
||||
* Do not display current project in board selector
|
||||
* Do not set default task assignee for team projects
|
||||
|
|
|
|||
|
|
@ -32,6 +32,13 @@ class ProjectProcedure extends BaseProcedure
|
|||
return $this->formatProject($project);
|
||||
}
|
||||
|
||||
public function getProjectByEmail($email)
|
||||
{
|
||||
$project = $this->formatProject($this->projectModel->getByEmail($email));
|
||||
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getProjectByEmail', $project['id']);
|
||||
return $this->formatProject($project);
|
||||
}
|
||||
|
||||
public function getAllProjects()
|
||||
{
|
||||
return $this->formatProjects($this->projectModel->getAll());
|
||||
|
|
|
|||
|
|
@ -12,6 +12,11 @@ use Kanboard\Core\Base;
|
|||
*/
|
||||
class AppHelper extends Base
|
||||
{
|
||||
public function isAjax()
|
||||
{
|
||||
return $this->request->isAjax();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render Javascript component
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1311,4 +1311,6 @@ return array(
|
|||
// 'Your profile must have a valid email address.' => '',
|
||||
// 'Unfortunately, we are unable to reset your password. Did you entered a valid username? Do you have an email address in your profile?' => '',
|
||||
// 'TRL - Turkish Lira' => '',
|
||||
// 'The project email is optional and could be used by several plugins.' => '',
|
||||
// 'The email project must be unique across all projects' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1311,4 +1311,6 @@ return array(
|
|||
// 'Your profile must have a valid email address.' => '',
|
||||
// 'Unfortunately, we are unable to reset your password. Did you entered a valid username? Do you have an email address in your profile?' => '',
|
||||
// 'TRL - Turkish Lira' => '',
|
||||
// 'The project email is optional and could be used by several plugins.' => '',
|
||||
// 'The email project must be unique across all projects' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1311,4 +1311,6 @@ return array(
|
|||
// 'Your profile must have a valid email address.' => '',
|
||||
// 'Unfortunately, we are unable to reset your password. Did you entered a valid username? Do you have an email address in your profile?' => '',
|
||||
// 'TRL - Turkish Lira' => '',
|
||||
// 'The project email is optional and could be used by several plugins.' => '',
|
||||
// 'The email project must be unique across all projects' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1311,4 +1311,6 @@ return array(
|
|||
// 'Your profile must have a valid email address.' => '',
|
||||
// 'Unfortunately, we are unable to reset your password. Did you entered a valid username? Do you have an email address in your profile?' => '',
|
||||
// 'TRL - Turkish Lira' => '',
|
||||
// 'The project email is optional and could be used by several plugins.' => '',
|
||||
// 'The email project must be unique across all projects' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1311,4 +1311,6 @@ return array(
|
|||
// 'Your profile must have a valid email address.' => '',
|
||||
// 'Unfortunately, we are unable to reset your password. Did you entered a valid username? Do you have an email address in your profile?' => '',
|
||||
// 'TRL - Turkish Lira' => '',
|
||||
// 'The project email is optional and could be used by several plugins.' => '',
|
||||
// 'The email project must be unique across all projects' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1311,4 +1311,6 @@ return array(
|
|||
// 'Your profile must have a valid email address.' => '',
|
||||
// 'Unfortunately, we are unable to reset your password. Did you entered a valid username? Do you have an email address in your profile?' => '',
|
||||
// 'TRL - Turkish Lira' => '',
|
||||
// 'The project email is optional and could be used by several plugins.' => '',
|
||||
// 'The email project must be unique across all projects' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1311,4 +1311,6 @@ return array(
|
|||
// 'Your profile must have a valid email address.' => '',
|
||||
// 'Unfortunately, we are unable to reset your password. Did you entered a valid username? Do you have an email address in your profile?' => '',
|
||||
// 'TRL - Turkish Lira' => '',
|
||||
// 'The project email is optional and could be used by several plugins.' => '',
|
||||
// 'The email project must be unique across all projects' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -961,7 +961,7 @@ return array(
|
|||
'Do you really want to close all tasks of this column?' => 'Voulez-vous vraiment fermer toutes les tâches de cette colonne ?',
|
||||
'%d task(s) in the column "%s" and the swimlane "%s" will be closed.' => '%d tâche(s) dans la colonne « %s » et la swimlane « %s » seront fermées.',
|
||||
'Close all tasks of this column' => 'Fermer toutes les tâches de cette colonne',
|
||||
'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.',
|
||||
'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 utilisateur.',
|
||||
'My dashboard' => 'Mon tableau de bord',
|
||||
'My profile' => 'Mon profil',
|
||||
'Project owner: ' => 'Responsable du projet : ',
|
||||
|
|
@ -1311,4 +1311,6 @@ return array(
|
|||
'Your profile must have a valid email address.' => 'Votre profil doit avoir une adresse e-mail valide.',
|
||||
'Unfortunately, we are unable to reset your password. Did you entered a valid username? Do you have an email address in your profile?' => 'Malheureusement, nous ne pouvons pas réinitialiser votre mot de passe. Avez-vous saisi un nom d\'utilisateur valide ? Avez-vous une adresse e-mail dans votre profil ?',
|
||||
'TRL - Turkish Lira' => 'TRL - Livre turque',
|
||||
'The project email is optional and could be used by several plugins.' => 'L\'adresse email d\'un projet est optionnel et pourrait être utilisé par plusieurs extensions.',
|
||||
'The email project must be unique across all projects' => 'L\'adresse email d\'un projet doit être unique pour tous les projets',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1311,4 +1311,6 @@ return array(
|
|||
// 'Your profile must have a valid email address.' => '',
|
||||
// 'Unfortunately, we are unable to reset your password. Did you entered a valid username? Do you have an email address in your profile?' => '',
|
||||
// 'TRL - Turkish Lira' => '',
|
||||
// 'The project email is optional and could be used by several plugins.' => '',
|
||||
// 'The email project must be unique across all projects' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1311,4 +1311,6 @@ return array(
|
|||
// 'Your profile must have a valid email address.' => '',
|
||||
// 'Unfortunately, we are unable to reset your password. Did you entered a valid username? Do you have an email address in your profile?' => '',
|
||||
// 'TRL - Turkish Lira' => '',
|
||||
// 'The project email is optional and could be used by several plugins.' => '',
|
||||
// 'The email project must be unique across all projects' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1311,4 +1311,6 @@ return array(
|
|||
// 'Your profile must have a valid email address.' => '',
|
||||
// 'Unfortunately, we are unable to reset your password. Did you entered a valid username? Do you have an email address in your profile?' => '',
|
||||
// 'TRL - Turkish Lira' => '',
|
||||
// 'The project email is optional and could be used by several plugins.' => '',
|
||||
// 'The email project must be unique across all projects' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1311,4 +1311,6 @@ return array(
|
|||
// 'Your profile must have a valid email address.' => '',
|
||||
// 'Unfortunately, we are unable to reset your password. Did you entered a valid username? Do you have an email address in your profile?' => '',
|
||||
// 'TRL - Turkish Lira' => '',
|
||||
// 'The project email is optional and could be used by several plugins.' => '',
|
||||
// 'The email project must be unique across all projects' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1311,4 +1311,6 @@ return array(
|
|||
// 'Your profile must have a valid email address.' => '',
|
||||
// 'Unfortunately, we are unable to reset your password. Did you entered a valid username? Do you have an email address in your profile?' => '',
|
||||
// 'TRL - Turkish Lira' => '',
|
||||
// 'The project email is optional and could be used by several plugins.' => '',
|
||||
// 'The email project must be unique across all projects' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1311,4 +1311,6 @@ return array(
|
|||
// 'Your profile must have a valid email address.' => '',
|
||||
// 'Unfortunately, we are unable to reset your password. Did you entered a valid username? Do you have an email address in your profile?' => '',
|
||||
// 'TRL - Turkish Lira' => '',
|
||||
// 'The project email is optional and could be used by several plugins.' => '',
|
||||
// 'The email project must be unique across all projects' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1311,4 +1311,6 @@ return array(
|
|||
// 'Your profile must have a valid email address.' => '',
|
||||
// 'Unfortunately, we are unable to reset your password. Did you entered a valid username? Do you have an email address in your profile?' => '',
|
||||
// 'TRL - Turkish Lira' => '',
|
||||
// 'The project email is optional and could be used by several plugins.' => '',
|
||||
// 'The email project must be unique across all projects' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1311,4 +1311,6 @@ return array(
|
|||
// 'Your profile must have a valid email address.' => '',
|
||||
// 'Unfortunately, we are unable to reset your password. Did you entered a valid username? Do you have an email address in your profile?' => '',
|
||||
// 'TRL - Turkish Lira' => '',
|
||||
// 'The project email is optional and could be used by several plugins.' => '',
|
||||
// 'The email project must be unique across all projects' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1311,4 +1311,6 @@ return array(
|
|||
// 'Your profile must have a valid email address.' => '',
|
||||
// 'Unfortunately, we are unable to reset your password. Did you entered a valid username? Do you have an email address in your profile?' => '',
|
||||
// 'TRL - Turkish Lira' => '',
|
||||
// 'The project email is optional and could be used by several plugins.' => '',
|
||||
// 'The email project must be unique across all projects' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1311,4 +1311,6 @@ return array(
|
|||
// 'Your profile must have a valid email address.' => '',
|
||||
// 'Unfortunately, we are unable to reset your password. Did you entered a valid username? Do you have an email address in your profile?' => '',
|
||||
// 'TRL - Turkish Lira' => '',
|
||||
// 'The project email is optional and could be used by several plugins.' => '',
|
||||
// 'The email project must be unique across all projects' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1311,4 +1311,6 @@ return array(
|
|||
'Your profile must have a valid email address.' => 'O seu perfil deve ter um endereço de email válido.',
|
||||
'Unfortunately, we are unable to reset your password. Did you entered a valid username? Do you have an email address in your profile?' => 'Infelizmente, não conseguimos redefinir a sua password. Colocou um utilizador válido? Tem um endereço de email definido no seu perfil?',
|
||||
'TRL - Turkish Lira' => 'TRL - Lira Turca',
|
||||
// 'The project email is optional and could be used by several plugins.' => '',
|
||||
// 'The email project must be unique across all projects' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1311,4 +1311,6 @@ return array(
|
|||
// 'Your profile must have a valid email address.' => '',
|
||||
// 'Unfortunately, we are unable to reset your password. Did you entered a valid username? Do you have an email address in your profile?' => '',
|
||||
// 'TRL - Turkish Lira' => '',
|
||||
// 'The project email is optional and could be used by several plugins.' => '',
|
||||
// 'The email project must be unique across all projects' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1311,4 +1311,6 @@ return array(
|
|||
// 'Your profile must have a valid email address.' => '',
|
||||
// 'Unfortunately, we are unable to reset your password. Did you entered a valid username? Do you have an email address in your profile?' => '',
|
||||
// 'TRL - Turkish Lira' => '',
|
||||
// 'The project email is optional and could be used by several plugins.' => '',
|
||||
// 'The email project must be unique across all projects' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1311,4 +1311,6 @@ return array(
|
|||
// 'Your profile must have a valid email address.' => '',
|
||||
// 'Unfortunately, we are unable to reset your password. Did you entered a valid username? Do you have an email address in your profile?' => '',
|
||||
// 'TRL - Turkish Lira' => '',
|
||||
// 'The project email is optional and could be used by several plugins.' => '',
|
||||
// 'The email project must be unique across all projects' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1311,4 +1311,6 @@ return array(
|
|||
// 'Your profile must have a valid email address.' => '',
|
||||
// 'Unfortunately, we are unable to reset your password. Did you entered a valid username? Do you have an email address in your profile?' => '',
|
||||
// 'TRL - Turkish Lira' => '',
|
||||
// 'The project email is optional and could be used by several plugins.' => '',
|
||||
// 'The email project must be unique across all projects' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1311,4 +1311,6 @@ return array(
|
|||
// 'Your profile must have a valid email address.' => '',
|
||||
// 'Unfortunately, we are unable to reset your password. Did you entered a valid username? Do you have an email address in your profile?' => '',
|
||||
// 'TRL - Turkish Lira' => '',
|
||||
// 'The project email is optional and could be used by several plugins.' => '',
|
||||
// 'The email project must be unique across all projects' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1311,4 +1311,6 @@ return array(
|
|||
// 'Your profile must have a valid email address.' => '',
|
||||
// 'Unfortunately, we are unable to reset your password. Did you entered a valid username? Do you have an email address in your profile?' => '',
|
||||
// 'TRL - Turkish Lira' => '',
|
||||
// 'The project email is optional and could be used by several plugins.' => '',
|
||||
// 'The email project must be unique across all projects' => '',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -105,6 +105,22 @@ class ProjectModel extends Base
|
|||
return $this->db->table(self::TABLE)->eq('identifier', strtoupper($identifier))->findOne();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a project by the email address
|
||||
*
|
||||
* @access public
|
||||
* @param string $email
|
||||
* @return array|boolean
|
||||
*/
|
||||
public function getByEmail($email)
|
||||
{
|
||||
if (empty($email)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->db->table(self::TABLE)->eq('email', $email)->findOne();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch project data by using the token
|
||||
*
|
||||
|
|
|
|||
|
|
@ -6,7 +6,12 @@ use PDO;
|
|||
use Kanboard\Core\Security\Token;
|
||||
use Kanboard\Core\Security\Role;
|
||||
|
||||
const VERSION = 120;
|
||||
const VERSION = 121;
|
||||
|
||||
function version_121(PDO $pdo)
|
||||
{
|
||||
$pdo->exec('ALTER TABLE projects ADD COLUMN email VARCHAR(255)');
|
||||
}
|
||||
|
||||
function version_120(PDO $pdo)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,7 +6,12 @@ use PDO;
|
|||
use Kanboard\Core\Security\Token;
|
||||
use Kanboard\Core\Security\Role;
|
||||
|
||||
const VERSION = 99;
|
||||
const VERSION = 100;
|
||||
|
||||
function version_100(PDO $pdo)
|
||||
{
|
||||
$pdo->exec('ALTER TABLE "projects" ADD COLUMN email VARCHAR(255)');
|
||||
}
|
||||
|
||||
function version_99(PDO $pdo)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,7 +6,12 @@ use Kanboard\Core\Security\Token;
|
|||
use Kanboard\Core\Security\Role;
|
||||
use PDO;
|
||||
|
||||
const VERSION = 110;
|
||||
const VERSION = 111;
|
||||
|
||||
function version_111(PDO $pdo)
|
||||
{
|
||||
$pdo->exec('ALTER TABLE "projects" ADD COLUMN email TEXT');
|
||||
}
|
||||
|
||||
function version_110(PDO $pdo)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,12 @@
|
|||
<div class="page-header">
|
||||
<h2><?= $this->text->e($project['name']) ?> > <?= t('Edit project') ?></h2>
|
||||
</div>
|
||||
<?php if ($this->app->isAjax()): ?>
|
||||
<div class="page-header">
|
||||
<h2><?= $this->text->e($project['name']) ?> > <?= t('Edit project') ?></h2>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="page-header">
|
||||
<h2><?= t('Edit project') ?></h2>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<form method="post" action="<?= $this->url->href('ProjectEditController', 'update', array('project_id' => $project['id'], 'redirect' => 'edit')) ?>" autocomplete="off">
|
||||
<?= $this->form->csrf() ?>
|
||||
<?= $this->form->hidden('id', $values) ?>
|
||||
|
|
@ -11,12 +17,16 @@
|
|||
<?= $this->form->label(t('Name'), 'name') ?>
|
||||
<?= $this->form->text('name', $values, $errors, array('required', 'maxlength="50"', 'autofocus', 'tabindex="1"')) ?>
|
||||
|
||||
<?= $this->form->label(t('Email'), 'email') ?>
|
||||
<?= $this->form->email('email', $values, $errors, array('maxlength="255"', 'tabindex="2"')) ?>
|
||||
<p class="form-help"><?= t('The project email is optional and could be used by several plugins.') ?></p>
|
||||
|
||||
<?= $this->form->label(t('Identifier'), 'identifier') ?>
|
||||
<?= $this->form->text('identifier', $values, $errors, array('maxlength="50"', 'tabindex="2"')) ?>
|
||||
<?= $this->form->text('identifier', $values, $errors, array('maxlength="50"', 'tabindex="3"')) ?>
|
||||
<p class="form-help"><?= t('The project identifier is optional and must be alphanumeric, example: MYPROJECT.') ?></p>
|
||||
|
||||
<?= $this->form->label(t('Description'), 'description') ?>
|
||||
<?= $this->form->textEditor('description', $values, $errors, array('tabindex' => 3)) ?>
|
||||
<?= $this->form->textEditor('description', $values, $errors, array('tabindex' => 4)) ?>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ class ProjectValidator extends BaseValidator
|
|||
new Validators\MaxLength('end_date', t('The maximum length is %d characters', 10), 10),
|
||||
new Validators\AlphaNumeric('identifier', t('This value must be alphanumeric')) ,
|
||||
new Validators\Unique('identifier', t('The identifier must be unique'), $this->db->getConnection(), ProjectModel::TABLE),
|
||||
new Validators\Email('email', t('Email address invalid')) ,
|
||||
new Validators\Unique('email', t('The email project must be unique across all projects'), $this->db->getConnection(), ProjectModel::TABLE),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -182,6 +182,56 @@ Response example:
|
|||
}
|
||||
```
|
||||
|
||||
## getProjectByEmail
|
||||
|
||||
- Purpose: **Get project information**
|
||||
- Parameters:
|
||||
- **email** (string, required)
|
||||
- Result on success: **project properties**
|
||||
- Result on failure: **null**
|
||||
|
||||
Request example:
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "getProjectByEmail",
|
||||
"id": 1620253806,
|
||||
"params": {
|
||||
"email": "my_project@my_domain.tld"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Response example:
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1620253806,
|
||||
"result": {
|
||||
"id": "1",
|
||||
"name": "Test",
|
||||
"is_active": "1",
|
||||
"token": "",
|
||||
"last_modified": "1436119135",
|
||||
"is_public": "0",
|
||||
"is_private": "0",
|
||||
"is_everybody_allowed": "0",
|
||||
"default_swimlane": "Default swimlane",
|
||||
"show_default_swimlane": "1",
|
||||
"description": "test",
|
||||
"identifier": "",
|
||||
"email": "my_project@my_domain.tld",
|
||||
"url": {
|
||||
"board": "http:\/\/127.0.0.1:8000\/?controller=board&action=show&project_id=1",
|
||||
"calendar": "http:\/\/127.0.0.1:8000\/?controller=calendar&action=show&project_id=1",
|
||||
"list": "http:\/\/127.0.0.1:8000\/?controller=listing&action=show&project_id=1"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## getAllProjects
|
||||
|
||||
- Purpose: **Get all available projects**
|
||||
|
|
|
|||
|
|
@ -298,6 +298,39 @@ class ProjectModelTest extends Base
|
|||
$this->assertFalse($project);
|
||||
}
|
||||
|
||||
public function testEmail()
|
||||
{
|
||||
$projectModel = new ProjectModel($this->container);
|
||||
|
||||
// Creation
|
||||
$this->assertEquals(1, $projectModel->create(array('name' => 'UnitTest1', 'email' => 'test1@localhost')));
|
||||
$this->assertEquals(2, $projectModel->create(array('name' => 'UnitTest2')));
|
||||
|
||||
$project = $projectModel->getById(1);
|
||||
$this->assertNotEmpty($project);
|
||||
$this->assertEquals('test1@localhost', $project['email']);
|
||||
|
||||
$project = $projectModel->getById(2);
|
||||
$this->assertNotEmpty($project);
|
||||
$this->assertEquals('', $project['email']);
|
||||
|
||||
// Update
|
||||
$this->assertTrue($projectModel->update(array('id' => '1', 'email' => 'test1@here')));
|
||||
|
||||
$project = $projectModel->getById(1);
|
||||
$this->assertNotEmpty($project);
|
||||
$this->assertEquals('test1@here', $project['email']);
|
||||
|
||||
$project = $projectModel->getByEmail('test1@here');
|
||||
$this->assertEquals(1, $project['id']);
|
||||
|
||||
$project = $projectModel->getByEmail('test1@localhost');
|
||||
$this->assertEmpty($project);
|
||||
|
||||
$project = $projectModel->getByEmail('');
|
||||
$this->assertFalse($project);
|
||||
}
|
||||
|
||||
public function testThatProjectCreatorAreAlsoOwner()
|
||||
{
|
||||
$projectModel = new ProjectModel($this->container);
|
||||
|
|
|
|||
Loading…
Reference in New Issue