Add the possibility to send tasks and comments to multiple recipients

This commit is contained in:
Frederic Guillot 2017-11-17 14:46:23 -08:00
parent 3b786e05e0
commit 2a313eb971
44 changed files with 84 additions and 85 deletions

View File

@ -9,6 +9,7 @@ Breaking changes:
New features: New features:
* Add predefined templates for task descriptions * Add predefined templates for task descriptions
* Add the possibility to send tasks and comments to multiple recipients
* Add users, groups and projects search * Add users, groups and projects search
* Add command line argument to display Kanboard version * Add command line argument to display Kanboard version
* Add user backend provider system (to be used by external plugins) * Add user backend provider system (to be used by external plugins)
@ -16,7 +17,6 @@ New features:
Improvements: Improvements:
* Improve docs
* Minor CSS improvements * Minor CSS improvements
* Add help message on project sharing page * Add help message on project sharing page
* Task CSV import is now able to handle the priority, start date, tags and one external link * Task CSV import is now able to handle the priority, start date, tags and one external link

View File

@ -51,24 +51,25 @@ class CommentMailController extends BaseController
protected function sendByEmail(array $values) protected function sendByEmail(array $values)
{ {
$html = $this->template->render('comment_mail/email', array( $html = $this->template->render('comment_mail/email', array('email' => $values));
'email' => $values, $emails = explode_csv_field($values['emails']);
));
$this->emailClient->send( foreach ($emails as $email) {
$values['email'], $this->emailClient->send(
$values['email'], $email,
$values['subject'], $email,
$html $values['subject'],
); $html
);
}
} }
protected function prepareComment(array $values) protected function prepareComment(array $values)
{ {
$values['comment'] .= "\n\n_".t('Sent by email to [%s](mailto:%s) (%s)', $values['email'], $values['email'], $values['subject']).'_'; $values['comment'] .= "\n\n_".t('Sent by email to "%s" (%s)', $values['emails'], $values['subject']).'_';
unset($values['subject']); unset($values['subject']);
unset($values['email']); unset($values['emails']);
return $values; return $values;
} }

View File

@ -36,7 +36,7 @@ class TaskMailController extends BaseController
$this->flash->success(t('Task sent by email successfully.')); $this->flash->success(t('Task sent by email successfully.'));
$this->commentModel->create(array( $this->commentModel->create(array(
'comment' => t('This task was sent by email to "%s" with subject "%s".', $values['email'], $values['subject']), 'comment' => t('This task was sent by email to "%s" with subject "%s".', $values['emails'], $values['subject']),
'user_id' => $this->userSession->getId(), 'user_id' => $this->userSession->getId(),
'task_id' => $task['id'], 'task_id' => $task['id'],
)); ));
@ -49,15 +49,16 @@ class TaskMailController extends BaseController
protected function sendByEmail(array $values, array $task) protected function sendByEmail(array $values, array $task)
{ {
$html = $this->template->render('task_mail/email', array( $emails = explode_csv_field($values['emails']);
'task' => $task, $html = $this->template->render('task_mail/email', array('task' => $task));
));
$this->emailClient->send( foreach ($emails as $email) {
$values['email'], $this->emailClient->send(
$values['email'], $email,
$values['subject'], $email,
$html $values['subject'],
); $html
);
}
} }
} }

View File

@ -67,9 +67,7 @@ class TaskImport extends Base
$this->nbImportedTasks++; $this->nbImportedTasks++;
if (! empty($row['tags'])) { if (! empty($row['tags'])) {
$tagsList = explode(',', $row['tags']); $this->taskTagModel->save($this->projectId, $taskId, explode_csv_field($row['tags']));
array_walk($tagsList, function (&$value) { $value = trim($value); });
$this->taskTagModel->save($this->projectId, $taskId, $tagsList);
} }
if (! empty($row['external_link'])) { if (! empty($row['external_link'])) {

View File

@ -1266,7 +1266,7 @@ return array(
'Unable to upload files, check the permissions of your data folder.' => 'Nemoguće priložiti datoteke, provjeri prava na "data" direktoriju na serveru.', 'Unable to upload files, check the permissions of your data folder.' => 'Nemoguće priložiti datoteke, provjeri prava na "data" direktoriju na serveru.',
'Another category with the same name exists in this project' => 'Kategorija sa ovim imenom već postoji na ovom projektu', 'Another category with the same name exists in this project' => 'Kategorija sa ovim imenom već postoji na ovom projektu',
'Comment sent by email successfully.' => 'Komentar je uspješno poslan email-om.', 'Comment sent by email successfully.' => 'Komentar je uspješno poslan email-om.',
'Sent by email to [%s](mailto:%s) (%s)' => 'Pošalji email-om [%s](mailto:%s) (%s)', 'Sent by email to "%s" (%s)' => 'Pošalji email-om "%s" (%s)',
'Unable to read uploaded file.' => 'Nemoguće pročitati dodanu datoteku.', 'Unable to read uploaded file.' => 'Nemoguće pročitati dodanu datoteku.',
'Database uploaded successfully.' => 'Baza podataka je uspješno dodana.', 'Database uploaded successfully.' => 'Baza podataka je uspješno dodana.',
'Task sent by email successfully.' => 'Zadatak je uspješno poslan email-om.', 'Task sent by email successfully.' => 'Zadatak je uspješno poslan email-om.',

View File

@ -1266,7 +1266,7 @@ return array(
'Unable to upload files, check the permissions of your data folder.' => 'No es pot pujar arxius, comprovar els permisos de la carpeta de dades.', 'Unable to upload files, check the permissions of your data folder.' => 'No es pot pujar arxius, comprovar els permisos de la carpeta de dades.',
'Another category with the same name exists in this project' => 'Una altra categoria amb el mateix nom existeix en aquest projecte', 'Another category with the same name exists in this project' => 'Una altra categoria amb el mateix nom existeix en aquest projecte',
'Comment sent by email successfully.' => 'Comentar enviat per correu electrònic amb èxit.', 'Comment sent by email successfully.' => 'Comentar enviat per correu electrònic amb èxit.',
// 'Sent by email to [%s](mailto:%s) (%s)' => '', // 'Sent by email to "%s" (%s)' => '',
'Unable to read uploaded file.' => 'No es pot llegir el fitxer pujat.', 'Unable to read uploaded file.' => 'No es pot llegir el fitxer pujat.',
'Database uploaded successfully.' => 'Base de dades carregat correctament.', 'Database uploaded successfully.' => 'Base de dades carregat correctament.',
'Task sent by email successfully.' => 'Tasca enviat per correu electrònic amb èxit.', 'Task sent by email successfully.' => 'Tasca enviat per correu electrònic amb èxit.',

View File

@ -1266,7 +1266,7 @@ return array(
// 'Unable to upload files, check the permissions of your data folder.' => '', // 'Unable to upload files, check the permissions of your data folder.' => '',
// 'Another category with the same name exists in this project' => '', // 'Another category with the same name exists in this project' => '',
// 'Comment sent by email successfully.' => '', // 'Comment sent by email successfully.' => '',
// 'Sent by email to [%s](mailto:%s) (%s)' => '', // 'Sent by email to "%s" (%s)' => '',
// 'Unable to read uploaded file.' => '', // 'Unable to read uploaded file.' => '',
// 'Database uploaded successfully.' => '', // 'Database uploaded successfully.' => '',
// 'Task sent by email successfully.' => '', // 'Task sent by email successfully.' => '',

View File

@ -1266,7 +1266,7 @@ return array(
// 'Unable to upload files, check the permissions of your data folder.' => '', // 'Unable to upload files, check the permissions of your data folder.' => '',
// 'Another category with the same name exists in this project' => '', // 'Another category with the same name exists in this project' => '',
// 'Comment sent by email successfully.' => '', // 'Comment sent by email successfully.' => '',
// 'Sent by email to [%s](mailto:%s) (%s)' => '', // 'Sent by email to "%s" (%s)' => '',
// 'Unable to read uploaded file.' => '', // 'Unable to read uploaded file.' => '',
// 'Database uploaded successfully.' => '', // 'Database uploaded successfully.' => '',
// 'Task sent by email successfully.' => '', // 'Task sent by email successfully.' => '',

View File

@ -1266,7 +1266,7 @@ return array(
'Unable to upload files, check the permissions of your data folder.' => 'Dateien können nicht hochgeladen werden, überprüfen Sie die Berechtigungen Ihres Datenordners.', 'Unable to upload files, check the permissions of your data folder.' => 'Dateien können nicht hochgeladen werden, überprüfen Sie die Berechtigungen Ihres Datenordners.',
'Another category with the same name exists in this project' => 'Eine weitere Kategorie mit demselben Namen existiert in diesem Projekt', 'Another category with the same name exists in this project' => 'Eine weitere Kategorie mit demselben Namen existiert in diesem Projekt',
'Comment sent by email successfully.' => 'Kommentar wurde erfolgreich per E-Mail gesendet.', 'Comment sent by email successfully.' => 'Kommentar wurde erfolgreich per E-Mail gesendet.',
'Sent by email to [%s](mailto:%s) (%s)' => 'Wurde per E-Mail an [%s] gesendet (mailto:%s) (%s)', 'Sent by email to "%s" (%s)' => 'Wurde per E-Mail an [%s] gesendet "%s"',
'Unable to read uploaded file.' => 'Die hochgeladene Datei konnte nicht gelesen werden.', 'Unable to read uploaded file.' => 'Die hochgeladene Datei konnte nicht gelesen werden.',
'Database uploaded successfully.' => 'Die Datenbank wurde erfolgreich hochgeladen.', 'Database uploaded successfully.' => 'Die Datenbank wurde erfolgreich hochgeladen.',
'Task sent by email successfully.' => 'Aufgabe wurde erfolgreich per E-Mail gesendet.', 'Task sent by email successfully.' => 'Aufgabe wurde erfolgreich per E-Mail gesendet.',

View File

@ -1266,7 +1266,7 @@ return array(
// 'Unable to upload files, check the permissions of your data folder.' => '', // 'Unable to upload files, check the permissions of your data folder.' => '',
// 'Another category with the same name exists in this project' => '', // 'Another category with the same name exists in this project' => '',
// 'Comment sent by email successfully.' => '', // 'Comment sent by email successfully.' => '',
// 'Sent by email to [%s](mailto:%s) (%s)' => '', // 'Sent by email to "%s" (%s)' => '',
// 'Unable to read uploaded file.' => '', // 'Unable to read uploaded file.' => '',
// 'Database uploaded successfully.' => '', // 'Database uploaded successfully.' => '',
// 'Task sent by email successfully.' => '', // 'Task sent by email successfully.' => '',

View File

@ -1266,7 +1266,7 @@ return array(
'Unable to upload files, check the permissions of your data folder.' => 'No se pueden cargar archivos, verifique los permisos de su carpeta de datos (data)', 'Unable to upload files, check the permissions of your data folder.' => 'No se pueden cargar archivos, verifique los permisos de su carpeta de datos (data)',
'Another category with the same name exists in this project' => 'Ya existe otra categoría con el mismo nombre en este proyecto', 'Another category with the same name exists in this project' => 'Ya existe otra categoría con el mismo nombre en este proyecto',
'Comment sent by email successfully.' => 'Comentario enviado exitosamente por email', 'Comment sent by email successfully.' => 'Comentario enviado exitosamente por email',
'Sent by email to [%s](mailto:%s) (%s)' => 'Enviado por email a [%s](mailto:%s) (%s)', 'Sent by email to "%s" (%s)' => 'Enviado por email a "%s" (%s)',
'Unable to read uploaded file.' => 'No se pudo leer el archivo cargado', 'Unable to read uploaded file.' => 'No se pudo leer el archivo cargado',
'Database uploaded successfully.' => 'Base de datos cargada exitosamente', 'Database uploaded successfully.' => 'Base de datos cargada exitosamente',
'Task sent by email successfully.' => 'Tarea enviada exitosamente por email', 'Task sent by email successfully.' => 'Tarea enviada exitosamente por email',

View File

@ -1266,7 +1266,7 @@ return array(
// 'Unable to upload files, check the permissions of your data folder.' => '', // 'Unable to upload files, check the permissions of your data folder.' => '',
// 'Another category with the same name exists in this project' => '', // 'Another category with the same name exists in this project' => '',
// 'Comment sent by email successfully.' => '', // 'Comment sent by email successfully.' => '',
// 'Sent by email to [%s](mailto:%s) (%s)' => '', // 'Sent by email to "%s" (%s)' => '',
// 'Unable to read uploaded file.' => '', // 'Unable to read uploaded file.' => '',
// 'Database uploaded successfully.' => '', // 'Database uploaded successfully.' => '',
// 'Task sent by email successfully.' => '', // 'Task sent by email successfully.' => '',

View File

@ -1266,7 +1266,7 @@ return array(
'Unable to upload files, check the permissions of your data folder.' => 'Impossible de transférer le ou les fichiers, vérifiez les permissions du répertoire de données.', 'Unable to upload files, check the permissions of your data folder.' => 'Impossible de transférer le ou les fichiers, vérifiez les permissions du répertoire de données.',
'Another category with the same name exists in this project' => 'Une autre catégorie avec le même nom existe dans ce projet', 'Another category with the same name exists in this project' => 'Une autre catégorie avec le même nom existe dans ce projet',
'Comment sent by email successfully.' => 'Commentaire envoyé par email avec succès.', 'Comment sent by email successfully.' => 'Commentaire envoyé par email avec succès.',
'Sent by email to [%s](mailto:%s) (%s)' => 'Envoyé par email à [%s](mailto:%s) (%s)', 'Sent by email to "%s" (%s)' => 'Envoyé par email à « %s » (%s)',
'Unable to read uploaded file.' => 'Impossible de lire le fichier téléversé.', 'Unable to read uploaded file.' => 'Impossible de lire le fichier téléversé.',
'Database uploaded successfully.' => 'Base de données téléversée avec succès.', 'Database uploaded successfully.' => 'Base de données téléversée avec succès.',
'Task sent by email successfully.' => 'Tâche envoyée par email avec succès.', 'Task sent by email successfully.' => 'Tâche envoyée par email avec succès.',

View File

@ -1266,7 +1266,7 @@ return array(
// 'Unable to upload files, check the permissions of your data folder.' => '', // 'Unable to upload files, check the permissions of your data folder.' => '',
// 'Another category with the same name exists in this project' => '', // 'Another category with the same name exists in this project' => '',
// 'Comment sent by email successfully.' => '', // 'Comment sent by email successfully.' => '',
// 'Sent by email to [%s](mailto:%s) (%s)' => '', // 'Sent by email to "%s" (%s)' => '',
// 'Unable to read uploaded file.' => '', // 'Unable to read uploaded file.' => '',
// 'Database uploaded successfully.' => '', // 'Database uploaded successfully.' => '',
// 'Task sent by email successfully.' => '', // 'Task sent by email successfully.' => '',

View File

@ -1266,7 +1266,7 @@ return array(
'Unable to upload files, check the permissions of your data folder.' => 'Nem lehet feltölteni fájlokat. Ellenőrizze az adatkönyvtár jogosultságait.', 'Unable to upload files, check the permissions of your data folder.' => 'Nem lehet feltölteni fájlokat. Ellenőrizze az adatkönyvtár jogosultságait.',
'Another category with the same name exists in this project' => 'Már létezik egy ugyanilyen nevű kategória ebben a projektben', 'Another category with the same name exists in this project' => 'Már létezik egy ugyanilyen nevű kategória ebben a projektben',
'Comment sent by email successfully.' => 'A megjegyzés sikeresen elküldve e-mailben.', 'Comment sent by email successfully.' => 'A megjegyzés sikeresen elküldve e-mailben.',
'Sent by email to [%s](mailto:%s) (%s)' => 'E-mail küldve neki: [%s](mailto:%s) (%s)', 'Sent by email to "%s" (%s)' => 'E-mail küldve neki: "%s" (%s)',
'Unable to read uploaded file.' => 'Nem lehet beolvasni a feltöltött fájlt.', 'Unable to read uploaded file.' => 'Nem lehet beolvasni a feltöltött fájlt.',
'Database uploaded successfully.' => 'Az adatbázis sikeresen feltöltve.', 'Database uploaded successfully.' => 'Az adatbázis sikeresen feltöltve.',
'Task sent by email successfully.' => 'A feladat sikeresen elküldve e-mailben.', 'Task sent by email successfully.' => 'A feladat sikeresen elküldve e-mailben.',

View File

@ -1266,7 +1266,7 @@ return array(
// 'Unable to upload files, check the permissions of your data folder.' => '', // 'Unable to upload files, check the permissions of your data folder.' => '',
// 'Another category with the same name exists in this project' => '', // 'Another category with the same name exists in this project' => '',
// 'Comment sent by email successfully.' => '', // 'Comment sent by email successfully.' => '',
// 'Sent by email to [%s](mailto:%s) (%s)' => '', // 'Sent by email to "%s" (%s)' => '',
// 'Unable to read uploaded file.' => '', // 'Unable to read uploaded file.' => '',
// 'Database uploaded successfully.' => '', // 'Database uploaded successfully.' => '',
// 'Task sent by email successfully.' => '', // 'Task sent by email successfully.' => '',

View File

@ -1266,7 +1266,7 @@ return array(
// 'Unable to upload files, check the permissions of your data folder.' => '', // 'Unable to upload files, check the permissions of your data folder.' => '',
// 'Another category with the same name exists in this project' => '', // 'Another category with the same name exists in this project' => '',
// 'Comment sent by email successfully.' => '', // 'Comment sent by email successfully.' => '',
// 'Sent by email to [%s](mailto:%s) (%s)' => '', // 'Sent by email to "%s" (%s)' => '',
// 'Unable to read uploaded file.' => '', // 'Unable to read uploaded file.' => '',
// 'Database uploaded successfully.' => '', // 'Database uploaded successfully.' => '',
// 'Task sent by email successfully.' => '', // 'Task sent by email successfully.' => '',

View File

@ -1266,7 +1266,7 @@ return array(
'Unable to upload files, check the permissions of your data folder.' => 'ファイルをアップロードできません。データフォルダのアクセス権を確認してください。', 'Unable to upload files, check the permissions of your data folder.' => 'ファイルをアップロードできません。データフォルダのアクセス権を確認してください。',
'Another category with the same name exists in this project' => '同じ名前の別のカテゴリがプロジェクトに存在します', 'Another category with the same name exists in this project' => '同じ名前の別のカテゴリがプロジェクトに存在します',
'Comment sent by email successfully.' => 'メールでコメントを送信しました', 'Comment sent by email successfully.' => 'メールでコメントを送信しました',
'Sent by email to [%s](mailto:%s) (%s)' => '%s をメールで送信しました(mailto:%s) (%s)', 'Sent by email to "%s" (%s)' => '%s をメールで送信しました "%s"',
'Unable to read uploaded file.' => 'アップロードされたファイルを読み込めません', 'Unable to read uploaded file.' => 'アップロードされたファイルを読み込めません',
'Database uploaded successfully.' => 'データベースをアップロードしました', 'Database uploaded successfully.' => 'データベースをアップロードしました',
'Task sent by email successfully.' => 'タスクをメールで送信しました', 'Task sent by email successfully.' => 'タスクをメールで送信しました',

View File

@ -1266,7 +1266,7 @@ return array(
// 'Unable to upload files, check the permissions of your data folder.' => '', // 'Unable to upload files, check the permissions of your data folder.' => '',
// 'Another category with the same name exists in this project' => '', // 'Another category with the same name exists in this project' => '',
// 'Comment sent by email successfully.' => '', // 'Comment sent by email successfully.' => '',
// 'Sent by email to [%s](mailto:%s) (%s)' => '', // 'Sent by email to "%s" (%s)' => '',
// 'Unable to read uploaded file.' => '', // 'Unable to read uploaded file.' => '',
// 'Database uploaded successfully.' => '', // 'Database uploaded successfully.' => '',
// 'Task sent by email successfully.' => '', // 'Task sent by email successfully.' => '',

View File

@ -1266,7 +1266,7 @@ return array(
// 'Unable to upload files, check the permissions of your data folder.' => '', // 'Unable to upload files, check the permissions of your data folder.' => '',
// 'Another category with the same name exists in this project' => '', // 'Another category with the same name exists in this project' => '',
// 'Comment sent by email successfully.' => '', // 'Comment sent by email successfully.' => '',
// 'Sent by email to [%s](mailto:%s) (%s)' => '', // 'Sent by email to "%s" (%s)' => '',
// 'Unable to read uploaded file.' => '', // 'Unable to read uploaded file.' => '',
// 'Database uploaded successfully.' => '', // 'Database uploaded successfully.' => '',
// 'Task sent by email successfully.' => '', // 'Task sent by email successfully.' => '',

View File

@ -1266,7 +1266,7 @@ return array(
// 'Unable to upload files, check the permissions of your data folder.' => '', // 'Unable to upload files, check the permissions of your data folder.' => '',
// 'Another category with the same name exists in this project' => '', // 'Another category with the same name exists in this project' => '',
// 'Comment sent by email successfully.' => '', // 'Comment sent by email successfully.' => '',
// 'Sent by email to [%s](mailto:%s) (%s)' => '', // 'Sent by email to "%s" (%s)' => '',
// 'Unable to read uploaded file.' => '', // 'Unable to read uploaded file.' => '',
// 'Database uploaded successfully.' => '', // 'Database uploaded successfully.' => '',
// 'Task sent by email successfully.' => '', // 'Task sent by email successfully.' => '',

View File

@ -1266,7 +1266,7 @@ return array(
// 'Unable to upload files, check the permissions of your data folder.' => '', // 'Unable to upload files, check the permissions of your data folder.' => '',
// 'Another category with the same name exists in this project' => '', // 'Another category with the same name exists in this project' => '',
// 'Comment sent by email successfully.' => '', // 'Comment sent by email successfully.' => '',
// 'Sent by email to [%s](mailto:%s) (%s)' => '', // 'Sent by email to "%s" (%s)' => '',
// 'Unable to read uploaded file.' => '', // 'Unable to read uploaded file.' => '',
// 'Database uploaded successfully.' => '', // 'Database uploaded successfully.' => '',
// 'Task sent by email successfully.' => '', // 'Task sent by email successfully.' => '',

View File

@ -1266,7 +1266,7 @@ return array(
// 'Unable to upload files, check the permissions of your data folder.' => '', // 'Unable to upload files, check the permissions of your data folder.' => '',
// 'Another category with the same name exists in this project' => '', // 'Another category with the same name exists in this project' => '',
// 'Comment sent by email successfully.' => '', // 'Comment sent by email successfully.' => '',
// 'Sent by email to [%s](mailto:%s) (%s)' => '', // 'Sent by email to "%s" (%s)' => '',
// 'Unable to read uploaded file.' => '', // 'Unable to read uploaded file.' => '',
// 'Database uploaded successfully.' => '', // 'Database uploaded successfully.' => '',
// 'Task sent by email successfully.' => '', // 'Task sent by email successfully.' => '',

View File

@ -1266,7 +1266,7 @@ return array(
'Unable to upload files, check the permissions of your data folder.' => 'Incapaz de enviar arquivos. Verifique as permissões da sua pasta de dados.', 'Unable to upload files, check the permissions of your data folder.' => 'Incapaz de enviar arquivos. Verifique as permissões da sua pasta de dados.',
'Another category with the same name exists in this project' => 'Outra categoria com o mesmo nome existe neste projeto', 'Another category with the same name exists in this project' => 'Outra categoria com o mesmo nome existe neste projeto',
'Comment sent by email successfully.' => 'Comentário enviado por e-mail com sucesso.', 'Comment sent by email successfully.' => 'Comentário enviado por e-mail com sucesso.',
'Sent by email to [%s](mailto:%s) (%s)' => 'Enviar por e-mail para [%s](mailto:%s) (%s)', 'Sent by email to "%s" (%s)' => 'Enviar por e-mail para "%s" (%s)',
'Unable to read uploaded file.' => 'Incapaz de ler arquivos enviados.', 'Unable to read uploaded file.' => 'Incapaz de ler arquivos enviados.',
'Database uploaded successfully.' => 'Base de dados enviado com sucesso.', 'Database uploaded successfully.' => 'Base de dados enviado com sucesso.',
'Task sent by email successfully.' => 'Tarefa enviada por e-mail com sucesso.', 'Task sent by email successfully.' => 'Tarefa enviada por e-mail com sucesso.',

View File

@ -1266,7 +1266,7 @@ return array(
'Unable to upload files, check the permissions of your data folder.' => 'Impossivel enviar ficheiros, verifique as permissões da pasta data', 'Unable to upload files, check the permissions of your data folder.' => 'Impossivel enviar ficheiros, verifique as permissões da pasta data',
'Another category with the same name exists in this project' => 'Outra categoria com o mesmo nome já existe neste projecto', 'Another category with the same name exists in this project' => 'Outra categoria com o mesmo nome já existe neste projecto',
'Comment sent by email successfully.' => 'Comentário enviado por email com sucesso.', 'Comment sent by email successfully.' => 'Comentário enviado por email com sucesso.',
'Sent by email to [%s](mailto:%s) (%s)' => 'Enviado por email para [%s](mailto:%s) (%s)', 'Sent by email to "%s" (%s)' => 'Enviado por email para "%s" (%s)',
'Unable to read uploaded file.' => 'Não foi possivel ler ficheiro enviado.', 'Unable to read uploaded file.' => 'Não foi possivel ler ficheiro enviado.',
'Database uploaded successfully.' => 'Base de dados enviada com sucesso.', 'Database uploaded successfully.' => 'Base de dados enviada com sucesso.',
'Task sent by email successfully.' => 'Tarefa enviada por email com sucesso.', 'Task sent by email successfully.' => 'Tarefa enviada por email com sucesso.',

View File

@ -1266,7 +1266,7 @@ return array(
'Unable to upload files, check the permissions of your data folder.' => 'Nu am putut încărca fișierele, verifică permisiunile directorului de date.', 'Unable to upload files, check the permissions of your data folder.' => 'Nu am putut încărca fișierele, verifică permisiunile directorului de date.',
'Another category with the same name exists in this project' => 'Altă categorie cu același nume există deja în proiect', 'Another category with the same name exists in this project' => 'Altă categorie cu același nume există deja în proiect',
'Comment sent by email successfully.' => 'Comentariul a fost trimis prin e-mail.', 'Comment sent by email successfully.' => 'Comentariul a fost trimis prin e-mail.',
'Sent by email to [%s](mailto:%s) (%s)' => 'Trimite prin e-mail la [%s](mailto:%s) (%s)', 'Sent by email to "%s" (%s)' => 'Trimite prin e-mail la "%s" (%s)',
'Unable to read uploaded file.' => 'Nu pot citi fișierul încărcat.', 'Unable to read uploaded file.' => 'Nu pot citi fișierul încărcat.',
'Database uploaded successfully.' => 'Baza de date a fost încărcată cu succes.', 'Database uploaded successfully.' => 'Baza de date a fost încărcată cu succes.',
'Task sent by email successfully.' => 'Sarcina a fost trimisă prin e-mail.', 'Task sent by email successfully.' => 'Sarcina a fost trimisă prin e-mail.',

View File

@ -1266,7 +1266,7 @@ return array(
'Unable to upload files, check the permissions of your data folder.' => 'Невозможно загрузить файлы, проверьте права доступа на папку "data".', 'Unable to upload files, check the permissions of your data folder.' => 'Невозможно загрузить файлы, проверьте права доступа на папку "data".',
'Another category with the same name exists in this project' => 'Другая категория с таким же именем уже существует в этом проекте', 'Another category with the same name exists in this project' => 'Другая категория с таким же именем уже существует в этом проекте',
'Comment sent by email successfully.' => 'Комментарий успешно отправлен по e-mail.', 'Comment sent by email successfully.' => 'Комментарий успешно отправлен по e-mail.',
'Sent by email to [%s](mailto:%s) (%s)' => 'Отправлен по e-mail для [%s](mailto:%s) (%s)', 'Sent by email to "%s" (%s)' => 'Отправлен по e-mail для "%s" (%s)',
'Unable to read uploaded file.' => 'Не удаётся прочитать загруженный файл.', 'Unable to read uploaded file.' => 'Не удаётся прочитать загруженный файл.',
'Database uploaded successfully.' => 'База данных успешно импортирована.', 'Database uploaded successfully.' => 'База данных успешно импортирована.',
'Task sent by email successfully.' => 'Задача успешно отправлена по e-mail.', 'Task sent by email successfully.' => 'Задача успешно отправлена по e-mail.',

View File

@ -1266,7 +1266,7 @@ return array(
// 'Unable to upload files, check the permissions of your data folder.' => '', // 'Unable to upload files, check the permissions of your data folder.' => '',
// 'Another category with the same name exists in this project' => '', // 'Another category with the same name exists in this project' => '',
// 'Comment sent by email successfully.' => '', // 'Comment sent by email successfully.' => '',
// 'Sent by email to [%s](mailto:%s) (%s)' => '', // 'Sent by email to "%s" (%s)' => '',
// 'Unable to read uploaded file.' => '', // 'Unable to read uploaded file.' => '',
// 'Database uploaded successfully.' => '', // 'Database uploaded successfully.' => '',
// 'Task sent by email successfully.' => '', // 'Task sent by email successfully.' => '',

View File

@ -1266,7 +1266,7 @@ return array(
// 'Unable to upload files, check the permissions of your data folder.' => '', // 'Unable to upload files, check the permissions of your data folder.' => '',
// 'Another category with the same name exists in this project' => '', // 'Another category with the same name exists in this project' => '',
// 'Comment sent by email successfully.' => '', // 'Comment sent by email successfully.' => '',
// 'Sent by email to [%s](mailto:%s) (%s)' => '', // 'Sent by email to "%s" (%s)' => '',
// 'Unable to read uploaded file.' => '', // 'Unable to read uploaded file.' => '',
// 'Database uploaded successfully.' => '', // 'Database uploaded successfully.' => '',
// 'Task sent by email successfully.' => '', // 'Task sent by email successfully.' => '',

View File

@ -1266,7 +1266,7 @@ return array(
// 'Unable to upload files, check the permissions of your data folder.' => '', // 'Unable to upload files, check the permissions of your data folder.' => '',
// 'Another category with the same name exists in this project' => '', // 'Another category with the same name exists in this project' => '',
// 'Comment sent by email successfully.' => '', // 'Comment sent by email successfully.' => '',
// 'Sent by email to [%s](mailto:%s) (%s)' => '', // 'Sent by email to "%s" (%s)' => '',
// 'Unable to read uploaded file.' => '', // 'Unable to read uploaded file.' => '',
// 'Database uploaded successfully.' => '', // 'Database uploaded successfully.' => '',
// 'Task sent by email successfully.' => '', // 'Task sent by email successfully.' => '',

View File

@ -1266,7 +1266,7 @@ return array(
'Unable to upload files, check the permissions of your data folder.' => 'Dosya yüklenemedi. Lütfen yükleme dizine yazma izninizi kontrol ediniz.', 'Unable to upload files, check the permissions of your data folder.' => 'Dosya yüklenemedi. Lütfen yükleme dizine yazma izninizi kontrol ediniz.',
'Another category with the same name exists in this project' => 'Bu projede aynı ada sahip başka bir kategori var', 'Another category with the same name exists in this project' => 'Bu projede aynı ada sahip başka bir kategori var',
'Comment sent by email successfully.' => 'Yorum ePosta ile başarıyla gönderildi.', 'Comment sent by email successfully.' => 'Yorum ePosta ile başarıyla gönderildi.',
'Sent by email to [%s](mailto:%s) (%s)' => 'ePostayı gönder [%s](mailto:%s) (%s)', 'Sent by email to "%s" (%s)' => 'ePostayı gönder "%s" (%s)',
'Unable to read uploaded file.' => 'Yüklenen dosya okunamadı.', 'Unable to read uploaded file.' => 'Yüklenen dosya okunamadı.',
'Database uploaded successfully.' => 'Veritabanı başarıyla yüklendi.', 'Database uploaded successfully.' => 'Veritabanı başarıyla yüklendi.',
'Task sent by email successfully.' => 'Görev ePosta ile başarıyla gönderildi.', 'Task sent by email successfully.' => 'Görev ePosta ile başarıyla gönderildi.',

View File

@ -1272,7 +1272,7 @@ return array(
'Unable to upload files, check the permissions of your data folder.' => 'Không thể tải tệp lên, hãy kiểm tra quyền của thư mục dữ liệu của bạn.', 'Unable to upload files, check the permissions of your data folder.' => 'Không thể tải tệp lên, hãy kiểm tra quyền của thư mục dữ liệu của bạn.',
'Another category with the same name exists in this project' => 'Một thể loại khác có cùng tên tồn tại trong dự án này', 'Another category with the same name exists in this project' => 'Một thể loại khác có cùng tên tồn tại trong dự án này',
'Comment sent by email successfully.' => 'Thảo luận gửi qua email thành công.', 'Comment sent by email successfully.' => 'Thảo luận gửi qua email thành công.',
'Sent by email to [%s](mailto:%s) (%s)' => 'Gửi qua email tới [ %s] (mailto: %s) ( %s)', 'Sent by email to "%s" (%s)' => 'Gửi qua email tới "%s" ( %s)',
'Unable to read uploaded file.' => 'Không thể đọc tập tin được tải lên.', 'Unable to read uploaded file.' => 'Không thể đọc tập tin được tải lên.',
'Database uploaded successfully.' => 'Cơ sở dữ liệu được tải lên thành công.', 'Database uploaded successfully.' => 'Cơ sở dữ liệu được tải lên thành công.',
'Task sent by email successfully.' => 'Nhiệm vụ gửi qua email thành công.', 'Task sent by email successfully.' => 'Nhiệm vụ gửi qua email thành công.',

View File

@ -1266,7 +1266,7 @@ return array(
'Unable to upload files, check the permissions of your data folder.' => '无法上传文件请检查你的data目录权限。', 'Unable to upload files, check the permissions of your data folder.' => '无法上传文件请检查你的data目录权限。',
// 'Another category with the same name exists in this project' => '', // 'Another category with the same name exists in this project' => '',
// 'Comment sent by email successfully.' => '', // 'Comment sent by email successfully.' => '',
// 'Sent by email to [%s](mailto:%s) (%s)' => '', // 'Sent by email to "%s" (%s)' => '',
// 'Unable to read uploaded file.' => '', // 'Unable to read uploaded file.' => '',
// 'Database uploaded successfully.' => '', // 'Database uploaded successfully.' => '',
// 'Task sent by email successfully.' => '', // 'Task sent by email successfully.' => '',

View File

@ -6,8 +6,8 @@
<?= $this->form->hidden('task_id', $values) ?> <?= $this->form->hidden('task_id', $values) ?>
<?= $this->form->hidden('user_id', $values) ?> <?= $this->form->hidden('user_id', $values) ?>
<?= $this->form->label(t('Email'), 'email') ?> <?= $this->form->label(t('Email'), 'emails') ?>
<?= $this->form->email('email', $values, $errors, array('autofocus', 'required', 'tabindex="1"')) ?> <?= $this->form->text('emails', $values, $errors, array('autofocus', 'required', 'tabindex="1"')) ?>
<?php if (! empty($members)): ?> <?php if (! empty($members)): ?>
<div class="dropdown"> <div class="dropdown">

View File

@ -4,8 +4,8 @@
<form method="post" action="<?= $this->url->href('TaskMailController', 'send', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off" class="js-mail-form"> <form method="post" action="<?= $this->url->href('TaskMailController', 'send', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off" class="js-mail-form">
<?= $this->form->csrf() ?> <?= $this->form->csrf() ?>
<?= $this->form->label(t('Email'), 'email') ?> <?= $this->form->label(t('Email'), 'emails') ?>
<?= $this->form->email('email', $values, $errors, array('autofocus', 'required', 'tabindex="1"')) ?> <?= $this->form->text('emails', $values, $errors, array('autofocus', 'required', 'tabindex="1"')) ?>
<?php if (! empty($members)): ?> <?php if (! empty($members)): ?>
<div class="dropdown"> <div class="dropdown">

View File

@ -26,8 +26,7 @@ class CommentValidator extends BaseValidator
new Validators\Required('task_id', t('This value is required')), new Validators\Required('task_id', t('This value is required')),
new Validators\Required('user_id', t('This value is required')), new Validators\Required('user_id', t('This value is required')),
new Validators\Required('subject', t('This field is required')), new Validators\Required('subject', t('This field is required')),
new Validators\Required('email', t('This field is required')), new Validators\Required('emails', t('This field is required')),
new Validators\Email('email', t('Email address invalid')),
); );
$v = new Validator($values, array_merge($rules, $this->commonValidationRules())); $v = new Validator($values, array_merge($rules, $this->commonValidationRules()));

View File

@ -217,8 +217,7 @@ class TaskValidator extends BaseValidator
{ {
$rules = array( $rules = array(
new Validators\Required('subject', t('This field is required')), new Validators\Required('subject', t('This field is required')),
new Validators\Required('email', t('This field is required')), new Validators\Required('emails', t('This field is required')),
new Validators\Email('email', t('Email address invalid')),
); );
$v = new Validator($values, $rules); $v = new Validator($values, $rules);

View File

@ -2,6 +2,13 @@
use Kanboard\Core\Translator; use Kanboard\Core\Translator;
function explode_csv_field($field)
{
$fields = explode(',', $field);
array_walk($fields, function (&$value) { $value = trim($value); });
return array_filter($fields);
}
/** /**
* Associate another dict to a dict based on a common key * Associate another dict to a dict based on a common key
* *

File diff suppressed because one or more lines are too long

View File

@ -1,9 +1,15 @@
KB.onClick('.js-autocomplete-email', function (e) { KB.onClick('.js-autocomplete-email', function (e) {
var email = KB.dom(e.target).data('email'); var email = e.target.dataset.email;
var emailField = KB.find('.js-mail-form input[type="email"]'); var emailField = document.querySelector('.js-mail-form input[name="emails"]');
if (email && emailField) { if (!email || !emailField) {
emailField.build().value = email; return;
}
if (emailField.value !== '') {
emailField.value += ', ' + email;
} else {
emailField.value = email;
} }
_KB.controllers.Dropdown.close(); _KB.controllers.Dropdown.close();

View File

@ -14,7 +14,7 @@ class CommentValidatorTest extends Base
'user_id' => 1, 'user_id' => 1,
'task_id' => 1, 'task_id' => 1,
'comment' => 'blah', 'comment' => 'blah',
'email' => 'test@localhost', 'emails' => 'test@localhost, another@localhost',
'subject' => 'something', 'subject' => 'something',
)); ));
@ -24,20 +24,10 @@ class CommentValidatorTest extends Base
'user_id' => 1, 'user_id' => 1,
'task_id' => 1, 'task_id' => 1,
'comment' => 'blah', 'comment' => 'blah',
'email' => 'invalid',
'subject' => 'something', 'subject' => 'something',
)); ));
$this->assertFalse($result[0]); $this->assertFalse($result[0]);
$result = $commentValidator->validateEmailCreation(array(
'user_id' => 1,
'task_id' => 1,
'comment' => 'bla',
'email' => 'test@localhost',
));
$this->assertFalse($result[0]);
} }
public function testValidateCreation() public function testValidateCreation()

View File

@ -10,16 +10,13 @@ class TaskValidatorTest extends Base
{ {
$taskValidator = new TaskValidator($this->container); $taskValidator = new TaskValidator($this->container);
$result = $taskValidator->validateEmailCreation(array('email' => 'test@localhost', 'subject' => 'test')); $result = $taskValidator->validateEmailCreation(array('emails' => 'test@localhost', 'subject' => 'test'));
$this->assertTrue($result[0]); $this->assertTrue($result[0]);
$result = $taskValidator->validateEmailCreation(array('email' => 'test', 'subject' => 'test'));
$this->assertFalse($result[0]);
$result = $taskValidator->validateEmailCreation(array('subject' => 'test')); $result = $taskValidator->validateEmailCreation(array('subject' => 'test'));
$this->assertFalse($result[0]); $this->assertFalse($result[0]);
$result = $taskValidator->validateEmailCreation(array('email' => 'test@localhost')); $result = $taskValidator->validateEmailCreation(array('emails' => 'test@localhost, test@localhost'));
$this->assertFalse($result[0]); $this->assertFalse($result[0]);
} }
@ -104,7 +101,6 @@ class TaskValidatorTest extends Base
$result = $taskValidator->validateCreation(array('project_id' => 1, 'title' => 'test', 'date_due' => '02/01/2017 1:15 pm')); $result = $taskValidator->validateCreation(array('project_id' => 1, 'title' => 'test', 'date_due' => '02/01/2017 1:15 pm'));
$this->assertFalse($result[0]); $this->assertFalse($result[0]);
// date_started // date_started
// ISO dates // ISO dates
$result = $taskValidator->validateCreation(array('project_id' => 1, 'title' => 'test', 'date_started' => '2017-02-01')); $result = $taskValidator->validateCreation(array('project_id' => 1, 'title' => 'test', 'date_started' => '2017-02-01'));

View File

@ -163,6 +163,7 @@ return array(
'Kanboard\\Console\\TaskOverdueNotificationCommand' => $baseDir . '/app/Console/TaskOverdueNotificationCommand.php', 'Kanboard\\Console\\TaskOverdueNotificationCommand' => $baseDir . '/app/Console/TaskOverdueNotificationCommand.php',
'Kanboard\\Console\\TaskTriggerCommand' => $baseDir . '/app/Console/TaskTriggerCommand.php', 'Kanboard\\Console\\TaskTriggerCommand' => $baseDir . '/app/Console/TaskTriggerCommand.php',
'Kanboard\\Console\\TransitionExportCommand' => $baseDir . '/app/Console/TransitionExportCommand.php', 'Kanboard\\Console\\TransitionExportCommand' => $baseDir . '/app/Console/TransitionExportCommand.php',
'Kanboard\\Console\\VersionCommand' => $baseDir . '/app/Console/VersionCommand.php',
'Kanboard\\Console\\WorkerCommand' => $baseDir . '/app/Console/WorkerCommand.php', 'Kanboard\\Console\\WorkerCommand' => $baseDir . '/app/Console/WorkerCommand.php',
'Kanboard\\Controller\\ActionController' => $baseDir . '/app/Controller/ActionController.php', 'Kanboard\\Controller\\ActionController' => $baseDir . '/app/Controller/ActionController.php',
'Kanboard\\Controller\\ActionCreationController' => $baseDir . '/app/Controller/ActionCreationController.php', 'Kanboard\\Controller\\ActionCreationController' => $baseDir . '/app/Controller/ActionCreationController.php',

View File

@ -299,6 +299,7 @@ class ComposerStaticInit6edea6294a88689e3f5c56484bb70c9b
'Kanboard\\Console\\TaskOverdueNotificationCommand' => __DIR__ . '/../..' . '/app/Console/TaskOverdueNotificationCommand.php', 'Kanboard\\Console\\TaskOverdueNotificationCommand' => __DIR__ . '/../..' . '/app/Console/TaskOverdueNotificationCommand.php',
'Kanboard\\Console\\TaskTriggerCommand' => __DIR__ . '/../..' . '/app/Console/TaskTriggerCommand.php', 'Kanboard\\Console\\TaskTriggerCommand' => __DIR__ . '/../..' . '/app/Console/TaskTriggerCommand.php',
'Kanboard\\Console\\TransitionExportCommand' => __DIR__ . '/../..' . '/app/Console/TransitionExportCommand.php', 'Kanboard\\Console\\TransitionExportCommand' => __DIR__ . '/../..' . '/app/Console/TransitionExportCommand.php',
'Kanboard\\Console\\VersionCommand' => __DIR__ . '/../..' . '/app/Console/VersionCommand.php',
'Kanboard\\Console\\WorkerCommand' => __DIR__ . '/../..' . '/app/Console/WorkerCommand.php', 'Kanboard\\Console\\WorkerCommand' => __DIR__ . '/../..' . '/app/Console/WorkerCommand.php',
'Kanboard\\Controller\\ActionController' => __DIR__ . '/../..' . '/app/Controller/ActionController.php', 'Kanboard\\Controller\\ActionController' => __DIR__ . '/../..' . '/app/Controller/ActionController.php',
'Kanboard\\Controller\\ActionCreationController' => __DIR__ . '/../..' . '/app/Controller/ActionCreationController.php', 'Kanboard\\Controller\\ActionCreationController' => __DIR__ . '/../..' . '/app/Controller/ActionCreationController.php',