Move slack, hipchat and jabber integrations to plugins
This commit is contained in:
parent
9283fb88d8
commit
09da289c2f
|
|
@ -44,7 +44,7 @@ class Config extends Base
|
|||
$values += array('subtask_restriction' => 0, 'subtask_time_tracking' => 0, 'cfd_include_closed_tasks' => 0);
|
||||
break;
|
||||
case 'integrations':
|
||||
$values += array('integration_slack_webhook' => 0, 'integration_hipchat' => 0, 'integration_gravatar' => 0, 'integration_jabber' => 0);
|
||||
$values += array('integration_gravatar' => 0);
|
||||
break;
|
||||
case 'calendar':
|
||||
$values += array('calendar_user_subtasks_time_tracking' => 0);
|
||||
|
|
|
|||
|
|
@ -89,28 +89,49 @@ class Project extends Base
|
|||
*
|
||||
* @access public
|
||||
*/
|
||||
public function integration()
|
||||
public function integrations()
|
||||
{
|
||||
$project = $this->getProject();
|
||||
|
||||
if ($this->request->isPost()) {
|
||||
$params = $this->request->getValues();
|
||||
$params += array('hipchat' => 0, 'slack' => 0, 'jabber' => 0);
|
||||
$this->projectIntegration->saveParameters($project['id'], $params);
|
||||
$this->projectMetadata->save($project['id'], $this->request->getValues());
|
||||
$this->session->flash(t('Project updated successfully.'));
|
||||
$this->response->redirect($this->helper->url->to('project', 'integrations', array('project_id' => $project['id'])));
|
||||
}
|
||||
|
||||
$values = $this->projectIntegration->getParameters($project['id']);
|
||||
$values += array('hipchat_api_url' => 'https://api.hipchat.com');
|
||||
|
||||
$this->response->html($this->projectLayout('project/integrations', array(
|
||||
'project' => $project,
|
||||
'title' => t('Integrations'),
|
||||
'webhook_token' => $this->config->get('webhook_token'),
|
||||
'values' => $values,
|
||||
'values' => $this->projectMetadata->getAll($project['id']),
|
||||
'errors' => array(),
|
||||
)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Display project notifications
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function notifications()
|
||||
{
|
||||
$project = $this->getProject();
|
||||
|
||||
if ($this->request->isPost()) {
|
||||
$values = $this->request->getValues();
|
||||
$this->projectNotification->saveSettings($project['id'], $values);
|
||||
$this->session->flash(t('Project updated successfully.'));
|
||||
$this->response->redirect($this->helper->url->to('project', 'notifications', array('project_id' => $project['id'])));
|
||||
}
|
||||
|
||||
$this->response->html($this->projectLayout('project/notifications', array(
|
||||
'notifications' => $this->projectNotification->readSettings($project['id']),
|
||||
'types' => $this->projectNotificationType->getTypes(),
|
||||
'project' => $project,
|
||||
'title' => t('Notifications'),
|
||||
)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a form to edit a project
|
||||
*
|
||||
|
|
|
|||
|
|
@ -213,6 +213,28 @@ class User extends Base
|
|||
)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Display user integrations
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function integrations()
|
||||
{
|
||||
$user = $this->getUser();
|
||||
|
||||
if ($this->request->isPost()) {
|
||||
$values = $this->request->getValues();
|
||||
$this->userMetadata->save($user['id'], $values);
|
||||
$this->session->flash(t('User updated successfully.'));
|
||||
$this->response->redirect($this->helper->url->to('user', 'integrations', array('user_id' => $user['id'])));
|
||||
}
|
||||
|
||||
$this->response->html($this->layout('user/integrations', array(
|
||||
'user' => $user,
|
||||
'values' => $this->userMetadata->getall($user['id']),
|
||||
)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Display external accounts
|
||||
*
|
||||
|
|
|
|||
|
|
@ -27,9 +27,6 @@ use Pimple\Container;
|
|||
* @property \Kanboard\Integration\BitbucketWebhook $bitbucketWebhook
|
||||
* @property \Kanboard\Integration\GithubWebhook $githubWebhook
|
||||
* @property \Kanboard\Integration\GitlabWebhook $gitlabWebhook
|
||||
* @property \Kanboard\Integration\HipchatWebhook $hipchatWebhook
|
||||
* @property \Kanboard\Integration\Jabber $jabber
|
||||
* @property \Kanboard\Integration\SlackWebhook $slackWebhook
|
||||
* @property \Kanboard\Formatter\ProjectGanttFormatter $projectGanttFormatter
|
||||
* @property \Kanboard\Formatter\TaskFilterGanttFormatter $taskFilterGanttFormatter
|
||||
* @property \Kanboard\Formatter\TaskFilterAutoCompleteFormatter $taskFilterAutoCompleteFormatter
|
||||
|
|
@ -49,6 +46,7 @@ use Pimple\Container;
|
|||
* @property \Kanboard\Model\File $file
|
||||
* @property \Kanboard\Model\LastLogin $lastLogin
|
||||
* @property \Kanboard\Model\Link $link
|
||||
* @property \Kanboard\Model\Notification $notification
|
||||
* @property \Kanboard\Model\OverdueNotification $overdueNotification
|
||||
* @property \Kanboard\Model\Project $project
|
||||
* @property \Kanboard\Model\ProjectActivity $projectActivity
|
||||
|
|
@ -56,7 +54,7 @@ use Pimple\Container;
|
|||
* @property \Kanboard\Model\ProjectDuplication $projectDuplication
|
||||
* @property \Kanboard\Model\ProjectDailyColumnStats $projectDailyColumnStats
|
||||
* @property \Kanboard\Model\ProjectDailyStats $projectDailyStats
|
||||
* @property \Kanboard\Model\ProjectIntegration $projectIntegration
|
||||
* @property \Kanboard\Model\ProjectMetadata $projectMetadata
|
||||
* @property \Kanboard\Model\ProjectPermission $projectPermission
|
||||
* @property \Kanboard\Model\Subtask $subtask
|
||||
* @property \Kanboard\Model\SubtaskExport $subtaskExport
|
||||
|
|
@ -76,6 +74,7 @@ use Pimple\Container;
|
|||
* @property \Kanboard\Model\TaskPosition $taskPosition
|
||||
* @property \Kanboard\Model\TaskStatus $taskStatus
|
||||
* @property \Kanboard\Model\TaskValidator $taskValidator
|
||||
* @property \Kanboard\Model\TaskMetadata $taskMetadata
|
||||
* @property \Kanboard\Model\Transition $transition
|
||||
* @property \Kanboard\Model\User $user
|
||||
* @property \Kanboard\Model\UserImport $userImport
|
||||
|
|
@ -84,6 +83,7 @@ use Pimple\Container;
|
|||
* @property \Kanboard\Model\UserNotificationFilter $userNotificationFilter
|
||||
* @property \Kanboard\Model\UserUnreadNotification $userUnreadNotification
|
||||
* @property \Kanboard\Model\UserSession $userSession
|
||||
* @property \Kanboard\Model\UserMetadata $userMetadata
|
||||
* @property \Kanboard\Model\Webhook $webhook
|
||||
* @property \Psr\Log\LoggerInterface $logger
|
||||
* @property \League\HTMLToMarkdown\HtmlConverter $htmlConverter
|
||||
|
|
|
|||
|
|
@ -1,93 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Kanboard\Integration;
|
||||
|
||||
/**
|
||||
* Hipchat webhook
|
||||
*
|
||||
* @package integration
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class HipchatWebhook extends \Kanboard\Core\Base
|
||||
{
|
||||
/**
|
||||
* Return true if Hipchat is enabled for this project or globally
|
||||
*
|
||||
* @access public
|
||||
* @param integer $project_id
|
||||
* @return boolean
|
||||
*/
|
||||
public function isActivated($project_id)
|
||||
{
|
||||
return $this->config->get('integration_hipchat') == 1 || $this->projectIntegration->hasValue($project_id, 'hipchat', 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get API parameters
|
||||
*
|
||||
* @access public
|
||||
* @param integer $project_id
|
||||
* @return array
|
||||
*/
|
||||
public function getParameters($project_id)
|
||||
{
|
||||
if ($this->config->get('integration_hipchat') == 1) {
|
||||
return array(
|
||||
'api_url' => $this->config->get('integration_hipchat_api_url'),
|
||||
'room_id' => $this->config->get('integration_hipchat_room_id'),
|
||||
'room_token' => $this->config->get('integration_hipchat_room_token'),
|
||||
);
|
||||
}
|
||||
|
||||
$options = $this->projectIntegration->getParameters($project_id);
|
||||
|
||||
return array(
|
||||
'api_url' => $options['hipchat_api_url'],
|
||||
'room_id' => $options['hipchat_room_id'],
|
||||
'room_token' => $options['hipchat_room_token'],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the notification if activated
|
||||
*
|
||||
* @access public
|
||||
* @param integer $project_id Project id
|
||||
* @param integer $task_id Task id
|
||||
* @param string $event_name Event name
|
||||
* @param array $event Event data
|
||||
*/
|
||||
public function notify($project_id, $task_id, $event_name, array $event)
|
||||
{
|
||||
if ($this->isActivated($project_id)) {
|
||||
$params = $this->getParameters($project_id);
|
||||
$project = $this->project->getbyId($project_id);
|
||||
|
||||
$event['event_name'] = $event_name;
|
||||
$event['author'] = $this->user->getFullname($this->session['user']);
|
||||
|
||||
$html = '<img src="http://kanboard.net/assets/img/favicon-32x32.png"/>';
|
||||
$html .= '<strong>'.$project['name'].'</strong>'.(isset($event['task']['title']) ? '<br/>'.$event['task']['title'] : '').'<br/>';
|
||||
$html .= $this->projectActivity->getTitle($event);
|
||||
|
||||
if ($this->config->get('application_url')) {
|
||||
$html .= '<br/><a href="'.$this->helper->url->href('task', 'show', array('task_id' => $task_id, 'project_id' => $project_id), false, '', true).'">';
|
||||
$html .= t('view the task on Kanboard').'</a>';
|
||||
}
|
||||
|
||||
$payload = array(
|
||||
'message' => $html,
|
||||
'color' => 'yellow',
|
||||
);
|
||||
|
||||
$url = sprintf(
|
||||
'%s/v2/room/%s/notification?auth_token=%s',
|
||||
$params['api_url'],
|
||||
$params['room_id'],
|
||||
$params['room_token']
|
||||
);
|
||||
|
||||
$this->httpClient->postJson($url, $payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,126 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Kanboard\Integration;
|
||||
|
||||
use Exception;
|
||||
use Fabiang\Xmpp\Options;
|
||||
use Fabiang\Xmpp\Client;
|
||||
use Fabiang\Xmpp\Protocol\Message;
|
||||
use Fabiang\Xmpp\Protocol\Presence;
|
||||
|
||||
/**
|
||||
* Jabber
|
||||
*
|
||||
* @package integration
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class Jabber extends \Kanboard\Core\Base
|
||||
{
|
||||
/**
|
||||
* Return true if Jabber is enabled for this project or globally
|
||||
*
|
||||
* @access public
|
||||
* @param integer $project_id
|
||||
* @return boolean
|
||||
*/
|
||||
public function isActivated($project_id)
|
||||
{
|
||||
return $this->config->get('integration_jabber') == 1 || $this->projectIntegration->hasValue($project_id, 'jabber', 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get connection parameters
|
||||
*
|
||||
* @access public
|
||||
* @param integer $project_id
|
||||
* @return array
|
||||
*/
|
||||
public function getParameters($project_id)
|
||||
{
|
||||
if ($this->config->get('integration_jabber') == 1) {
|
||||
return array(
|
||||
'server' => $this->config->get('integration_jabber_server'),
|
||||
'domain' => $this->config->get('integration_jabber_domain'),
|
||||
'username' => $this->config->get('integration_jabber_username'),
|
||||
'password' => $this->config->get('integration_jabber_password'),
|
||||
'nickname' => $this->config->get('integration_jabber_nickname'),
|
||||
'room' => $this->config->get('integration_jabber_room'),
|
||||
);
|
||||
}
|
||||
|
||||
$options = $this->projectIntegration->getParameters($project_id);
|
||||
|
||||
return array(
|
||||
'server' => $options['jabber_server'],
|
||||
'domain' => $options['jabber_domain'],
|
||||
'username' => $options['jabber_username'],
|
||||
'password' => $options['jabber_password'],
|
||||
'nickname' => $options['jabber_nickname'],
|
||||
'room' => $options['jabber_room'],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build and send the message
|
||||
*
|
||||
* @access public
|
||||
* @param integer $project_id Project id
|
||||
* @param integer $task_id Task id
|
||||
* @param string $event_name Event name
|
||||
* @param array $event Event data
|
||||
*/
|
||||
public function notify($project_id, $task_id, $event_name, array $event)
|
||||
{
|
||||
if ($this->isActivated($project_id)) {
|
||||
$project = $this->project->getbyId($project_id);
|
||||
|
||||
$event['event_name'] = $event_name;
|
||||
$event['author'] = $this->user->getFullname($this->session['user']);
|
||||
|
||||
$payload = '['.$project['name'].'] '.str_replace('"', '"', $this->projectActivity->getTitle($event)).(isset($event['task']['title']) ? ' ('.$event['task']['title'].')' : '');
|
||||
|
||||
if ($this->config->get('application_url')) {
|
||||
$payload .= ' '.$this->helper->url->to('task', 'show', array('task_id' => $task_id, 'project_id' => $project_id), '', true);
|
||||
}
|
||||
|
||||
$this->sendMessage($project_id, $payload);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send message to the XMPP server
|
||||
*
|
||||
* @access public
|
||||
* @param integer $project_id
|
||||
* @param string $payload
|
||||
*/
|
||||
public function sendMessage($project_id, $payload)
|
||||
{
|
||||
try {
|
||||
$params = $this->getParameters($project_id);
|
||||
|
||||
$options = new Options($params['server']);
|
||||
$options->setUsername($params['username']);
|
||||
$options->setPassword($params['password']);
|
||||
$options->setTo($params['domain']);
|
||||
$options->setLogger($this->container['logger']);
|
||||
|
||||
$client = new Client($options);
|
||||
|
||||
$channel = new Presence;
|
||||
$channel->setTo($params['room'])->setNickName($params['nickname']);
|
||||
$client->send($channel);
|
||||
|
||||
$message = new Message;
|
||||
$message->setMessage($payload)
|
||||
->setTo($params['room'])
|
||||
->setType(Message::TYPE_GROUPCHAT);
|
||||
|
||||
$client->send($message);
|
||||
|
||||
$client->disconnect();
|
||||
} catch (Exception $e) {
|
||||
$this->container['logger']->error('Jabber error: '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,126 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Kanboard\Integration;
|
||||
|
||||
/**
|
||||
* Slack Webhook
|
||||
*
|
||||
* @package integration
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class SlackWebhook extends \Kanboard\Core\Base
|
||||
{
|
||||
/**
|
||||
* Return true if Slack is enabled for this project or globally
|
||||
*
|
||||
* @access public
|
||||
* @param integer $project_id
|
||||
* @return boolean
|
||||
*/
|
||||
public function isActivated($project_id)
|
||||
{
|
||||
return $this->config->get('integration_slack_webhook') == 1 || $this->projectIntegration->hasValue($project_id, 'slack', 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get wehbook url
|
||||
*
|
||||
* @access public
|
||||
* @param integer $project_id
|
||||
* @return string
|
||||
*/
|
||||
public function getWebhookUrl($project_id)
|
||||
{
|
||||
if ($this->config->get('integration_slack_webhook') == 1) {
|
||||
return $this->config->get('integration_slack_webhook_url');
|
||||
}
|
||||
|
||||
$options = $this->projectIntegration->getParameters($project_id);
|
||||
return isset($options['slack_webhook_url']) ? $options['slack_webhook_url'] : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get optional Slack channel
|
||||
*
|
||||
* @access public
|
||||
* @param integer $project_id
|
||||
* @return string
|
||||
*/
|
||||
public function getChannel($project_id)
|
||||
{
|
||||
$channel = $this->config->get('integration_slack_webhook_channel');
|
||||
|
||||
if (! empty($channel)) {
|
||||
return $channel;
|
||||
}
|
||||
|
||||
$options = $this->projectIntegration->getParameters($project_id);
|
||||
return isset($options['slack_webhook_channel']) ? $options['slack_webhook_channel'] : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Send notification to Slack
|
||||
*
|
||||
* @access public
|
||||
* @param integer $project_id Project id
|
||||
* @param integer $task_id Task id
|
||||
* @param string $event_name Event name
|
||||
* @param array $event Event data
|
||||
*/
|
||||
public function notify($project_id, $task_id, $event_name, array $event)
|
||||
{
|
||||
if ($this->isActivated($project_id)) {
|
||||
$project = $this->project->getbyId($project_id);
|
||||
|
||||
$event['event_name'] = $event_name;
|
||||
$event['author'] = $this->user->getFullname($this->session['user']);
|
||||
|
||||
$message = '*['.$project['name'].']* ';
|
||||
$message .= str_replace('"', '"', $this->projectActivity->getTitle($event));
|
||||
$message .= isset($event['task']['title']) ? ' ('.$event['task']['title'].')' : '';
|
||||
|
||||
if ($this->config->get('application_url')) {
|
||||
$message .= ' - <'.$this->helper->url->href('task', 'show', array('task_id' => $task_id, 'project_id' => $project_id), false, '', true);
|
||||
$message .= '|'.t('view the task on Kanboard').'>';
|
||||
}
|
||||
|
||||
$this->sendMessage($project_id, $message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send message to Slack
|
||||
*
|
||||
* @access public
|
||||
* @param integer $project_id
|
||||
* @param string $message
|
||||
*/
|
||||
public function sendMessage($project_id, $message)
|
||||
{
|
||||
$payload = array(
|
||||
'text' => $message,
|
||||
'username' => 'Kanboard',
|
||||
'icon_url' => 'http://kanboard.net/assets/img/favicon.png',
|
||||
);
|
||||
|
||||
$this->sendPayload($project_id, $payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send payload to Slack
|
||||
*
|
||||
* @access public
|
||||
* @param integer $project_id
|
||||
* @param array $payload
|
||||
*/
|
||||
public function sendPayload($project_id, array $payload)
|
||||
{
|
||||
$channel = $this->getChannel($project_id);
|
||||
|
||||
if (! empty($channel)) {
|
||||
$payload['channel'] = $channel;
|
||||
}
|
||||
|
||||
$this->httpClient->postJson($this->getWebhookUrl($project_id), $payload);
|
||||
}
|
||||
}
|
||||
|
|
@ -697,15 +697,9 @@ return array(
|
|||
'Reference currency' => 'Referenční měna',
|
||||
'The currency rate have been added successfully.' => 'Směnný kurz byl úspěšně přidán.',
|
||||
'Unable to add this currency rate.' => 'Nelze přidat tento směnný kurz',
|
||||
'Send notifications to a Slack channel' => 'Zaslání upozornění do Slack kanálu',
|
||||
'Webhook URL' => 'Webhook URL',
|
||||
'Help on Slack integration' => 'Nápověda pro Slack integraci.',
|
||||
'%s remove the assignee of the task %s' => '%s odstranil přiřazení úkolu %s ',
|
||||
'Send notifications to Hipchat' => 'Odeslat upozornění přes Hipchat',
|
||||
'API URL' => 'API URL',
|
||||
'Room API ID or name' => 'Raum API ID oder Name',
|
||||
'Room notification token' => 'Raum Benachrichtigungstoken',
|
||||
'Help on Hipchat integration' => 'Hilfe bei Hipchat Integration',
|
||||
'Enable Gravatar images' => 'Aktiviere Gravatar Bilder',
|
||||
'Information' => 'Informace',
|
||||
'Check two factor authentication code' => 'Prüfe Zwei-Faktor-Authentifizierungscode',
|
||||
|
|
@ -768,14 +762,6 @@ return array(
|
|||
// 'When task is moved from first column' => '',
|
||||
// 'When task is moved to last column' => '',
|
||||
// 'Year(s)' => '',
|
||||
// 'Jabber (XMPP)' => '',
|
||||
// 'Send notifications to Jabber' => '',
|
||||
// 'XMPP server address' => '',
|
||||
// 'Jabber domain' => '',
|
||||
// 'Jabber nickname' => '',
|
||||
// 'Multi-user chat room' => '',
|
||||
// 'Help on Jabber integration' => '',
|
||||
// 'The server address must use this format: "tcp://hostname:5222"' => '',
|
||||
'Calendar settings' => 'Nastavení kalendáře',
|
||||
// 'Project calendar view' => '',
|
||||
'Project settings' => 'Nastavení projektu',
|
||||
|
|
@ -820,8 +806,6 @@ return array(
|
|||
'%s moved the task #%d to the swimlane "%s"' => '%s hat die Aufgabe #%d in die Swimlane "%s" verschoben',
|
||||
// 'Swimlane' => '',
|
||||
// 'Gravatar' => '',
|
||||
// 'Hipchat' => '',
|
||||
// 'Slack' => '',
|
||||
'%s moved the task %s to the first swimlane' => '%s hat die Aufgabe %s in die erste Swimlane verschoben',
|
||||
'%s moved the task %s to the swimlane "%s"' => '%s hat die Aufgaben %s in die Swimlane "%s" verschoben',
|
||||
'This report contains all subtasks information for the given date range.' => 'Report obsahuje všechny informace o dílčích úkolech pro daný časový úsek',
|
||||
|
|
@ -918,7 +902,6 @@ return array(
|
|||
'Help on Google authentication' => 'Nápověda k ověřování pomocí služby Google',
|
||||
'Github Authentication' => 'Ověřování pomocí služby Github',
|
||||
'Help on Github authentication' => 'Nápověda k ověřování pomocí služby Github',
|
||||
'Channel/Group/User (Optional)' => 'Kanál/Skupina/Uživatel (volitelně)',
|
||||
'Lead time: ' => 'Dodací lhůta: ',
|
||||
'Cycle time: ' => 'Doba cyklu: ',
|
||||
'Time spent into each column' => 'Čas strávený v každé fázi',
|
||||
|
|
|
|||
|
|
@ -697,15 +697,9 @@ return array(
|
|||
// 'Reference currency' => '',
|
||||
// 'The currency rate have been added successfully.' => '',
|
||||
// 'Unable to add this currency rate.' => '',
|
||||
// 'Send notifications to a Slack channel' => '',
|
||||
// 'Webhook URL' => '',
|
||||
// 'Help on Slack integration' => '',
|
||||
// '%s remove the assignee of the task %s' => '',
|
||||
// 'Send notifications to Hipchat' => '',
|
||||
// 'API URL' => '',
|
||||
// 'Room API ID or name' => '',
|
||||
// 'Room notification token' => '',
|
||||
// 'Help on Hipchat integration' => '',
|
||||
// 'Enable Gravatar images' => '',
|
||||
// 'Information' => '',
|
||||
// 'Check two factor authentication code' => '',
|
||||
|
|
@ -768,14 +762,6 @@ return array(
|
|||
// 'When task is moved from first column' => '',
|
||||
// 'When task is moved to last column' => '',
|
||||
// 'Year(s)' => '',
|
||||
// 'Jabber (XMPP)' => '',
|
||||
// 'Send notifications to Jabber' => '',
|
||||
// 'XMPP server address' => '',
|
||||
// 'Jabber domain' => '',
|
||||
// 'Jabber nickname' => '',
|
||||
// 'Multi-user chat room' => '',
|
||||
// 'Help on Jabber integration' => '',
|
||||
// 'The server address must use this format: "tcp://hostname:5222"' => '',
|
||||
// 'Calendar settings' => '',
|
||||
// 'Project calendar view' => '',
|
||||
// 'Project settings' => '',
|
||||
|
|
@ -820,8 +806,6 @@ return array(
|
|||
// '%s moved the task #%d to the swimlane "%s"' => '',
|
||||
// 'Swimlane' => '',
|
||||
// 'Gravatar' => '',
|
||||
// 'Hipchat' => '',
|
||||
// 'Slack' => '',
|
||||
// '%s moved the task %s to the first swimlane' => '',
|
||||
// '%s moved the task %s to the swimlane "%s"' => '',
|
||||
// 'This report contains all subtasks information for the given date range.' => '',
|
||||
|
|
@ -918,7 +902,6 @@ return array(
|
|||
// 'Help on Google authentication' => '',
|
||||
// 'Github Authentication' => '',
|
||||
// 'Help on Github authentication' => '',
|
||||
// 'Channel/Group/User (Optional)' => '',
|
||||
// 'Lead time: ' => '',
|
||||
// 'Cycle time: ' => '',
|
||||
// 'Time spent into each column' => '',
|
||||
|
|
|
|||
|
|
@ -697,15 +697,9 @@ return array(
|
|||
'Reference currency' => 'Referenzwährung',
|
||||
'The currency rate have been added successfully.' => 'Der Währungskurs wurde erfolgreich hinzugefügt.',
|
||||
'Unable to add this currency rate.' => 'Währungskurs konnte nicht hinzugefügt werden',
|
||||
'Send notifications to a Slack channel' => 'Benachrichtigung an einen Slack-Kanal senden',
|
||||
'Webhook URL' => 'Webhook-URL',
|
||||
'Help on Slack integration' => 'Hilfe für Slack-Integration.',
|
||||
'%s remove the assignee of the task %s' => '%s Zuordnung für die Aufgabe %s entfernen',
|
||||
'Send notifications to Hipchat' => 'Sende Benachrichtigung an Hipchat',
|
||||
'API URL' => 'API-URL',
|
||||
'Room API ID or name' => 'Raum-API-ID oder -Name',
|
||||
'Room notification token' => 'Raum-Benachrichtigungstoken',
|
||||
'Help on Hipchat integration' => 'Hilfe bei Hipchat-Integration',
|
||||
'Enable Gravatar images' => 'Aktiviere Gravatar-Bilder',
|
||||
'Information' => 'Information',
|
||||
'Check two factor authentication code' => 'Prüfe Zwei-Faktor-Authentifizierungscode',
|
||||
|
|
@ -768,14 +762,6 @@ return array(
|
|||
'When task is moved from first column' => 'Wenn Aufgabe von erster Spalte verschoben wird',
|
||||
'When task is moved to last column' => 'Wenn Aufgabe in letzte Spalte verschoben wird',
|
||||
'Year(s)' => 'Jahr(e)',
|
||||
'Jabber (XMPP)' => 'Jabber (XMPP)',
|
||||
'Send notifications to Jabber' => 'Benachrichtigungen an Jabber senden',
|
||||
'XMPP server address' => 'XMPP-Server-Adresse',
|
||||
'Jabber domain' => 'Jabber-Domain',
|
||||
'Jabber nickname' => 'Jabber-Nickname',
|
||||
'Multi-user chat room' => 'Multi-User-Chatroom',
|
||||
'Help on Jabber integration' => 'Hilfe zur Jabber-Integration',
|
||||
'The server address must use this format: "tcp://hostname:5222"' => 'Die Server-Adresse muss in diesem Format sein: "tcp://hostname:5222"',
|
||||
'Calendar settings' => 'Kalender-Einstellungen',
|
||||
'Project calendar view' => 'Projekt-Kalendarsicht',
|
||||
'Project settings' => 'Projekteinstellungen',
|
||||
|
|
@ -820,8 +806,6 @@ return array(
|
|||
'%s moved the task #%d to the swimlane "%s"' => '%s hat die Aufgabe #%d in die Swimlane "%s" verschoben',
|
||||
'Swimlane' => 'Swimlane',
|
||||
'Gravatar' => 'Gravatar',
|
||||
'Hipchat' => 'Hipchat',
|
||||
'Slack' => 'Slack',
|
||||
'%s moved the task %s to the first swimlane' => '%s hat die Aufgabe %s in die erste Swimlane verschoben',
|
||||
'%s moved the task %s to the swimlane "%s"' => '%s hat die Aufgaben %s in die Swimlane "%s" verschoben',
|
||||
'This report contains all subtasks information for the given date range.' => 'Der Bericht beinhaltet alle Teilaufgaben im gewählten Zeitraum',
|
||||
|
|
@ -918,7 +902,6 @@ return array(
|
|||
'Help on Google authentication' => 'Hilfe bei Google-Authentifizierung',
|
||||
'Github Authentication' => 'Github-Authentifizierung',
|
||||
'Help on Github authentication' => 'Hilfe bei Github-Authentifizierung',
|
||||
'Channel/Group/User (Optional)' => 'Kanal/Gruppe/Benutzer (optional)',
|
||||
'Lead time: ' => 'Durchlaufzeit:',
|
||||
'Cycle time: ' => 'Zykluszeit:',
|
||||
'Time spent into each column' => 'zeit verbracht in jeder Spalte',
|
||||
|
|
|
|||
|
|
@ -697,15 +697,9 @@ return array(
|
|||
'Reference currency' => 'Moneda de referencia',
|
||||
'The currency rate have been added successfully.' => 'Se ha añadido el cambio de moneda con éxito',
|
||||
'Unable to add this currency rate.' => 'No pude añadir este cambio de moneda.',
|
||||
'Send notifications to a Slack channel' => 'Enviar notificaciones a un canal Desatendido',
|
||||
'Webhook URL' => 'URL de Disparador Web (webhook)',
|
||||
'Help on Slack integration' => 'Ayuda sobre integración Desatendida',
|
||||
'%s remove the assignee of the task %s' => '%s quita el concesionario de la tarea %s',
|
||||
'Send notifications to Hipchat' => 'Enviar notificaciones a Hipchat',
|
||||
'API URL' => 'URL de API',
|
||||
'Room API ID or name' => 'ID de API de habitación o nombre',
|
||||
'Room notification token' => 'Notificación de ficha de Habitación',
|
||||
'Help on Hipchat integration' => 'Ayuda sobre integración de Hipchat',
|
||||
'Enable Gravatar images' => 'Activar imágenes Gravatar',
|
||||
'Information' => 'Información',
|
||||
'Check two factor authentication code' => 'Revisar código de autenticación de dos factores',
|
||||
|
|
@ -768,14 +762,6 @@ return array(
|
|||
'When task is moved from first column' => 'Cuando la tarea es movida desde la primera columna',
|
||||
'When task is moved to last column' => 'Cuando la tarea es movida a la última columna',
|
||||
'Year(s)' => 'Año(s)',
|
||||
'Jabber (XMPP)' => 'Jabber (XMPP)',
|
||||
'Send notifications to Jabber' => 'Enviar notificaciones a Jabber',
|
||||
'XMPP server address' => 'Dirección del servidor XMPP',
|
||||
'Jabber domain' => 'Dominio Jabber',
|
||||
'Jabber nickname' => 'Apodo Jabber',
|
||||
'Multi-user chat room' => 'Sala de chat multiusuario',
|
||||
'Help on Jabber integration' => 'Ayuda para la integración con Jabber',
|
||||
'The server address must use this format: "tcp://hostname:5222"' => 'La dirección del servidor debe usar este formato: "tcp://hostname:5222"',
|
||||
'Calendar settings' => 'Parámetros del Calendario',
|
||||
'Project calendar view' => 'Vista de Calendario para el Proyecto',
|
||||
'Project settings' => 'Parámetros del Proyecto',
|
||||
|
|
@ -820,8 +806,6 @@ return array(
|
|||
'%s moved the task #%d to the swimlane "%s"' => '%s movió la tarea #%d a la calle "%s"',
|
||||
'Swimlane' => 'Calle',
|
||||
'Gravatar' => 'Gravatar',
|
||||
'Hipchat' => 'Hipchat',
|
||||
'Slack' => 'Desatendida',
|
||||
'%s moved the task %s to the first swimlane' => '%s movió la tarea %s a la primera calle',
|
||||
'%s moved the task %s to the swimlane "%s"' => '%s movió la tarea %s a la calle "%s"',
|
||||
'This report contains all subtasks information for the given date range.' => 'Este informe contiene todas la información de las subtareas para el rango proporcionado de fechas.',
|
||||
|
|
@ -918,7 +902,6 @@ return array(
|
|||
'Help on Google authentication' => 'Ayuda con la aAutenticación de Google',
|
||||
'Github Authentication' => 'Autenticación de Github',
|
||||
'Help on Github authentication' => 'Ayuda con la autenticación de Github',
|
||||
'Channel/Group/User (Optional)' => 'Canal/Grupo/Usuario (Opcional)',
|
||||
'Lead time: ' => 'Plazo de entrega: ',
|
||||
'Cycle time: ' => 'Tiempo de Ciclo: ',
|
||||
'Time spent into each column' => 'Tiempo empleado en cada columna',
|
||||
|
|
|
|||
|
|
@ -697,15 +697,9 @@ return array(
|
|||
// 'Reference currency' => '',
|
||||
// 'The currency rate have been added successfully.' => '',
|
||||
// 'Unable to add this currency rate.' => '',
|
||||
// 'Send notifications to a Slack channel' => '',
|
||||
// 'Webhook URL' => '',
|
||||
// 'Help on Slack integration' => '',
|
||||
// '%s remove the assignee of the task %s' => '',
|
||||
// 'Send notifications to Hipchat' => '',
|
||||
// 'API URL' => '',
|
||||
// 'Room API ID or name' => '',
|
||||
// 'Room notification token' => '',
|
||||
// 'Help on Hipchat integration' => '',
|
||||
// 'Enable Gravatar images' => '',
|
||||
// 'Information' => '',
|
||||
// 'Check two factor authentication code' => '',
|
||||
|
|
@ -768,14 +762,6 @@ return array(
|
|||
// 'When task is moved from first column' => '',
|
||||
// 'When task is moved to last column' => '',
|
||||
// 'Year(s)' => '',
|
||||
// 'Jabber (XMPP)' => '',
|
||||
// 'Send notifications to Jabber' => '',
|
||||
// 'XMPP server address' => '',
|
||||
// 'Jabber domain' => '',
|
||||
// 'Jabber nickname' => '',
|
||||
// 'Multi-user chat room' => '',
|
||||
// 'Help on Jabber integration' => '',
|
||||
// 'The server address must use this format: "tcp://hostname:5222"' => '',
|
||||
// 'Calendar settings' => '',
|
||||
// 'Project calendar view' => '',
|
||||
// 'Project settings' => '',
|
||||
|
|
@ -820,8 +806,6 @@ return array(
|
|||
// '%s moved the task #%d to the swimlane "%s"' => '',
|
||||
// 'Swimlane' => '',
|
||||
// 'Gravatar' => '',
|
||||
// 'Hipchat' => '',
|
||||
// 'Slack' => '',
|
||||
// '%s moved the task %s to the first swimlane' => '',
|
||||
// '%s moved the task %s to the swimlane "%s"' => '',
|
||||
// 'This report contains all subtasks information for the given date range.' => '',
|
||||
|
|
@ -918,7 +902,6 @@ return array(
|
|||
// 'Help on Google authentication' => '',
|
||||
// 'Github Authentication' => '',
|
||||
// 'Help on Github authentication' => '',
|
||||
// 'Channel/Group/User (Optional)' => '',
|
||||
// 'Lead time: ' => '',
|
||||
// 'Cycle time: ' => '',
|
||||
// 'Time spent into each column' => '',
|
||||
|
|
|
|||
|
|
@ -699,15 +699,9 @@ return array(
|
|||
'Reference currency' => 'Devise de référence',
|
||||
'The currency rate have been added successfully.' => 'Le taux de change a été ajouté avec succès.',
|
||||
'Unable to add this currency rate.' => 'Impossible d\'ajouter ce taux de change',
|
||||
'Send notifications to a Slack channel' => 'Envoyer les notifications sur un salon de discussion Slack',
|
||||
'Webhook URL' => 'URL du webhook',
|
||||
'Help on Slack integration' => 'Aide sur l\'intégration avec Slack',
|
||||
'%s remove the assignee of the task %s' => '%s a enlevé la personne assignée à la tâche %s',
|
||||
'Send notifications to Hipchat' => 'Envoyer les notifications vers Hipchat',
|
||||
'API URL' => 'URL de l\'api',
|
||||
'Room API ID or name' => 'Nom ou identifiant du salon de discussion',
|
||||
'Room notification token' => 'Jeton de sécurité du salon de discussion',
|
||||
'Help on Hipchat integration' => 'Aide sur l\'intégration avec Hipchat',
|
||||
'Enable Gravatar images' => 'Activer les images Gravatar',
|
||||
'Information' => 'Informations',
|
||||
'Check two factor authentication code' => 'Vérification du code pour l\'authentification à deux-facteurs',
|
||||
|
|
@ -770,14 +764,6 @@ return array(
|
|||
'When task is moved from first column' => 'Lorsque la tâche est déplacée en dehors de la première colonne',
|
||||
'When task is moved to last column' => 'Lorsque la tâche est déplacée dans la dernière colonne',
|
||||
'Year(s)' => 'Année(s)',
|
||||
'Jabber (XMPP)' => 'Jabber (XMPP)',
|
||||
'Send notifications to Jabber' => 'Envoyer les notifications vers Jabber',
|
||||
'XMPP server address' => 'Adresse du serveur XMPP',
|
||||
'Jabber domain' => 'Nom de domaine Jabber',
|
||||
'Jabber nickname' => 'Pseudonyme Jabber',
|
||||
'Multi-user chat room' => 'Salon de discussion multi-utilisateurs',
|
||||
'Help on Jabber integration' => 'Aide sur l\'intégration avec Jabber',
|
||||
'The server address must use this format: "tcp://hostname:5222"' => 'L\'adresse du serveur doit utiliser le format suivant : « tcp://hostname:5222 »',
|
||||
'Calendar settings' => 'Paramètres du calendrier',
|
||||
'Project calendar view' => 'Vue en mode projet du calendrier',
|
||||
'Project settings' => 'Paramètres du projet',
|
||||
|
|
@ -822,8 +808,6 @@ return array(
|
|||
'%s moved the task #%d to the swimlane "%s"' => '%s a déplacé la tâche n°%d dans la swimlane « %s »',
|
||||
'Swimlane' => 'Swimlane',
|
||||
'Gravatar' => 'Gravatar',
|
||||
'Hipchat' => 'Hipchat',
|
||||
'Slack' => 'Slack',
|
||||
'%s moved the task %s to the first swimlane' => '%s a déplacé la tâche %s dans la première swimlane',
|
||||
'%s moved the task %s to the swimlane "%s"' => '%s a déplacé la tâche %s dans la swimlane « %s »',
|
||||
'This report contains all subtasks information for the given date range.' => 'Ce rapport contient les informations de toutes les sous-tâches pour la période sélectionnée.',
|
||||
|
|
@ -920,7 +904,6 @@ return array(
|
|||
'Help on Google authentication' => 'Aide sur l\'authentification Google',
|
||||
'Github Authentication' => 'Authentification Github',
|
||||
'Help on Github authentication' => 'Aide sur l\'authentification Github',
|
||||
'Channel/Group/User (Optional)' => 'Canal/Groupe/Utilisateur (Optionnel)',
|
||||
'Lead time: ' => 'Lead time : ',
|
||||
'Cycle time: ' => 'Temps de cycle : ',
|
||||
'Time spent into each column' => 'Temps passé dans chaque colonne',
|
||||
|
|
|
|||
|
|
@ -697,15 +697,9 @@ return array(
|
|||
// 'Reference currency' => '',
|
||||
// 'The currency rate have been added successfully.' => '',
|
||||
// 'Unable to add this currency rate.' => '',
|
||||
// 'Send notifications to a Slack channel' => '',
|
||||
// 'Webhook URL' => '',
|
||||
// 'Help on Slack integration' => '',
|
||||
// '%s remove the assignee of the task %s' => '',
|
||||
// 'Send notifications to Hipchat' => '',
|
||||
// 'API URL' => '',
|
||||
// 'Room API ID or name' => '',
|
||||
// 'Room notification token' => '',
|
||||
// 'Help on Hipchat integration' => '',
|
||||
// 'Enable Gravatar images' => '',
|
||||
// 'Information' => '',
|
||||
// 'Check two factor authentication code' => '',
|
||||
|
|
@ -768,14 +762,6 @@ return array(
|
|||
// 'When task is moved from first column' => '',
|
||||
// 'When task is moved to last column' => '',
|
||||
// 'Year(s)' => '',
|
||||
// 'Jabber (XMPP)' => '',
|
||||
// 'Send notifications to Jabber' => '',
|
||||
// 'XMPP server address' => '',
|
||||
// 'Jabber domain' => '',
|
||||
// 'Jabber nickname' => '',
|
||||
// 'Multi-user chat room' => '',
|
||||
// 'Help on Jabber integration' => '',
|
||||
// 'The server address must use this format: "tcp://hostname:5222"' => '',
|
||||
// 'Calendar settings' => '',
|
||||
// 'Project calendar view' => '',
|
||||
// 'Project settings' => '',
|
||||
|
|
@ -820,8 +806,6 @@ return array(
|
|||
// '%s moved the task #%d to the swimlane "%s"' => '',
|
||||
// 'Swimlane' => '',
|
||||
// 'Gravatar' => '',
|
||||
// 'Hipchat' => '',
|
||||
// 'Slack' => '',
|
||||
// '%s moved the task %s to the first swimlane' => '',
|
||||
// '%s moved the task %s to the swimlane "%s"' => '',
|
||||
// 'This report contains all subtasks information for the given date range.' => '',
|
||||
|
|
@ -918,7 +902,6 @@ return array(
|
|||
// 'Help on Google authentication' => '',
|
||||
// 'Github Authentication' => '',
|
||||
// 'Help on Github authentication' => '',
|
||||
// 'Channel/Group/User (Optional)' => '',
|
||||
// 'Lead time: ' => '',
|
||||
// 'Cycle time: ' => '',
|
||||
// 'Time spent into each column' => '',
|
||||
|
|
|
|||
|
|
@ -697,15 +697,9 @@ return array(
|
|||
'Reference currency' => 'Referensi mata uang',
|
||||
'The currency rate have been added successfully.' => 'Nilai tukar mata uang berhasil ditambahkan.',
|
||||
'Unable to add this currency rate.' => 'Tidak dapat menambahkan nilai tukar mata uang',
|
||||
'Send notifications to a Slack channel' => 'Kirim pemberitahuan ke saluran Slack',
|
||||
'Webhook URL' => 'URL webhook',
|
||||
'Help on Slack integration' => 'Bantuan pada integrasi Slack',
|
||||
'%s remove the assignee of the task %s' => '%s menghapus penugasan dari tugas %s',
|
||||
'Send notifications to Hipchat' => 'Kirim pemberitahuan ke Hipchat',
|
||||
'API URL' => 'API URL',
|
||||
'Room API ID or name' => 'Id kamar API atau nama ',
|
||||
'Room notification token' => 'Token notifikasi kamar',
|
||||
'Help on Hipchat integration' => 'Bantuan pada integrasi Hipchat',
|
||||
'Enable Gravatar images' => 'Mengaktifkan gambar Gravatar',
|
||||
'Information' => 'Informasi',
|
||||
'Check two factor authentication code' => 'Cek dua faktor kode otentifikasi',
|
||||
|
|
@ -768,14 +762,6 @@ return array(
|
|||
'When task is moved from first column' => 'Ketika tugas dipindahkan dari kolom pertama',
|
||||
'When task is moved to last column' => 'Ketika tugas dipindahkan ke kolom terakhir',
|
||||
'Year(s)' => 'Tahun',
|
||||
'Jabber (XMPP)' => 'Jabber (XMPP)',
|
||||
'Send notifications to Jabber' => 'Kirim pemberitahuan ke Jabber',
|
||||
'XMPP server address' => 'alamat server XMPP',
|
||||
'Jabber domain' => 'Domain Jabber',
|
||||
'Jabber nickname' => 'Nickname Jabber',
|
||||
'Multi-user chat room' => 'Multi-pengguna kamar obrolan',
|
||||
'Help on Jabber integration' => 'Bantuan pada integrasi Jabber',
|
||||
'The server address must use this format: "tcp://hostname:5222"' => 'Alamat server harus menggunakan format ini : « tcp://hostname:5222 »',
|
||||
'Calendar settings' => 'Pengaturan kalender',
|
||||
'Project calendar view' => 'Tampilan kalender proyek',
|
||||
'Project settings' => 'Pengaturan proyek',
|
||||
|
|
@ -820,8 +806,6 @@ return array(
|
|||
'%s moved the task #%d to the swimlane "%s"' => '%s memindahkan tugas n°%d ke swimlane « %s »',
|
||||
'Swimlane' => 'Swimlane',
|
||||
'Gravatar' => 'Gravatar',
|
||||
'Hipchat' => 'Hipchat',
|
||||
'Slack' => 'Slack',
|
||||
'%s moved the task %s to the first swimlane' => '%s memindahkan tugas %s ke swimlane pertama',
|
||||
'%s moved the task %s to the swimlane "%s"' => '%s memindahkan tugas %s ke swimlane « %s »',
|
||||
'This report contains all subtasks information for the given date range.' => 'Laporan ini berisi semua informasi subtugas untuk rentang tanggal tertentu.',
|
||||
|
|
@ -918,7 +902,6 @@ return array(
|
|||
'Help on Google authentication' => 'Bantuan pada otentifikasi Google',
|
||||
'Github Authentication' => 'Otentifikasi Github',
|
||||
'Help on Github authentication' => 'Bantuan pada otentifikasi Github',
|
||||
'Channel/Group/User (Optional)' => 'Kanal/Grup/Pengguna (pilihan)',
|
||||
'Lead time: ' => 'Lead time : ',
|
||||
'Cycle time: ' => 'Siklus waktu : ',
|
||||
'Time spent into each column' => 'Waktu yang dihabiskan di setiap kolom',
|
||||
|
|
|
|||
|
|
@ -697,15 +697,9 @@ return array(
|
|||
'Reference currency' => 'Valuta di riferimento',
|
||||
'The currency rate have been added successfully.' => 'Il tasso di cambio è stato aggiunto con successo.',
|
||||
'Unable to add this currency rate.' => 'Impossibile aggiungere questo tasso di cambio.',
|
||||
'Send notifications to a Slack channel' => 'Invia notifiche al canale Slack',
|
||||
'Webhook URL' => 'URL Webhook',
|
||||
'Help on Slack integration' => 'Guida all\'integrazione con Slack',
|
||||
'%s remove the assignee of the task %s' => '%s rimuove l\'assegnatario del compito %s',
|
||||
'Send notifications to Hipchat' => 'Invia notifiche a Hipchat',
|
||||
'API URL' => 'URL API',
|
||||
'Room API ID or name' => 'Nome o ID API della Room',
|
||||
'Room notification token' => 'Token per le notifiche della Room',
|
||||
'Help on Hipchat integration' => 'Guida all\'integrazione di Hipchat',
|
||||
'Enable Gravatar images' => 'Abilita immagini Gravatar',
|
||||
'Information' => 'Informazioni',
|
||||
'Check two factor authentication code' => 'Controlla il codice di autenticazione a due fattori',
|
||||
|
|
@ -768,14 +762,6 @@ return array(
|
|||
// 'When task is moved from first column' => '',
|
||||
// 'When task is moved to last column' => '',
|
||||
// 'Year(s)' => '',
|
||||
// 'Jabber (XMPP)' => '',
|
||||
// 'Send notifications to Jabber' => '',
|
||||
// 'XMPP server address' => '',
|
||||
// 'Jabber domain' => '',
|
||||
// 'Jabber nickname' => '',
|
||||
// 'Multi-user chat room' => '',
|
||||
// 'Help on Jabber integration' => '',
|
||||
// 'The server address must use this format: "tcp://hostname:5222"' => '',
|
||||
// 'Calendar settings' => '',
|
||||
// 'Project calendar view' => '',
|
||||
// 'Project settings' => '',
|
||||
|
|
@ -820,8 +806,6 @@ return array(
|
|||
// '%s moved the task #%d to the swimlane "%s"' => '',
|
||||
// 'Swimlane' => '',
|
||||
// 'Gravatar' => '',
|
||||
// 'Hipchat' => '',
|
||||
// 'Slack' => '',
|
||||
// '%s moved the task %s to the first swimlane' => '',
|
||||
// '%s moved the task %s to the swimlane "%s"' => '',
|
||||
// 'This report contains all subtasks information for the given date range.' => '',
|
||||
|
|
@ -918,7 +902,6 @@ return array(
|
|||
// 'Help on Google authentication' => '',
|
||||
// 'Github Authentication' => '',
|
||||
// 'Help on Github authentication' => '',
|
||||
// 'Channel/Group/User (Optional)' => '',
|
||||
// 'Lead time: ' => '',
|
||||
// 'Cycle time: ' => '',
|
||||
// 'Time spent into each column' => '',
|
||||
|
|
|
|||
|
|
@ -697,15 +697,9 @@ return array(
|
|||
'Reference currency' => '基軸通貨',
|
||||
// 'The currency rate have been added successfully.' => '',
|
||||
'Unable to add this currency rate.' => 'この通貨レートを追加できません。',
|
||||
'Send notifications to a Slack channel' => 'Slack チャンネルに通知を送信',
|
||||
'Webhook URL' => 'Webhook URL',
|
||||
'Help on Slack integration' => 'Slack 連携のヘルプ',
|
||||
'%s remove the assignee of the task %s' => '%s がタスク「%s」の担当を解除しました。',
|
||||
'Send notifications to Hipchat' => 'Hipchat に通知を送信',
|
||||
'API URL' => 'API URL',
|
||||
'Room API ID or name' => 'Room API ID または名前',
|
||||
'Room notification token' => 'Room 通知トークン',
|
||||
'Help on Hipchat integration' => 'Hipchat 連携のヘルプ',
|
||||
'Enable Gravatar images' => 'Gravatar イメージを有効化',
|
||||
'Information' => '情報 ',
|
||||
'Check two factor authentication code' => '2 段認証をチェックする',
|
||||
|
|
@ -768,14 +762,6 @@ return array(
|
|||
// 'When task is moved from first column' => '',
|
||||
// 'When task is moved to last column' => '',
|
||||
// 'Year(s)' => '',
|
||||
// 'Jabber (XMPP)' => '',
|
||||
// 'Send notifications to Jabber' => '',
|
||||
// 'XMPP server address' => '',
|
||||
// 'Jabber domain' => '',
|
||||
// 'Jabber nickname' => '',
|
||||
// 'Multi-user chat room' => '',
|
||||
// 'Help on Jabber integration' => '',
|
||||
// 'The server address must use this format: "tcp://hostname:5222"' => '',
|
||||
// 'Calendar settings' => '',
|
||||
// 'Project calendar view' => '',
|
||||
// 'Project settings' => '',
|
||||
|
|
@ -820,8 +806,6 @@ return array(
|
|||
// '%s moved the task #%d to the swimlane "%s"' => '',
|
||||
// 'Swimlane' => '',
|
||||
// 'Gravatar' => '',
|
||||
// 'Hipchat' => '',
|
||||
// 'Slack' => '',
|
||||
// '%s moved the task %s to the first swimlane' => '',
|
||||
// '%s moved the task %s to the swimlane "%s"' => '',
|
||||
// 'This report contains all subtasks information for the given date range.' => '',
|
||||
|
|
@ -918,7 +902,6 @@ return array(
|
|||
// 'Help on Google authentication' => '',
|
||||
// 'Github Authentication' => '',
|
||||
// 'Help on Github authentication' => '',
|
||||
// 'Channel/Group/User (Optional)' => '',
|
||||
// 'Lead time: ' => '',
|
||||
// 'Cycle time: ' => '',
|
||||
// 'Time spent into each column' => '',
|
||||
|
|
|
|||
|
|
@ -697,15 +697,9 @@ return array(
|
|||
// 'Reference currency' => '',
|
||||
// 'The currency rate have been added successfully.' => '',
|
||||
// 'Unable to add this currency rate.' => '',
|
||||
// 'Send notifications to a Slack channel' => '',
|
||||
// 'Webhook URL' => '',
|
||||
// 'Help on Slack integration' => '',
|
||||
// '%s remove the assignee of the task %s' => '',
|
||||
// 'Send notifications to Hipchat' => '',
|
||||
// 'API URL' => '',
|
||||
// 'Room API ID or name' => '',
|
||||
// 'Room notification token' => '',
|
||||
// 'Help on Hipchat integration' => '',
|
||||
// 'Enable Gravatar images' => '',
|
||||
// 'Information' => '',
|
||||
// 'Check two factor authentication code' => '',
|
||||
|
|
@ -768,14 +762,6 @@ return array(
|
|||
'When task is moved from first column' => 'Når oppgaven er flyttet fra første kolon',
|
||||
'When task is moved to last column' => 'Når oppgaven er flyttet til siste kolonne',
|
||||
'Year(s)' => 'år',
|
||||
// 'Jabber (XMPP)' => '',
|
||||
// 'Send notifications to Jabber' => '',
|
||||
// 'XMPP server address' => '',
|
||||
// 'Jabber domain' => '',
|
||||
// 'Jabber nickname' => '',
|
||||
// 'Multi-user chat room' => '',
|
||||
// 'Help on Jabber integration' => '',
|
||||
// 'The server address must use this format: "tcp://hostname:5222"' => '',
|
||||
'Calendar settings' => 'Kalenderinstillinger',
|
||||
'Project calendar view' => 'Visning prosjektkalender',
|
||||
'Project settings' => 'Prosjektinnstillinger',
|
||||
|
|
@ -820,8 +806,6 @@ return array(
|
|||
// '%s moved the task #%d to the swimlane "%s"' => '',
|
||||
'Swimlane' => 'Svømmebane',
|
||||
// 'Gravatar' => '',
|
||||
// 'Hipchat' => '',
|
||||
// 'Slack' => '',
|
||||
// '%s moved the task %s to the first swimlane' => '',
|
||||
// '%s moved the task %s to the swimlane "%s"' => '',
|
||||
// 'This report contains all subtasks information for the given date range.' => '',
|
||||
|
|
@ -918,7 +902,6 @@ return array(
|
|||
// 'Help on Google authentication' => '',
|
||||
// 'Github Authentication' => '',
|
||||
// 'Help on Github authentication' => '',
|
||||
// 'Channel/Group/User (Optional)' => '',
|
||||
// 'Lead time: ' => '',
|
||||
// 'Cycle time: ' => '',
|
||||
// 'Time spent into each column' => '',
|
||||
|
|
|
|||
|
|
@ -697,15 +697,9 @@ return array(
|
|||
// 'Reference currency' => '',
|
||||
// 'The currency rate have been added successfully.' => '',
|
||||
// 'Unable to add this currency rate.' => '',
|
||||
// 'Send notifications to a Slack channel' => '',
|
||||
// 'Webhook URL' => '',
|
||||
// 'Help on Slack integration' => '',
|
||||
// '%s remove the assignee of the task %s' => '',
|
||||
// 'Send notifications to Hipchat' => '',
|
||||
// 'API URL' => '',
|
||||
// 'Room API ID or name' => '',
|
||||
// 'Room notification token' => '',
|
||||
// 'Help on Hipchat integration' => '',
|
||||
// 'Enable Gravatar images' => '',
|
||||
// 'Information' => '',
|
||||
// 'Check two factor authentication code' => '',
|
||||
|
|
@ -768,14 +762,6 @@ return array(
|
|||
// 'When task is moved from first column' => '',
|
||||
// 'When task is moved to last column' => '',
|
||||
// 'Year(s)' => '',
|
||||
// 'Jabber (XMPP)' => '',
|
||||
// 'Send notifications to Jabber' => '',
|
||||
// 'XMPP server address' => '',
|
||||
// 'Jabber domain' => '',
|
||||
// 'Jabber nickname' => '',
|
||||
// 'Multi-user chat room' => '',
|
||||
// 'Help on Jabber integration' => '',
|
||||
// 'The server address must use this format: "tcp://hostname:5222"' => '',
|
||||
// 'Calendar settings' => '',
|
||||
// 'Project calendar view' => '',
|
||||
// 'Project settings' => '',
|
||||
|
|
@ -820,8 +806,6 @@ return array(
|
|||
// '%s moved the task #%d to the swimlane "%s"' => '',
|
||||
// 'Swimlane' => '',
|
||||
// 'Gravatar' => '',
|
||||
// 'Hipchat' => '',
|
||||
// 'Slack' => '',
|
||||
// '%s moved the task %s to the first swimlane' => '',
|
||||
// '%s moved the task %s to the swimlane "%s"' => '',
|
||||
// 'This report contains all subtasks information for the given date range.' => '',
|
||||
|
|
@ -918,7 +902,6 @@ return array(
|
|||
// 'Help on Google authentication' => '',
|
||||
// 'Github Authentication' => '',
|
||||
// 'Help on Github authentication' => '',
|
||||
// 'Channel/Group/User (Optional)' => '',
|
||||
// 'Lead time: ' => '',
|
||||
// 'Cycle time: ' => '',
|
||||
// 'Time spent into each column' => '',
|
||||
|
|
|
|||
|
|
@ -697,15 +697,9 @@ return array(
|
|||
'Reference currency' => 'Waluta referencyjna',
|
||||
'The currency rate have been added successfully.' => 'Dodano kurs waluty',
|
||||
'Unable to add this currency rate.' => 'Nie można dodać kursu waluty',
|
||||
// 'Send notifications to a Slack channel' => '',
|
||||
// 'Webhook URL' => '',
|
||||
// 'Help on Slack integration' => '',
|
||||
'%s remove the assignee of the task %s' => '%s usunął osobę przypisaną do zadania %s',
|
||||
// 'Send notifications to Hipchat' => '',
|
||||
// 'API URL' => '',
|
||||
// 'Room API ID or name' => '',
|
||||
// 'Room notification token' => '',
|
||||
// 'Help on Hipchat integration' => '',
|
||||
// 'Enable Gravatar images' => '',
|
||||
'Information' => 'Informacje',
|
||||
'Check two factor authentication code' => 'Sprawdź kod weryfikujący',
|
||||
|
|
@ -768,14 +762,6 @@ return array(
|
|||
'When task is moved from first column' => 'Przeniesienie zadania z pierwszej kolumny',
|
||||
'When task is moved to last column' => 'Przeniesienie zadania do ostatniej kolumny',
|
||||
'Year(s)' => 'Lat',
|
||||
// 'Jabber (XMPP)' => '',
|
||||
// 'Send notifications to Jabber' => '',
|
||||
// 'XMPP server address' => '',
|
||||
// 'Jabber domain' => '',
|
||||
// 'Jabber nickname' => '',
|
||||
// 'Multi-user chat room' => '',
|
||||
// 'Help on Jabber integration' => '',
|
||||
// 'The server address must use this format: "tcp://hostname:5222"' => '',
|
||||
'Calendar settings' => 'Ustawienia kalendarza',
|
||||
'Project calendar view' => 'Widok kalendarza projektu',
|
||||
'Project settings' => 'Ustawienia Projektu',
|
||||
|
|
@ -820,8 +806,6 @@ return array(
|
|||
// '%s moved the task #%d to the swimlane "%s"' => '',
|
||||
// 'Swimlane' => '',
|
||||
// 'Gravatar' => '',
|
||||
// 'Hipchat' => '',
|
||||
// 'Slack' => '',
|
||||
// '%s moved the task %s to the first swimlane' => '',
|
||||
// '%s moved the task %s to the swimlane "%s"' => '',
|
||||
// 'This report contains all subtasks information for the given date range.' => '',
|
||||
|
|
@ -918,7 +902,6 @@ return array(
|
|||
// 'Help on Google authentication' => '',
|
||||
// 'Github Authentication' => '',
|
||||
// 'Help on Github authentication' => '',
|
||||
// 'Channel/Group/User (Optional)' => '',
|
||||
// 'Lead time: ' => '',
|
||||
// 'Cycle time: ' => '',
|
||||
// 'Time spent into each column' => '',
|
||||
|
|
|
|||
|
|
@ -697,15 +697,9 @@ return array(
|
|||
'Reference currency' => 'Moeda de Referência',
|
||||
'The currency rate have been added successfully.' => 'A taxa de câmbio foi adicionada com sucesso.',
|
||||
'Unable to add this currency rate.' => 'Impossível de adicionar essa taxa de câmbio.',
|
||||
'Send notifications to a Slack channel' => 'Enviar as notificações em um canal Slack',
|
||||
'Webhook URL' => 'URL do webhook',
|
||||
'Help on Slack integration' => 'Ajuda sobre integração com o Slack',
|
||||
'%s remove the assignee of the task %s' => '%s removeu a pessoa designada para a tarefa %s',
|
||||
'Send notifications to Hipchat' => 'Enviar as notificações para o Hipchat',
|
||||
'API URL' => 'URL da API',
|
||||
'Room API ID or name' => 'Nome ou ID da sala de discussão',
|
||||
'Room notification token' => 'Código de segurança da sala de discussão',
|
||||
'Help on Hipchat integration' => 'Ajuda sobre integração com o Hipchat',
|
||||
'Enable Gravatar images' => 'Ativar imagens do Gravatar',
|
||||
'Information' => 'Informações',
|
||||
'Check two factor authentication code' => 'Verificação do código de autenticação à fator duplo',
|
||||
|
|
@ -768,14 +762,6 @@ return array(
|
|||
'When task is moved from first column' => 'Quando a tarefa é movida fora da primeira coluna',
|
||||
'When task is moved to last column' => 'Quando a tarefa é movida para a última coluna',
|
||||
'Year(s)' => 'Ano(s)',
|
||||
'Jabber (XMPP)' => 'Jabber (XMPP)',
|
||||
'Send notifications to Jabber' => 'Enviar notificações para o Jabber',
|
||||
'XMPP server address' => 'Endereço do servidor XMPP',
|
||||
'Jabber domain' => 'Nome de domínio Jabber',
|
||||
'Jabber nickname' => 'Apelido Jabber',
|
||||
'Multi-user chat room' => 'Sala de chat multi-usuário',
|
||||
'Help on Jabber integration' => 'Ajuda sobre integração com o Jabber',
|
||||
'The server address must use this format: "tcp://hostname:5222"' => 'O endereço do servidor deve usar o seguinte formato: "tcp://hostname:5222"',
|
||||
'Calendar settings' => 'Configurações do calendário',
|
||||
'Project calendar view' => 'Vista em modo projeto do calendário',
|
||||
'Project settings' => 'Configurações dos projetos',
|
||||
|
|
@ -820,8 +806,6 @@ return array(
|
|||
'%s moved the task #%d to the swimlane "%s"' => '%s moveu a tarefa #%d para a swimlane "%s"',
|
||||
'Swimlane' => 'Swimlane',
|
||||
'Gravatar' => 'Gravatar',
|
||||
'Hipchat' => 'Hipchat',
|
||||
'Slack' => 'Slack',
|
||||
'%s moved the task %s to the first swimlane' => '%s moveu a tarefa %s para a primeira swimlane',
|
||||
'%s moved the task %s to the swimlane "%s"' => '%s moveu a tarefa %s para a swimlane "%s"',
|
||||
'This report contains all subtasks information for the given date range.' => 'Este relatório contém informações de todas as sub-tarefas para o período selecionado.',
|
||||
|
|
@ -918,7 +902,6 @@ return array(
|
|||
'Help on Google authentication' => 'Ajuda com a autenticação Google',
|
||||
'Github Authentication' => 'Autenticação Github',
|
||||
'Help on Github authentication' => 'Ajuda com a autenticação Github',
|
||||
'Channel/Group/User (Optional)' => 'Canal/Grupo/Utilizador (Opcional)',
|
||||
'Lead time: ' => 'Lead time: ',
|
||||
'Cycle time: ' => 'Cycle time: ',
|
||||
'Time spent into each column' => 'Tempo gasto em cada coluna',
|
||||
|
|
|
|||
|
|
@ -697,15 +697,9 @@ return array(
|
|||
'Reference currency' => 'Moeda de Referência',
|
||||
'The currency rate have been added successfully.' => 'A taxa de câmbio foi adicionada com sucesso.',
|
||||
'Unable to add this currency rate.' => 'Impossível adicionar essa taxa de câmbio.',
|
||||
'Send notifications to a Slack channel' => 'Enviar as notificações por canal Slack',
|
||||
'Webhook URL' => 'URL do webhook',
|
||||
'Help on Slack integration' => 'Ajuda na integração com o Slack',
|
||||
'%s remove the assignee of the task %s' => '%s removeu a pessoa assignada à tarefa %s',
|
||||
'Send notifications to Hipchat' => 'Enviar as notificações para o Hipchat',
|
||||
'API URL' => 'URL da API',
|
||||
'Room API ID or name' => 'Nome ou ID da sala de discussão',
|
||||
'Room notification token' => 'Código de segurança da sala de discussão',
|
||||
'Help on Hipchat integration' => 'Ajuda na integração com o Hipchat',
|
||||
'Enable Gravatar images' => 'Activar imagem Gravatar',
|
||||
'Information' => 'Informações',
|
||||
'Check two factor authentication code' => 'Verificação do código de autenticação com factor duplo',
|
||||
|
|
@ -768,14 +762,6 @@ return array(
|
|||
'When task is moved from first column' => 'Quando a tarefa é movida fora da primeira coluna',
|
||||
'When task is moved to last column' => 'Quando a tarefa é movida para a última coluna',
|
||||
'Year(s)' => 'Ano(s)',
|
||||
'Jabber (XMPP)' => 'Jabber (XMPP)',
|
||||
'Send notifications to Jabber' => 'Enviar notificações para o Jabber',
|
||||
'XMPP server address' => 'Endereço do servidor XMPP',
|
||||
'Jabber domain' => 'Nome de domínio Jabber',
|
||||
'Jabber nickname' => 'Apelido Jabber',
|
||||
'Multi-user chat room' => 'Sala de chat multi-utilizador',
|
||||
'Help on Jabber integration' => 'Ajuda na integração com Jabber',
|
||||
'The server address must use this format: "tcp://hostname:5222"' => 'O endereço do servidor deve usar o seguinte formato: "tcp://hostname:5222"',
|
||||
'Calendar settings' => 'Configurações do calendário',
|
||||
'Project calendar view' => 'Vista em modo projecto do calendário',
|
||||
'Project settings' => 'Configurações dos projectos',
|
||||
|
|
@ -820,8 +806,6 @@ return array(
|
|||
'%s moved the task #%d to the swimlane "%s"' => '%s moveu a tarefa n° %d no swimlane "%s"',
|
||||
'Swimlane' => 'Swimlane',
|
||||
'Gravatar' => 'Gravatar',
|
||||
'Hipchat' => 'Hipchat',
|
||||
'Slack' => 'Slack',
|
||||
'%s moved the task %s to the first swimlane' => '%s moveu a tarefa %s no primeiro swimlane',
|
||||
'%s moved the task %s to the swimlane "%s"' => '%s moveu a tarefa %s no swimlane "%s"',
|
||||
'This report contains all subtasks information for the given date range.' => 'Este relatório contém informações de todas as sub-tarefas para o período selecionado.',
|
||||
|
|
@ -918,7 +902,6 @@ return array(
|
|||
'Help on Google authentication' => 'Ajuda com autenticação Google',
|
||||
'Github Authentication' => 'Autenticação Github',
|
||||
'Help on Github authentication' => 'Ajuda com autenticação Github',
|
||||
'Channel/Group/User (Optional)' => 'Canal/Grupo/Utilizador (Opcional)',
|
||||
'Lead time: ' => 'Tempo de Espera: ',
|
||||
'Cycle time: ' => 'Tempo de Ciclo: ',
|
||||
'Time spent into each column' => 'Tempo gasto em cada coluna',
|
||||
|
|
|
|||
|
|
@ -697,15 +697,9 @@ return array(
|
|||
'Reference currency' => 'Справочник валют',
|
||||
'The currency rate have been added successfully.' => 'Курс валюты был успешно добавлен.',
|
||||
'Unable to add this currency rate.' => 'Невозможно добавить этот курс валюты.',
|
||||
'Send notifications to a Slack channel' => 'Отправлять уведомления в канал Slack',
|
||||
'Webhook URL' => 'Webhook URL',
|
||||
'Help on Slack integration' => 'Помощь по интеграции Slack',
|
||||
'%s remove the assignee of the task %s' => '%s удалить назначенную задачу %s',
|
||||
'Send notifications to Hipchat' => 'Отправлять уведомления в Hipchat',
|
||||
'API URL' => 'API URL',
|
||||
'Room API ID or name' => 'API ID комнаты или имя',
|
||||
'Room notification token' => 'Ключь комнаты для уведомлений',
|
||||
'Help on Hipchat integration' => 'Помощь по интеграции Hipchat',
|
||||
'Enable Gravatar images' => 'Включить Gravatar изображения',
|
||||
'Information' => 'Информация',
|
||||
'Check two factor authentication code' => 'Проверка кода двухфакторной авторизации',
|
||||
|
|
@ -768,14 +762,6 @@ return array(
|
|||
'When task is moved from first column' => 'Когда задача перемещается из первой колонки',
|
||||
'When task is moved to last column' => 'Когда задача перемещается в последнюю колонку',
|
||||
'Year(s)' => 'Год(а)',
|
||||
'Jabber (XMPP)' => 'Jabber (XMPP)',
|
||||
'Send notifications to Jabber' => 'Отправлять уведомления в Jabber',
|
||||
'XMPP server address' => 'Адрес Jabber сервера',
|
||||
'Jabber domain' => 'Домен Jabber',
|
||||
'Jabber nickname' => 'Имя пользователя Jabber',
|
||||
'Multi-user chat room' => 'Многопользовательский чат',
|
||||
'Help on Jabber integration' => 'Помощь по интеграции Jabber',
|
||||
'The server address must use this format: "tcp://hostname:5222"' => 'Адрес сервера должен быть в формате: tcp://hostname:5222',
|
||||
'Calendar settings' => 'Настройки календаря',
|
||||
'Project calendar view' => 'Вид календаря проекта',
|
||||
'Project settings' => 'Настройки проекта',
|
||||
|
|
@ -820,8 +806,6 @@ return array(
|
|||
'%s moved the task #%d to the swimlane "%s"' => '%s задач перемещено #%d в дорожке "%s"',
|
||||
'Swimlane' => 'Дорожки',
|
||||
'Gravatar' => 'Граватар',
|
||||
'Hipchat' => 'Hipchat',
|
||||
'Slack' => 'Slack',
|
||||
// '%s moved the task %s to the first swimlane' => '',
|
||||
// '%s moved the task %s to the swimlane "%s"' => '',
|
||||
'This report contains all subtasks information for the given date range.' => 'Этот отчет содержит всю информацию подзадач в заданном диапазоне дат.',
|
||||
|
|
@ -918,7 +902,6 @@ return array(
|
|||
'Help on Google authentication' => 'Помощь в авторизации Google',
|
||||
'Github Authentication' => 'Авторизация Github',
|
||||
'Help on Github authentication' => 'Помощь в авторизации Github',
|
||||
'Channel/Group/User (Optional)' => 'Канал/Группа/Пользователь (опционально)',
|
||||
'Lead time: ' => 'Время выполнения:',
|
||||
'Cycle time: ' => 'Время цикла:',
|
||||
'Time spent into each column' => 'Время, проведенное в каждой колонке',
|
||||
|
|
|
|||
|
|
@ -697,15 +697,9 @@ return array(
|
|||
// 'Reference currency' => '',
|
||||
// 'The currency rate have been added successfully.' => '',
|
||||
// 'Unable to add this currency rate.' => '',
|
||||
// 'Send notifications to a Slack channel' => '',
|
||||
// 'Webhook URL' => '',
|
||||
// 'Help on Slack integration' => '',
|
||||
// '%s remove the assignee of the task %s' => '',
|
||||
// 'Send notifications to Hipchat' => '',
|
||||
// 'API URL' => '',
|
||||
// 'Room API ID or name' => '',
|
||||
// 'Room notification token' => '',
|
||||
// 'Help on Hipchat integration' => '',
|
||||
// 'Enable Gravatar images' => '',
|
||||
// 'Information' => '',
|
||||
// 'Check two factor authentication code' => '',
|
||||
|
|
@ -768,14 +762,6 @@ return array(
|
|||
// 'When task is moved from first column' => '',
|
||||
// 'When task is moved to last column' => '',
|
||||
// 'Year(s)' => '',
|
||||
// 'Jabber (XMPP)' => '',
|
||||
// 'Send notifications to Jabber' => '',
|
||||
// 'XMPP server address' => '',
|
||||
// 'Jabber domain' => '',
|
||||
// 'Jabber nickname' => '',
|
||||
// 'Multi-user chat room' => '',
|
||||
// 'Help on Jabber integration' => '',
|
||||
// 'The server address must use this format: "tcp://hostname:5222"' => '',
|
||||
// 'Calendar settings' => '',
|
||||
// 'Project calendar view' => '',
|
||||
// 'Project settings' => '',
|
||||
|
|
@ -820,8 +806,6 @@ return array(
|
|||
// '%s moved the task #%d to the swimlane "%s"' => '',
|
||||
// 'Swimlane' => '',
|
||||
// 'Gravatar' => '',
|
||||
// 'Hipchat' => '',
|
||||
// 'Slack' => '',
|
||||
// '%s moved the task %s to the first swimlane' => '',
|
||||
// '%s moved the task %s to the swimlane "%s"' => '',
|
||||
// 'This report contains all subtasks information for the given date range.' => '',
|
||||
|
|
@ -918,7 +902,6 @@ return array(
|
|||
// 'Help on Google authentication' => '',
|
||||
// 'Github Authentication' => '',
|
||||
// 'Help on Github authentication' => '',
|
||||
// 'Channel/Group/User (Optional)' => '',
|
||||
// 'Lead time: ' => '',
|
||||
// 'Cycle time: ' => '',
|
||||
// 'Time spent into each column' => '',
|
||||
|
|
|
|||
|
|
@ -697,15 +697,9 @@ return array(
|
|||
'Reference currency' => 'Referensvaluta',
|
||||
'The currency rate have been added successfully.' => 'Valutakursen har lagts till.',
|
||||
'Unable to add this currency rate.' => 'Kunde inte lägga till valutakursen.',
|
||||
'Send notifications to a Slack channel' => 'Skicka notiser till en Slack kanal',
|
||||
'Webhook URL' => 'Webhook URL',
|
||||
'Help on Slack integration' => 'Hjälp för Slack integration',
|
||||
'%s remove the assignee of the task %s' => '%s ta bort tilldelningen av uppgiften %s',
|
||||
'Send notifications to Hipchat' => 'Skicka notiser till Hipchat',
|
||||
'API URL' => 'API URL',
|
||||
'Room API ID or name' => 'Room API ID eller namn',
|
||||
'Room notification token' => 'Room notistoken',
|
||||
'Help on Hipchat integration' => 'Hjälp för Hipchat integration',
|
||||
'Enable Gravatar images' => 'Aktivera Gravatar bilder',
|
||||
'Information' => 'Information',
|
||||
'Check two factor authentication code' => 'Kolla tvåfaktorsverifieringskod',
|
||||
|
|
@ -768,14 +762,6 @@ return array(
|
|||
'When task is moved from first column' => 'När uppgiften flyttas från första kolumnen',
|
||||
'When task is moved to last column' => 'När uppgiften flyttas till sista kolumnen',
|
||||
'Year(s)' => 'År',
|
||||
'Jabber (XMPP)' => 'Jabber (XMPP)',
|
||||
'Send notifications to Jabber' => 'Skicka notiser till Jabber',
|
||||
'XMPP server address' => 'XMPP serveradress',
|
||||
'Jabber domain' => 'Jabber domän',
|
||||
'Jabber nickname' => 'Jabber smeknamn',
|
||||
'Multi-user chat room' => 'Multi-user chatrum',
|
||||
'Help on Jabber integration' => 'Hjälp för Jabber integration',
|
||||
'The server address must use this format: "tcp://hostname:5222"' => 'Serveradressen måste använda detta format: "tcp://hostname:5222"',
|
||||
'Calendar settings' => 'Inställningar för kalendern',
|
||||
'Project calendar view' => 'Projektkalendervy',
|
||||
'Project settings' => 'Projektinställningar',
|
||||
|
|
@ -820,8 +806,6 @@ return array(
|
|||
'%s moved the task #%d to the swimlane "%s"' => '%s flyttade uppgiften #%d till swimlane "%s"',
|
||||
'Swimlane' => 'Swimlane',
|
||||
'Gravatar' => 'Gravatar',
|
||||
'Hipchat' => 'Hipchat',
|
||||
'Slack' => 'Slack',
|
||||
'%s moved the task %s to the first swimlane' => '%s flyttade uppgiften %s till första swimlane',
|
||||
'%s moved the task %s to the swimlane "%s"' => '%s flyttade uppgiften %s till swimlane "%s"',
|
||||
'This report contains all subtasks information for the given date range.' => 'Denna rapport innehåller all deluppgiftsinformation för det givna datumintervallet.',
|
||||
|
|
@ -918,7 +902,6 @@ return array(
|
|||
'Help on Google authentication' => 'Hjälp för Google autentisering',
|
||||
'Github Authentication' => 'Github autentisering',
|
||||
'Help on Github authentication' => 'Hjälp för Github autentisering',
|
||||
'Channel/Group/User (Optional)' => 'Kanal/Grupp/Användare (valfri)',
|
||||
'Lead time: ' => 'Ledtid',
|
||||
'Cycle time: ' => 'Cykeltid',
|
||||
'Time spent into each column' => 'Tidsåtgång per kolumn',
|
||||
|
|
|
|||
|
|
@ -697,15 +697,9 @@ return array(
|
|||
// 'Reference currency' => '',
|
||||
// 'The currency rate have been added successfully.' => '',
|
||||
// 'Unable to add this currency rate.' => '',
|
||||
'Send notifications to a Slack channel' => 'ส่งการแจ้งเตือนไปทาง Slack channel',
|
||||
// 'Webhook URL' => '',
|
||||
// 'Help on Slack integration' => '',
|
||||
// '%s remove the assignee of the task %s' => '',
|
||||
// 'Send notifications to Hipchat' => '',
|
||||
// 'API URL' => '',
|
||||
// 'Room API ID or name' => '',
|
||||
// 'Room notification token' => '',
|
||||
// 'Help on Hipchat integration' => '',
|
||||
'Enable Gravatar images' => 'สามารถใช้งานภาพ Gravatar',
|
||||
'Information' => 'ข้อมูลสารสนเทศ',
|
||||
// 'Check two factor authentication code' => '',
|
||||
|
|
@ -768,14 +762,6 @@ return array(
|
|||
'When task is moved from first column' => 'เมื่องานถูกย้ายจากคอลัมน์แรก',
|
||||
'When task is moved to last column' => 'เมื่องานถูกย้ายไปคอลัมน์สุดท้าย',
|
||||
'Year(s)' => 'ปี',
|
||||
// 'Jabber (XMPP)' => '',
|
||||
// 'Send notifications to Jabber' => '',
|
||||
// 'XMPP server address' => '',
|
||||
// 'Jabber domain' => '',
|
||||
// 'Jabber nickname' => '',
|
||||
// 'Multi-user chat room' => '',
|
||||
// 'Help on Jabber integration' => '',
|
||||
// 'The server address must use this format: "tcp://hostname:5222"' => '',
|
||||
'Calendar settings' => 'ตั้งค่าปฏิทิน',
|
||||
'Project calendar view' => 'มุมมองปฏิทินของโปรเจค',
|
||||
'Project settings' => 'ตั้งค่าโปรเจค',
|
||||
|
|
@ -820,8 +806,6 @@ return array(
|
|||
// '%s moved the task #%d to the swimlane "%s"' => '',
|
||||
// 'Swimlane' => '',
|
||||
// 'Gravatar' => '',
|
||||
// 'Hipchat' => '',
|
||||
// 'Slack' => '',
|
||||
// '%s moved the task %s to the first swimlane' => '',
|
||||
// '%s moved the task %s to the swimlane "%s"' => '',
|
||||
// 'This report contains all subtasks information for the given date range.' => '',
|
||||
|
|
@ -918,7 +902,6 @@ return array(
|
|||
// 'Help on Google authentication' => '',
|
||||
// 'Github Authentication' => '',
|
||||
// 'Help on Github authentication' => '',
|
||||
// 'Channel/Group/User (Optional)' => '',
|
||||
// 'Lead time: ' => '',
|
||||
// 'Cycle time: ' => '',
|
||||
// 'Time spent into each column' => '',
|
||||
|
|
|
|||
|
|
@ -697,15 +697,9 @@ return array(
|
|||
// 'Reference currency' => '',
|
||||
// 'The currency rate have been added successfully.' => '',
|
||||
// 'Unable to add this currency rate.' => '',
|
||||
// 'Send notifications to a Slack channel' => '',
|
||||
// 'Webhook URL' => '',
|
||||
// 'Help on Slack integration' => '',
|
||||
// '%s remove the assignee of the task %s' => '',
|
||||
// 'Send notifications to Hipchat' => '',
|
||||
// 'API URL' => '',
|
||||
// 'Room API ID or name' => '',
|
||||
// 'Room notification token' => '',
|
||||
// 'Help on Hipchat integration' => '',
|
||||
// 'Enable Gravatar images' => '',
|
||||
// 'Information' => '',
|
||||
// 'Check two factor authentication code' => '',
|
||||
|
|
@ -768,14 +762,6 @@ return array(
|
|||
// 'When task is moved from first column' => '',
|
||||
// 'When task is moved to last column' => '',
|
||||
// 'Year(s)' => '',
|
||||
// 'Jabber (XMPP)' => '',
|
||||
// 'Send notifications to Jabber' => '',
|
||||
// 'XMPP server address' => '',
|
||||
// 'Jabber domain' => '',
|
||||
// 'Jabber nickname' => '',
|
||||
// 'Multi-user chat room' => '',
|
||||
// 'Help on Jabber integration' => '',
|
||||
// 'The server address must use this format: "tcp://hostname:5222"' => '',
|
||||
// 'Calendar settings' => '',
|
||||
// 'Project calendar view' => '',
|
||||
// 'Project settings' => '',
|
||||
|
|
@ -820,8 +806,6 @@ return array(
|
|||
// '%s moved the task #%d to the swimlane "%s"' => '',
|
||||
// 'Swimlane' => '',
|
||||
// 'Gravatar' => '',
|
||||
// 'Hipchat' => '',
|
||||
// 'Slack' => '',
|
||||
// '%s moved the task %s to the first swimlane' => '',
|
||||
// '%s moved the task %s to the swimlane "%s"' => '',
|
||||
// 'This report contains all subtasks information for the given date range.' => '',
|
||||
|
|
@ -918,7 +902,6 @@ return array(
|
|||
// 'Help on Google authentication' => '',
|
||||
// 'Github Authentication' => '',
|
||||
// 'Help on Github authentication' => '',
|
||||
// 'Channel/Group/User (Optional)' => '',
|
||||
// 'Lead time: ' => '',
|
||||
// 'Cycle time: ' => '',
|
||||
// 'Time spent into each column' => '',
|
||||
|
|
|
|||
|
|
@ -697,15 +697,9 @@ return array(
|
|||
'Reference currency' => '参考货币',
|
||||
'The currency rate have been added successfully.' => '成功添加汇率。',
|
||||
'Unable to add this currency rate.' => '无法添加此汇率',
|
||||
'Send notifications to a Slack channel' => '发送通知到 Slack 频道',
|
||||
'Webhook URL' => '网络钩子 URL',
|
||||
'Help on Slack integration' => 'Slack 整合帮助',
|
||||
'%s remove the assignee of the task %s' => '%s删除了任务%s的负责人',
|
||||
'Send notifications to Hipchat' => '发送通知到 Hipchat',
|
||||
'API URL' => 'API URL',
|
||||
'Room API ID or name' => '房间 API ID 或名称',
|
||||
'Room notification token' => '房间通知令牌',
|
||||
'Help on Hipchat integration' => 'Hipchat 整合帮助',
|
||||
'Enable Gravatar images' => '启用 Gravatar 图像',
|
||||
'Information' => '信息',
|
||||
'Check two factor authentication code' => '检查双重认证码',
|
||||
|
|
@ -768,14 +762,6 @@ return array(
|
|||
// 'When task is moved from first column' => '',
|
||||
// 'When task is moved to last column' => '',
|
||||
// 'Year(s)' => '',
|
||||
// 'Jabber (XMPP)' => '',
|
||||
// 'Send notifications to Jabber' => '',
|
||||
// 'XMPP server address' => '',
|
||||
// 'Jabber domain' => '',
|
||||
// 'Jabber nickname' => '',
|
||||
'Multi-user chat room' => '多用户聊天室',
|
||||
// 'Help on Jabber integration' => '',
|
||||
// 'The server address must use this format: "tcp://hostname:5222"' => '',
|
||||
'Calendar settings' => '日程设置',
|
||||
// 'Project calendar view' => '',
|
||||
'Project settings' => '项目设置',
|
||||
|
|
@ -820,8 +806,6 @@ return array(
|
|||
// '%s moved the task #%d to the swimlane "%s"' => '',
|
||||
// 'Swimlane' => '',
|
||||
// 'Gravatar' => '',
|
||||
// 'Hipchat' => '',
|
||||
// 'Slack' => '',
|
||||
// '%s moved the task %s to the first swimlane' => '',
|
||||
// '%s moved the task %s to the swimlane "%s"' => '',
|
||||
// 'This report contains all subtasks information for the given date range.' => '',
|
||||
|
|
@ -918,7 +902,6 @@ return array(
|
|||
// 'Help on Google authentication' => '',
|
||||
// 'Github Authentication' => '',
|
||||
// 'Help on Github authentication' => '',
|
||||
// 'Channel/Group/User (Optional)' => '',
|
||||
// 'Lead time: ' => '',
|
||||
// 'Cycle time: ' => '',
|
||||
// 'Time spent into each column' => '',
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ class Acl extends Base
|
|||
'column' => '*',
|
||||
'export' => '*',
|
||||
'taskimport' => '*',
|
||||
'project' => array('edit', 'update', 'share', 'integration', 'users', 'alloweverybody', 'allow', 'setowner', 'revoke', 'duplicate', 'disable', 'enable'),
|
||||
'project' => array('edit', 'update', 'share', 'integrations', 'notifications', 'users', 'alloweverybody', 'allow', 'setowner', 'revoke', 'duplicate', 'disable', 'enable'),
|
||||
'swimlane' => '*',
|
||||
'gantt' => array('project', 'savetaskdate', 'task', 'savetask'),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,142 @@
|
|||
<?php
|
||||
|
||||
namespace Kanboard\Model;
|
||||
|
||||
/**
|
||||
* Notification
|
||||
*
|
||||
* @package model
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class Notification extends Base
|
||||
{
|
||||
/**
|
||||
* Get the event title with author
|
||||
*
|
||||
* @access public
|
||||
* @param string $event_author
|
||||
* @param string $event_name
|
||||
* @param array $event_data
|
||||
* @return string
|
||||
*/
|
||||
public function getTitleWithAuthor($event_author, $event_name, array $event_data)
|
||||
{
|
||||
switch ($event_name) {
|
||||
case Task::EVENT_ASSIGNEE_CHANGE:
|
||||
$assignee = $event_data['task']['assignee_name'] ?: $event_data['task']['assignee_username'];
|
||||
|
||||
if (! empty($assignee)) {
|
||||
return e('%s change the assignee of the task #%d to %s', $event_author, $event_data['task']['id'], $assignee);
|
||||
}
|
||||
|
||||
return e('%s remove the assignee of the task %s', $event_author, e('#%d', $event_data['task']['id']));
|
||||
case Task::EVENT_UPDATE:
|
||||
return e('%s updated the task #%d', $event_author, $event_data['task']['id']);
|
||||
case Task::EVENT_CREATE:
|
||||
return e('%s created the task #%d', $event_author, $event_data['task']['id']);
|
||||
case Task::EVENT_CLOSE:
|
||||
return e('%s closed the task #%d', $event_author, $event_data['task']['id']);
|
||||
case Task::EVENT_OPEN:
|
||||
return e('%s open the task #%d', $event_author, $event_data['task']['id']);
|
||||
case Task::EVENT_MOVE_COLUMN:
|
||||
return e(
|
||||
'%s moved the task #%d to the column "%s"',
|
||||
$event_author,
|
||||
$event_data['task']['id'],
|
||||
$event_data['task']['column_title']
|
||||
);
|
||||
case Task::EVENT_MOVE_POSITION:
|
||||
return e(
|
||||
'%s moved the task #%d to the position %d in the column "%s"',
|
||||
$event_author,
|
||||
$event_data['task']['id'],
|
||||
$event_data['task']['position'],
|
||||
$event_data['task']['column_title']
|
||||
);
|
||||
case Task::EVENT_MOVE_SWIMLANE:
|
||||
if ($event_data['task']['swimlane_id'] == 0) {
|
||||
return e('%s moved the task #%d to the first swimlane', $event_author, $event_data['task']['id']);
|
||||
}
|
||||
|
||||
return e(
|
||||
'%s moved the task #%d to the swimlane "%s"',
|
||||
$event_author,
|
||||
$event_data['task']['id'],
|
||||
$event_data['task']['swimlane_name']
|
||||
);
|
||||
case Subtask::EVENT_UPDATE:
|
||||
return e('%s updated a subtask for the task #%d', $event_author, $event_data['task']['id']);
|
||||
case Subtask::EVENT_CREATE:
|
||||
return e('%s created a subtask for the task #%d', $event_author, $event_data['task']['id']);
|
||||
case Comment::EVENT_UPDATE:
|
||||
return e('%s updated a comment on the task #%d', $event_author, $event_data['task']['id']);
|
||||
case Comment::EVENT_CREATE:
|
||||
return e('%s commented on the task #%d', $event_author, $event_data['task']['id']);
|
||||
case File::EVENT_CREATE:
|
||||
return e('%s attached a file to the task #%d', $event_author, $event_data['task']['id']);
|
||||
default:
|
||||
return e('Notification');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the event title without author
|
||||
*
|
||||
* @access public
|
||||
* @param string $event_name
|
||||
* @param array $event_data
|
||||
* @return string
|
||||
*/
|
||||
public function getTitleWithoutAuthor($event_name, array $event_data)
|
||||
{
|
||||
switch ($event_name) {
|
||||
case File::EVENT_CREATE:
|
||||
$title = e('New attachment on task #%d: %s', $event_data['file']['task_id'], $event_data['file']['name']);
|
||||
break;
|
||||
case Comment::EVENT_CREATE:
|
||||
$title = e('New comment on task #%d', $event_data['comment']['task_id']);
|
||||
break;
|
||||
case Comment::EVENT_UPDATE:
|
||||
$title = e('Comment updated on task #%d', $event_data['comment']['task_id']);
|
||||
break;
|
||||
case Subtask::EVENT_CREATE:
|
||||
$title = e('New subtask on task #%d', $event_data['subtask']['task_id']);
|
||||
break;
|
||||
case Subtask::EVENT_UPDATE:
|
||||
$title = e('Subtask updated on task #%d', $event_data['subtask']['task_id']);
|
||||
break;
|
||||
case Task::EVENT_CREATE:
|
||||
$title = e('New task #%d: %s', $event_data['task']['id'], $event_data['task']['title']);
|
||||
break;
|
||||
case Task::EVENT_UPDATE:
|
||||
$title = e('Task updated #%d', $event_data['task']['id']);
|
||||
break;
|
||||
case Task::EVENT_CLOSE:
|
||||
$title = e('Task #%d closed', $event_data['task']['id']);
|
||||
break;
|
||||
case Task::EVENT_OPEN:
|
||||
$title = e('Task #%d opened', $event_data['task']['id']);
|
||||
break;
|
||||
case Task::EVENT_MOVE_COLUMN:
|
||||
$title = e('Column changed for task #%d', $event_data['task']['id']);
|
||||
break;
|
||||
case Task::EVENT_MOVE_POSITION:
|
||||
$title = e('New position for task #%d', $event_data['task']['id']);
|
||||
break;
|
||||
case Task::EVENT_MOVE_SWIMLANE:
|
||||
$title = e('Swimlane changed for task #%d', $event_data['task']['id']);
|
||||
break;
|
||||
case Task::EVENT_ASSIGNEE_CHANGE:
|
||||
$title = e('Assignee changed on task #%d', $event_data['task']['id']);
|
||||
break;
|
||||
case Task::EVENT_OVERDUE:
|
||||
$nb = count($event_data['tasks']);
|
||||
$title = $nb > 1 ? e('%d overdue tasks', $nb) : e('Task #%d is overdue', $event_data['tasks'][0]['id']);
|
||||
break;
|
||||
default:
|
||||
$title = e('Notification');
|
||||
}
|
||||
|
||||
return $title;
|
||||
}
|
||||
}
|
||||
|
|
@ -108,4 +108,20 @@ abstract class NotificationType extends Base
|
|||
{
|
||||
return $this->hiddens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep only loaded notification types
|
||||
*
|
||||
* @access public
|
||||
* @param string[] $types
|
||||
* @return array
|
||||
*/
|
||||
public function filterTypes(array $types)
|
||||
{
|
||||
$classes = $this->classes;
|
||||
|
||||
return array_filter($types, function($type) use ($classes) {
|
||||
return isset($classes[$type]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ class ProjectActivity extends Base
|
|||
unset($event['data']);
|
||||
|
||||
$event['author'] = $event['author_name'] ?: $event['author_username'];
|
||||
$event['event_title'] = $this->getTitle($event);
|
||||
$event['event_title'] = $this->notification->getTitleWithAuthor($event['author'], $event['event_name'], $event);
|
||||
$event['event_content'] = $this->getContent($event);
|
||||
}
|
||||
|
||||
|
|
@ -195,56 +195,6 @@ class ProjectActivity extends Base
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the event title (translated)
|
||||
*
|
||||
* @access public
|
||||
* @param array $event Event properties
|
||||
* @return string
|
||||
*/
|
||||
public function getTitle(array $event)
|
||||
{
|
||||
switch ($event['event_name']) {
|
||||
case Task::EVENT_ASSIGNEE_CHANGE:
|
||||
$assignee = $event['task']['assignee_name'] ?: $event['task']['assignee_username'];
|
||||
|
||||
if (! empty($assignee)) {
|
||||
return t('%s change the assignee of the task #%d to %s', $event['author'], $event['task']['id'], $assignee);
|
||||
}
|
||||
|
||||
return t('%s remove the assignee of the task %s', $event['author'], e('#%d', $event['task']['id']));
|
||||
case Task::EVENT_UPDATE:
|
||||
return t('%s updated the task #%d', $event['author'], $event['task']['id']);
|
||||
case Task::EVENT_CREATE:
|
||||
return t('%s created the task #%d', $event['author'], $event['task']['id']);
|
||||
case Task::EVENT_CLOSE:
|
||||
return t('%s closed the task #%d', $event['author'], $event['task']['id']);
|
||||
case Task::EVENT_OPEN:
|
||||
return t('%s open the task #%d', $event['author'], $event['task']['id']);
|
||||
case Task::EVENT_MOVE_COLUMN:
|
||||
return t('%s moved the task #%d to the column "%s"', $event['author'], $event['task']['id'], $event['task']['column_title']);
|
||||
case Task::EVENT_MOVE_POSITION:
|
||||
return t('%s moved the task #%d to the position %d in the column "%s"', $event['author'], $event['task']['id'], $event['task']['position'], $event['task']['column_title']);
|
||||
case Task::EVENT_MOVE_SWIMLANE:
|
||||
if ($event['task']['swimlane_id'] == 0) {
|
||||
return t('%s moved the task #%d to the first swimlane', $event['author'], $event['task']['id']);
|
||||
}
|
||||
return t('%s moved the task #%d to the swimlane "%s"', $event['author'], $event['task']['id'], $event['task']['swimlane_name']);
|
||||
case Subtask::EVENT_UPDATE:
|
||||
return t('%s updated a subtask for the task #%d', $event['author'], $event['task']['id']);
|
||||
case Subtask::EVENT_CREATE:
|
||||
return t('%s created a subtask for the task #%d', $event['author'], $event['task']['id']);
|
||||
case Comment::EVENT_UPDATE:
|
||||
return t('%s updated a comment on the task #%d', $event['author'], $event['task']['id']);
|
||||
case Comment::EVENT_CREATE:
|
||||
return t('%s commented on the task #%d', $event['author'], $event['task']['id']);
|
||||
case File::EVENT_CREATE:
|
||||
return t('%s attached a file to the task #%d', $event['author'], $event['task']['id']);
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode event data, supports unserialize() and json_decode()
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,66 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Kanboard\Model;
|
||||
|
||||
/**
|
||||
* Project integration
|
||||
*
|
||||
* @package model
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class ProjectIntegration extends Base
|
||||
{
|
||||
/**
|
||||
* SQL table name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const TABLE = 'project_integrations';
|
||||
|
||||
/**
|
||||
* Get all parameters for a project
|
||||
*
|
||||
* @access public
|
||||
* @param integer $project_id
|
||||
* @return array
|
||||
*/
|
||||
public function getParameters($project_id)
|
||||
{
|
||||
return $this->db->table(self::TABLE)->eq('project_id', $project_id)->findOne() ?: array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Save parameters for a project
|
||||
*
|
||||
* @access public
|
||||
* @param integer $project_id
|
||||
* @param array $values
|
||||
* @return boolean
|
||||
*/
|
||||
public function saveParameters($project_id, array $values)
|
||||
{
|
||||
if ($this->db->table(self::TABLE)->eq('project_id', $project_id)->exists()) {
|
||||
return $this->db->table(self::TABLE)->eq('project_id', $project_id)->update($values);
|
||||
}
|
||||
|
||||
return $this->db->table(self::TABLE)->insert($values + array('project_id' => $project_id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a project has the given parameter/value
|
||||
*
|
||||
* @access public
|
||||
* @param integer $project_id
|
||||
* @param string $option
|
||||
* @param string $value
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasValue($project_id, $option, $value)
|
||||
{
|
||||
return $this->db
|
||||
->table(self::TABLE)
|
||||
->eq('project_id', $project_id)
|
||||
->eq($option, $value)
|
||||
->exists();
|
||||
}
|
||||
}
|
||||
|
|
@ -22,8 +22,44 @@ class ProjectNotification extends Base
|
|||
{
|
||||
$project = $this->project->getById($project_id);
|
||||
|
||||
foreach ($this->projectNotificationType->getSelectedTypes($project_id) as $type) {
|
||||
$types = array_merge(
|
||||
$this->projectNotificationType->getHiddenTypes(),
|
||||
$this->projectNotificationType->getSelectedTypes($project_id)
|
||||
);
|
||||
|
||||
foreach ($types as $type) {
|
||||
$this->projectNotificationType->getType($type)->notifyProject($project, $event_name, $event_data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save settings for the given project
|
||||
*
|
||||
* @access public
|
||||
* @param integer $project_id
|
||||
* @param array $values
|
||||
*/
|
||||
public function saveSettings($project_id, array $values)
|
||||
{
|
||||
$this->db->startTransaction();
|
||||
|
||||
$types = empty($values['notification_types']) ? array() : array_keys($values['notification_types']);
|
||||
$this->projectNotificationType->saveSelectedTypes($project_id, $types);
|
||||
|
||||
$this->db->closeTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read user settings to display the form
|
||||
*
|
||||
* @access public
|
||||
* @param integer $project_id
|
||||
* @return array
|
||||
*/
|
||||
public function readSettings($project_id)
|
||||
{
|
||||
return array(
|
||||
'notification_types' => $this->projectNotificationType->getSelectedTypes($project_id),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,13 +26,13 @@ class ProjectNotificationType extends NotificationType
|
|||
*/
|
||||
public function getSelectedTypes($project_id)
|
||||
{
|
||||
$selectedTypes = $this->db
|
||||
$types = $this->db
|
||||
->table(self::TABLE)
|
||||
->eq('project_id', $project_id)
|
||||
->asc('notification_type')
|
||||
->findAllByColumn('notification_type');
|
||||
|
||||
return array_merge($this->getHiddenTypes(), $selectedTypes);
|
||||
return $this->filterTypes($types);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -52,6 +52,6 @@ class ProjectNotificationType extends NotificationType
|
|||
$results[] = $this->db->table(self::TABLE)->insert(array('project_id' => $project_id, 'notification_type' => $type));
|
||||
}
|
||||
|
||||
return ! in_array(false, $results);
|
||||
return ! in_array(false, $results, true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,8 @@ class UserNotificationType extends NotificationType
|
|||
*/
|
||||
public function getSelectedTypes($user_id)
|
||||
{
|
||||
return $this->db->table(self::TABLE)->eq('user_id', $user_id)->asc('notification_type')->findAllByColumn('notification_type');
|
||||
$types = $this->db->table(self::TABLE)->eq('user_id', $user_id)->asc('notification_type')->findAllByColumn('notification_type');
|
||||
return $this->filterTypes($types);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -46,6 +47,6 @@ class UserNotificationType extends NotificationType
|
|||
$results[] = $this->db->table(self::TABLE)->insert(array('user_id' => $user_id, 'notification_type' => $type));
|
||||
}
|
||||
|
||||
return ! in_array(false, $results);
|
||||
return ! in_array(false, $results, true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ class UserUnreadNotification extends Base
|
|||
|
||||
foreach ($events as &$event) {
|
||||
$event['event_data'] = json_decode($event['event_data'], true);
|
||||
$event['title'] = $this->getTitleFromEvent($event['event_name'], $event['event_data']);
|
||||
$event['title'] = $this->notification->getTitleWithoutAuthor($event['event_name'], $event['event_data']);
|
||||
}
|
||||
|
||||
return $events;
|
||||
|
|
@ -90,65 +90,4 @@ class UserUnreadNotification extends Base
|
|||
{
|
||||
return $this->db->table(self::TABLE)->eq('user_id', $user_id)->exists();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get title from event
|
||||
*
|
||||
* @access public
|
||||
* @param string $event_name
|
||||
* @param array $event_data
|
||||
* @return string
|
||||
*/
|
||||
public function getTitleFromEvent($event_name, array $event_data)
|
||||
{
|
||||
switch ($event_name) {
|
||||
case File::EVENT_CREATE:
|
||||
$title = t('New attachment on task #%d: %s', $event_data['file']['task_id'], $event_data['file']['name']);
|
||||
break;
|
||||
case Comment::EVENT_CREATE:
|
||||
$title = t('New comment on task #%d', $event_data['comment']['task_id']);
|
||||
break;
|
||||
case Comment::EVENT_UPDATE:
|
||||
$title = t('Comment updated on task #%d', $event_data['comment']['task_id']);
|
||||
break;
|
||||
case Subtask::EVENT_CREATE:
|
||||
$title = t('New subtask on task #%d', $event_data['subtask']['task_id']);
|
||||
break;
|
||||
case Subtask::EVENT_UPDATE:
|
||||
$title = t('Subtask updated on task #%d', $event_data['subtask']['task_id']);
|
||||
break;
|
||||
case Task::EVENT_CREATE:
|
||||
$title = t('New task #%d: %s', $event_data['task']['id'], $event_data['task']['title']);
|
||||
break;
|
||||
case Task::EVENT_UPDATE:
|
||||
$title = t('Task updated #%d', $event_data['task']['id']);
|
||||
break;
|
||||
case Task::EVENT_CLOSE:
|
||||
$title = t('Task #%d closed', $event_data['task']['id']);
|
||||
break;
|
||||
case Task::EVENT_OPEN:
|
||||
$title = t('Task #%d opened', $event_data['task']['id']);
|
||||
break;
|
||||
case Task::EVENT_MOVE_COLUMN:
|
||||
$title = t('Column changed for task #%d', $event_data['task']['id']);
|
||||
break;
|
||||
case Task::EVENT_MOVE_POSITION:
|
||||
$title = t('New position for task #%d', $event_data['task']['id']);
|
||||
break;
|
||||
case Task::EVENT_MOVE_SWIMLANE:
|
||||
$title = t('Swimlane changed for task #%d', $event_data['task']['id']);
|
||||
break;
|
||||
case Task::EVENT_ASSIGNEE_CHANGE:
|
||||
$title = t('Assignee changed on task #%d', $event_data['task']['id']);
|
||||
break;
|
||||
case Task::EVENT_OVERDUE:
|
||||
$nb = count($event_data['tasks']);
|
||||
$title = $nb > 1 ? t('%d overdue tasks', $nb) : t('Task #%d is overdue', $event_data['tasks'][0]['id']);
|
||||
break;
|
||||
default:
|
||||
$title = e('Notification');
|
||||
}
|
||||
|
||||
return $title;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ class ActivityStream extends Base implements NotificationInterface
|
|||
public function notifyProject(array $project, $event_name, array $event_data)
|
||||
{
|
||||
if ($this->userSession->isLogged()) {
|
||||
|
||||
$this->projectActivity->createEvent(
|
||||
$project['id'],
|
||||
$event_data['task']['id'],
|
||||
|
|
@ -43,16 +42,6 @@ class ActivityStream extends Base implements NotificationInterface
|
|||
$event_name,
|
||||
$event_data
|
||||
);
|
||||
|
||||
// TODO: need to be moved to external plugins
|
||||
foreach (array('slackWebhook', 'hipchatWebhook', 'jabber') as $model) {
|
||||
$this->$model->notify(
|
||||
$project['id'],
|
||||
$event_data['task']['id'],
|
||||
$event_name,
|
||||
$event_data
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,23 @@ function version_93($pdo)
|
|||
UNIQUE(task_id, name)
|
||||
) ENGINE=InnoDB CHARSET=utf8
|
||||
");
|
||||
|
||||
$pdo->exec("DROP TABLE project_integrations");
|
||||
|
||||
$pdo->exec("DELETE FROM settings WHERE `option`='integration_jabber'");
|
||||
$pdo->exec("DELETE FROM settings WHERE `option`='integration_jabber_server'");
|
||||
$pdo->exec("DELETE FROM settings WHERE `option`='integration_jabber_domain'");
|
||||
$pdo->exec("DELETE FROM settings WHERE `option`='integration_jabber_username'");
|
||||
$pdo->exec("DELETE FROM settings WHERE `option`='integration_jabber_password'");
|
||||
$pdo->exec("DELETE FROM settings WHERE `option`='integration_jabber_nickname'");
|
||||
$pdo->exec("DELETE FROM settings WHERE `option`='integration_jabber_room'");
|
||||
$pdo->exec("DELETE FROM settings WHERE `option`='integration_hipchat'");
|
||||
$pdo->exec("DELETE FROM settings WHERE `option`='integration_hipchat_api_url'");
|
||||
$pdo->exec("DELETE FROM settings WHERE `option`='integration_hipchat_room_id'");
|
||||
$pdo->exec("DELETE FROM settings WHERE `option`='integration_hipchat_room_token'");
|
||||
$pdo->exec("DELETE FROM settings WHERE `option`='integration_slack_webhook'");
|
||||
$pdo->exec("DELETE FROM settings WHERE `option`='integration_slack_webhook_url'");
|
||||
$pdo->exec("DELETE FROM settings WHERE `option`='integration_slack_webhook_channel'");
|
||||
}
|
||||
|
||||
function version_92($pdo)
|
||||
|
|
|
|||
|
|
@ -39,6 +39,23 @@ function version_73($pdo)
|
|||
UNIQUE(task_id, name)
|
||||
)
|
||||
");
|
||||
|
||||
$pdo->exec("DROP TABLE project_integrations");
|
||||
|
||||
$pdo->exec("DELETE FROM settings WHERE \"option\"='integration_jabber'");
|
||||
$pdo->exec("DELETE FROM settings WHERE \"option\"='integration_jabber_server'");
|
||||
$pdo->exec("DELETE FROM settings WHERE \"option\"='integration_jabber_domain'");
|
||||
$pdo->exec("DELETE FROM settings WHERE \"option\"='integration_jabber_username'");
|
||||
$pdo->exec("DELETE FROM settings WHERE \"option\"='integration_jabber_password'");
|
||||
$pdo->exec("DELETE FROM settings WHERE \"option\"='integration_jabber_nickname'");
|
||||
$pdo->exec("DELETE FROM settings WHERE \"option\"='integration_jabber_room'");
|
||||
$pdo->exec("DELETE FROM settings WHERE \"option\"='integration_hipchat'");
|
||||
$pdo->exec("DELETE FROM settings WHERE \"option\"='integration_hipchat_api_url'");
|
||||
$pdo->exec("DELETE FROM settings WHERE \"option\"='integration_hipchat_room_id'");
|
||||
$pdo->exec("DELETE FROM settings WHERE \"option\"='integration_hipchat_room_token'");
|
||||
$pdo->exec("DELETE FROM settings WHERE \"option\"='integration_slack_webhook'");
|
||||
$pdo->exec("DELETE FROM settings WHERE \"option\"='integration_slack_webhook_url'");
|
||||
$pdo->exec("DELETE FROM settings WHERE \"option\"='integration_slack_webhook_channel'");
|
||||
}
|
||||
|
||||
function version_72($pdo)
|
||||
|
|
|
|||
|
|
@ -39,6 +39,23 @@ function version_88($pdo)
|
|||
UNIQUE(task_id, name)
|
||||
)
|
||||
");
|
||||
|
||||
$pdo->exec("DROP TABLE project_integrations");
|
||||
|
||||
$pdo->exec("DELETE FROM settings WHERE \"option\"='integration_jabber'");
|
||||
$pdo->exec("DELETE FROM settings WHERE \"option\"='integration_jabber_server'");
|
||||
$pdo->exec("DELETE FROM settings WHERE \"option\"='integration_jabber_domain'");
|
||||
$pdo->exec("DELETE FROM settings WHERE \"option\"='integration_jabber_username'");
|
||||
$pdo->exec("DELETE FROM settings WHERE \"option\"='integration_jabber_password'");
|
||||
$pdo->exec("DELETE FROM settings WHERE \"option\"='integration_jabber_nickname'");
|
||||
$pdo->exec("DELETE FROM settings WHERE \"option\"='integration_jabber_room'");
|
||||
$pdo->exec("DELETE FROM settings WHERE \"option\"='integration_hipchat'");
|
||||
$pdo->exec("DELETE FROM settings WHERE \"option\"='integration_hipchat_api_url'");
|
||||
$pdo->exec("DELETE FROM settings WHERE \"option\"='integration_hipchat_room_id'");
|
||||
$pdo->exec("DELETE FROM settings WHERE \"option\"='integration_hipchat_room_token'");
|
||||
$pdo->exec("DELETE FROM settings WHERE \"option\"='integration_slack_webhook'");
|
||||
$pdo->exec("DELETE FROM settings WHERE \"option\"='integration_slack_webhook_url'");
|
||||
$pdo->exec("DELETE FROM settings WHERE \"option\"='integration_slack_webhook_channel'");
|
||||
}
|
||||
|
||||
function version_87($pdo)
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ class ClassProvider implements ServiceProviderInterface
|
|||
'File',
|
||||
'LastLogin',
|
||||
'Link',
|
||||
'Notification',
|
||||
'OverdueNotification',
|
||||
'Project',
|
||||
'ProjectActivity',
|
||||
|
|
@ -38,7 +39,6 @@ class ClassProvider implements ServiceProviderInterface
|
|||
'ProjectDuplication',
|
||||
'ProjectDailyColumnStats',
|
||||
'ProjectDailyStats',
|
||||
'ProjectIntegration',
|
||||
'ProjectPermission',
|
||||
'ProjectNotification',
|
||||
'ProjectMetadata',
|
||||
|
|
@ -98,9 +98,6 @@ class ClassProvider implements ServiceProviderInterface
|
|||
'BitbucketWebhook',
|
||||
'GithubWebhook',
|
||||
'GitlabWebhook',
|
||||
'HipchatWebhook',
|
||||
'Jabber',
|
||||
'SlackWebhook',
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -31,60 +31,6 @@
|
|||
<?= $this->form->checkbox('integration_gravatar', t('Enable Gravatar images'), 1, $values['integration_gravatar'] == 1) ?>
|
||||
</div>
|
||||
|
||||
<h3><img src="<?= $this->url->dir() ?>assets/img/jabber-icon.png"/> <?= t('Jabber (XMPP)') ?></h3>
|
||||
<div class="listing">
|
||||
<?= $this->form->checkbox('integration_jabber', t('Send notifications to Jabber'), 1, $values['integration_jabber'] == 1) ?>
|
||||
|
||||
<?= $this->form->label(t('XMPP server address'), 'integration_jabber_server') ?>
|
||||
<?= $this->form->text('integration_jabber_server', $values, $errors, array('placeholder="tcp://myserver:5222"')) ?>
|
||||
<p class="form-help"><?= t('The server address must use this format: "tcp://hostname:5222"') ?></p>
|
||||
|
||||
<?= $this->form->label(t('Jabber domain'), 'integration_jabber_domain') ?>
|
||||
<?= $this->form->text('integration_jabber_domain', $values, $errors, array('placeholder="example.com"')) ?>
|
||||
|
||||
<?= $this->form->label(t('Username'), 'integration_jabber_username') ?>
|
||||
<?= $this->form->text('integration_jabber_username', $values, $errors) ?>
|
||||
|
||||
<?= $this->form->label(t('Password'), 'integration_jabber_password') ?>
|
||||
<?= $this->form->password('integration_jabber_password', $values, $errors) ?>
|
||||
|
||||
<?= $this->form->label(t('Jabber nickname'), 'integration_jabber_nickname') ?>
|
||||
<?= $this->form->text('integration_jabber_nickname', $values, $errors) ?>
|
||||
|
||||
<?= $this->form->label(t('Multi-user chat room'), 'integration_jabber_room') ?>
|
||||
<?= $this->form->text('integration_jabber_room', $values, $errors, array('placeholder="myroom@conference.example.com"')) ?>
|
||||
|
||||
<p class="form-help"><?= $this->url->doc(t('Help on Jabber integration'), 'jabber') ?></p>
|
||||
</div>
|
||||
|
||||
<h3><img src="<?= $this->url->dir() ?>assets/img/hipchat-icon.png"/> <?= t('Hipchat') ?></h3>
|
||||
<div class="listing">
|
||||
<?= $this->form->checkbox('integration_hipchat', t('Send notifications to Hipchat'), 1, $values['integration_hipchat'] == 1) ?>
|
||||
|
||||
<?= $this->form->label(t('API URL'), 'integration_hipchat_api_url') ?>
|
||||
<?= $this->form->text('integration_hipchat_api_url', $values, $errors) ?>
|
||||
|
||||
<?= $this->form->label(t('Room API ID or name'), 'integration_hipchat_room_id') ?>
|
||||
<?= $this->form->text('integration_hipchat_room_id', $values, $errors) ?>
|
||||
|
||||
<?= $this->form->label(t('Room notification token'), 'integration_hipchat_room_token') ?>
|
||||
<?= $this->form->text('integration_hipchat_room_token', $values, $errors) ?>
|
||||
|
||||
<p class="form-help"><?= $this->url->doc(t('Help on Hipchat integration'), 'hipchat') ?></p>
|
||||
</div>
|
||||
|
||||
<h3><i class="fa fa-slack fa-fw"></i> <?= t('Slack') ?></h3>
|
||||
<div class="listing">
|
||||
<?= $this->form->checkbox('integration_slack_webhook', t('Send notifications to a Slack channel'), 1, $values['integration_slack_webhook'] == 1) ?>
|
||||
|
||||
<?= $this->form->label(t('Webhook URL'), 'integration_slack_webhook_url') ?>
|
||||
<?= $this->form->text('integration_slack_webhook_url', $values, $errors) ?>
|
||||
<?= $this->form->label(t('Channel/Group/User (Optional)'), 'integration_slack_webhook_channel') ?>
|
||||
<?= $this->form->text('integration_slack_webhook_channel', $values, $errors) ?>
|
||||
|
||||
<p class="form-help"><?= $this->url->doc(t('Help on Slack integration'), 'slack') ?></p>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@
|
|||
<h2><?= t('Integration with third-party services') ?></h2>
|
||||
</div>
|
||||
|
||||
<form method="post" action="<?= $this->url->href('project', 'integration', array('project_id' => $project['id'])) ?>" autocomplete="off">
|
||||
<form method="post" action="<?= $this->url->href('project', 'integrations', array('project_id' => $project['id'])) ?>" autocomplete="off">
|
||||
<?= $this->form->csrf() ?>
|
||||
|
||||
<?= $this->hook->render('template:project:integrations', array('values' => $values)) ?>
|
||||
|
||||
<h3><i class="fa fa-github fa-fw"></i> <?= t('Github webhooks') ?></h3>
|
||||
<div class="listing">
|
||||
|
|
@ -12,86 +13,15 @@
|
|||
<p class="form-help"><?= $this->url->doc(t('Help on Github webhooks'), 'github-webhooks') ?></p>
|
||||
</div>
|
||||
|
||||
|
||||
<h3><img src="<?= $this->url->dir() ?>assets/img/gitlab-icon.png"/> <?= t('Gitlab webhooks') ?></h3>
|
||||
<div class="listing">
|
||||
<input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('webhook', 'gitlab', array('token' => $webhook_token, 'project_id' => $project['id']), false, '', true) ?>"/><br/>
|
||||
<p class="form-help"><?= $this->url->doc(t('Help on Gitlab webhooks'), 'gitlab-webhooks') ?></p>
|
||||
</div>
|
||||
|
||||
|
||||
<h3><i class="fa fa-bitbucket fa-fw"></i> <?= t('Bitbucket webhooks') ?></h3>
|
||||
<div class="listing">
|
||||
<input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('webhook', 'bitbucket', array('token' => $webhook_token, 'project_id' => $project['id']), false, '', true) ?>"/><br/>
|
||||
<p class="form-help"><?= $this->url->doc(t('Help on Bitbucket webhooks'), 'bitbucket-webhooks') ?></p>
|
||||
</div>
|
||||
|
||||
|
||||
<h3><img src="<?= $this->url->dir() ?>assets/img/jabber-icon.png"/> <?= t('Jabber (XMPP)') ?></h3>
|
||||
<div class="listing">
|
||||
<?= $this->form->checkbox('jabber', t('Send notifications to Jabber'), 1, isset($values['jabber']) && $values['jabber'] == 1) ?>
|
||||
|
||||
<?= $this->form->label(t('XMPP server address'), 'jabber_server') ?>
|
||||
<?= $this->form->text('jabber_server', $values, $errors, array('placeholder="tcp://myserver:5222"')) ?>
|
||||
<p class="form-help"><?= t('The server address must use this format: "tcp://hostname:5222"') ?></p>
|
||||
|
||||
<?= $this->form->label(t('Jabber domain'), 'jabber_domain') ?>
|
||||
<?= $this->form->text('jabber_domain', $values, $errors, array('placeholder="example.com"')) ?>
|
||||
|
||||
<?= $this->form->label(t('Username'), 'jabber_username') ?>
|
||||
<?= $this->form->text('jabber_username', $values, $errors) ?>
|
||||
|
||||
<?= $this->form->label(t('Password'), 'jabber_password') ?>
|
||||
<?= $this->form->password('jabber_password', $values, $errors) ?>
|
||||
|
||||
<?= $this->form->label(t('Jabber nickname'), 'jabber_nickname') ?>
|
||||
<?= $this->form->text('jabber_nickname', $values, $errors) ?>
|
||||
|
||||
<?= $this->form->label(t('Multi-user chat room'), 'jabber_room') ?>
|
||||
<?= $this->form->text('jabber_room', $values, $errors, array('placeholder="myroom@conference.example.com"')) ?>
|
||||
|
||||
<p class="form-help"><?= $this->url->doc(t('Help on Jabber integration'), 'jabber') ?></p>
|
||||
|
||||
<div class="form-actions">
|
||||
<input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<h3><img src="<?= $this->url->dir() ?>assets/img/hipchat-icon.png"/> <?= t('Hipchat') ?></h3>
|
||||
<div class="listing">
|
||||
<?= $this->form->checkbox('hipchat', t('Send notifications to Hipchat'), 1, isset($values['hipchat']) && $values['hipchat'] == 1) ?>
|
||||
|
||||
<?= $this->form->label(t('API URL'), 'hipchat_api_url') ?>
|
||||
<?= $this->form->text('hipchat_api_url', $values, $errors) ?>
|
||||
|
||||
<?= $this->form->label(t('Room API ID or name'), 'hipchat_room_id') ?>
|
||||
<?= $this->form->text('hipchat_room_id', $values, $errors) ?>
|
||||
|
||||
<?= $this->form->label(t('Room notification token'), 'hipchat_room_token') ?>
|
||||
<?= $this->form->text('hipchat_room_token', $values, $errors) ?>
|
||||
|
||||
<p class="form-help"><?= $this->url->doc(t('Help on Hipchat integration'), 'hipchat') ?></a></p>
|
||||
|
||||
<div class="form-actions">
|
||||
<input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<h3><i class="fa fa-slack fa-fw"></i> <?= t('Slack') ?></h3>
|
||||
<div class="listing">
|
||||
<?= $this->form->checkbox('slack', t('Send notifications to a Slack channel'), 1, isset($values['slack']) && $values['slack'] == 1) ?>
|
||||
|
||||
<?= $this->form->label(t('Webhook URL'), 'slack_webhook_url') ?>
|
||||
<?= $this->form->text('slack_webhook_url', $values, $errors) ?>
|
||||
<?= $this->form->label(t('Channel/Group/User (Optional)'), 'slack_webhook_channel') ?>
|
||||
<?= $this->form->text('slack_webhook_channel', $values, $errors) ?>
|
||||
|
||||
<p class="form-help"><?= $this->url->doc(t('Help on Slack integration'), 'slack') ?></p>
|
||||
|
||||
<div class="form-actions">
|
||||
<input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<div class="page-header">
|
||||
<h2><?= t('Notifications') ?></h2>
|
||||
</div>
|
||||
<?php if (empty($types)): ?>
|
||||
<p class="alert"><?= t('There is no notification method registered.') ?></p>
|
||||
<?php else: ?>
|
||||
<form method="post" action="<?= $this->url->href('project', 'notifications', array('project_id' => $project['id'])) ?>" autocomplete="off">
|
||||
|
||||
<?= $this->form->csrf() ?>
|
||||
|
||||
<h4><?= t('Notification methods:') ?></h4>
|
||||
<?= $this->form->checkboxes('notification_types', $types, $notifications) ?>
|
||||
|
||||
<div class="form-actions">
|
||||
<input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
|
||||
<?= t('or') ?>
|
||||
<?= $this->url->link(t('cancel'), 'project', 'show', array('project_id' => $project['id'])) ?>
|
||||
</div>
|
||||
</form>
|
||||
<?php endif ?>
|
||||
|
|
@ -12,8 +12,11 @@
|
|||
<li <?= $this->app->getRouterController() === 'project' && $this->app->getRouterAction() === 'share' ? 'class="active"' : '' ?>>
|
||||
<?= $this->url->link(t('Public access'), 'project', 'share', array('project_id' => $project['id'])) ?>
|
||||
</li>
|
||||
<li <?= $this->app->getRouterController() === 'project' && $this->app->getRouterAction() === 'integration' ? 'class="active"' : '' ?>>
|
||||
<?= $this->url->link(t('Integrations'), 'project', 'integration', array('project_id' => $project['id'])) ?>
|
||||
<li <?= $this->app->getRouterController() === 'project' && $this->app->getRouterAction() === 'notifications' ? 'class="active"' : '' ?>>
|
||||
<?= $this->url->link(t('Notifications'), 'project', 'notifications', array('project_id' => $project['id'])) ?>
|
||||
</li>
|
||||
<li <?= $this->app->getRouterController() === 'project' && $this->app->getRouterAction() === 'integrations' ? 'class="active"' : '' ?>>
|
||||
<?= $this->url->link(t('Integrations'), 'project', 'integrations', array('project_id' => $project['id'])) ?>
|
||||
</li>
|
||||
<li <?= $this->app->getRouterController() === 'project' && $this->app->getRouterAction() === 'edit' ? 'class="active"' : '' ?>>
|
||||
<?= $this->url->link(t('Edit project'), 'project', 'edit', array('project_id' => $project['id'])) ?>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
<div class="page-header">
|
||||
<h2><?= t('Integrations') ?></h2>
|
||||
</div>
|
||||
|
||||
<form method="post" action="<?= $this->url->href('user', 'integrations', array('user_id' => $user['id'])) ?>" autocomplete="off">
|
||||
<?= $this->form->csrf() ?>
|
||||
<?php $hooks = $this->hook->render('template:user:integrations', array('values' => $values)) ?>
|
||||
<?php if (! empty($hooks)): ?>
|
||||
<?= $hooks ?>
|
||||
<?php else: ?>
|
||||
<p class="alert"><?= t('No external integration registered.') ?></p>
|
||||
<?php endif ?>
|
||||
</form>
|
||||
|
|
@ -56,6 +56,9 @@
|
|||
<li <?= $this->app->getRouterController() === 'user' && $this->app->getRouterAction() === 'external' ? 'class="active"' : '' ?>>
|
||||
<?= $this->url->link(t('External accounts'), 'user', 'external', array('user_id' => $user['id'])) ?>
|
||||
</li>
|
||||
<li <?= $this->app->getRouterController() === 'user' && $this->app->getRouterAction() === 'integrations' ? 'class="active"' : '' ?>>
|
||||
<?= $this->url->link(t('Integrations'), 'user', 'integrations', array('user_id' => $user['id'])) ?>
|
||||
</li>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($this->user->isAdmin()): ?>
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.2 KiB |
|
|
@ -4,12 +4,9 @@ Notifications
|
|||
Kanboard est capable d'envoyer des notifications via différents canaux :
|
||||
|
||||
- Email
|
||||
- Jabber/XMPP
|
||||
- Hipchat
|
||||
- Slack
|
||||
- Web (Liste de message non lus)
|
||||
|
||||
En fait, pour Jabber/Hipchat/Slack les notifications sont envoyées dans des salons de discussion car ils sont configurés au niveau projet.
|
||||
Cependant, les notifications par email sont envoyées à un individu.
|
||||
Vous pouvez ajouter d'autres cannaux an ajoutant des extensions comme par exemple Hipchat, Slack ou encore Jabber.
|
||||
|
||||
Configuration
|
||||
--------------
|
||||
|
|
@ -26,7 +23,7 @@ Vous pouvez choisir votre méthode favorite de notification :
|
|||
- Web
|
||||
|
||||
Pour chaque projet dont vous êtes membre, vous pouvez choisir de recevoir des notifications pour :
|
||||
|
||||
|
||||
- Toutes les tâches
|
||||
- Seulement les tâches qui vous sont assignées
|
||||
- Seulement les tâches que vous avez créées
|
||||
|
|
@ -41,7 +38,7 @@ Les notifications web sont accéssibles depuis le tableau de bord ou depuis l'ic
|
|||
|
||||

|
||||
|
||||
Les notifications sont affichés sous forme de liste. Vous pouvez marquer comme lu chacune d'entre-elle ou toutes en même temps.
|
||||
Les notifications sont affichés sous forme de liste. Vous pouvez marquer comme lu chacune d'entre-elle ou toutes en même temps.
|
||||
|
||||

|
||||
|
||||
|
|
|
|||
|
|
@ -1,38 +0,0 @@
|
|||
Hipchat integration
|
||||
===================
|
||||
|
||||
You can send notifications to Hipchat for all projects or only for specific projects.
|
||||
|
||||
- To send notifications for all projects, go to **Settings > Integrations > Hipchat**
|
||||
- To send notifications for only some projects, go to **Project settings > Integrations > Hipchat**
|
||||
|
||||
Each project can send notifications to a separate room.
|
||||
|
||||
Send notifications to a room
|
||||
-----------------------------
|
||||
|
||||
Example of notifications:
|
||||
|
||||

|
||||
|
||||
This feature use the room notification token system of Hipchat.
|
||||
|
||||
### Hipchat configuration
|
||||
|
||||

|
||||
|
||||
1. Go to to **My account**
|
||||
2. Click on the tab **Rooms** and select the room you want to send the notifications
|
||||
3. On the left, choose **Tokens**
|
||||
4. Enter a label, by example "Kanboard" and save
|
||||
|
||||
### Kanboard configuration
|
||||
|
||||

|
||||
|
||||
1. Go to **Settings > Integrations > Hipchat** or **Project settings > Integrations > Hipchat**
|
||||
2. Replace the API url if you use the self-hosted version of Hipchat
|
||||
3. Set the room name or the room API ID
|
||||
4. Copy and paste the token generated previously
|
||||
|
||||
Now, Kanboard events will be sent to the Hipchat room.
|
||||
|
|
@ -66,9 +66,6 @@ Using Kanboard
|
|||
- [Bitbucket webhooks](bitbucket-webhooks.markdown)
|
||||
- [Github webhooks](github-webhooks.markdown)
|
||||
- [Gitlab webhooks](gitlab-webhooks.markdown)
|
||||
- [Hipchat](hipchat.markdown)
|
||||
- [Jabber](jabber.markdown)
|
||||
- [Slack](slack.markdown)
|
||||
- [iCalendar subscriptions](ical.markdown)
|
||||
- [RSS/Atom subscriptions](rss.markdown)
|
||||
- [Json-RPC API](api-json-rpc.markdown)
|
||||
|
|
|
|||
|
|
@ -1,34 +0,0 @@
|
|||
Jabber/XMPP integration
|
||||
=======================
|
||||
|
||||
You can send notifications to a Jabber room for all projects or only for specific projects.
|
||||
|
||||
- To send notifications for all projects, go to **Settings > Integrations > Jabber**
|
||||
- To send notifications for only some projects, go to **Project settings > Integrations > Jabber**
|
||||
|
||||
Each project can send notifications to a separate room.
|
||||
|
||||
## Example of notification
|
||||
|
||||
Here an example with the Jabber client Adium:
|
||||
|
||||

|
||||
|
||||
## Configuration
|
||||
|
||||

|
||||
|
||||
1. Go to **Settings > Integrations > Jabber** or **Project settings > Integrations > Jabber**
|
||||
2. **XMPP server address**: URL of the XMPP server, example: **tcp://172.28.128.3:5222**
|
||||
3. **Jabber domain**: The **"to"** attribute of the XMPP protocol, example: **example.com**
|
||||
4. **Username**: The Jabber username used by Kanboard, example: **kanboard**
|
||||
5. **Password**: The Jabber password
|
||||
6. **Jabber nickname**: The nickname used to connect to the room
|
||||
7. **Multi-user chat room**: The address of the room, example: **demo@conference.example.com**
|
||||
|
||||
Now, Kanboard events will be sent to the Jabber conference room.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- Enable the debug mode
|
||||
- All connection errors with the XMPP server are recorded in the log files `data/debug.log` or syslog
|
||||
|
|
@ -4,14 +4,9 @@ Notifications
|
|||
Kanboard is able to send notifications through several channels:
|
||||
|
||||
- Email
|
||||
- Web
|
||||
- Jabber/XMPP
|
||||
- Hipchat
|
||||
- Slack
|
||||
- Web (List of unread messages)
|
||||
|
||||
Actually, Jabber/Hipchat/Slack notifications are sent to a room or group channel because they are configured at the project level.
|
||||
|
||||
However, email or web notifications are sent to an individual person.
|
||||
External plugins allow you to send notifications to Slack, Hipchat, Jabber or any chat system.
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
|
|
|||
|
|
@ -134,6 +134,8 @@ List of template hooks:
|
|||
- `template:dashboard:sidebar`
|
||||
- `template:config:sidebar`
|
||||
- `template:config:integrations`
|
||||
- `template:project:integrations`
|
||||
- `template:user:integrations`
|
||||
- `template:export:sidebar`
|
||||
- `template:layout:head`
|
||||
- `template:layout:top`
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
Add Notification Types with Plugins
|
||||
===================================
|
||||
|
||||
You can send notifications to almost any system by adding a new type.
|
||||
There are two kinds of notifications: project and user.
|
||||
|
||||
- Project: Notifications configured at the project level
|
||||
- User: Notifications sent individually and configured at the user profile
|
||||
|
||||
Register a new notification type
|
||||
--------------------------------
|
||||
|
||||
In your plugin registration file call the method `setType()`:
|
||||
|
||||
```php
|
||||
$this->userNotificationType->setType('irc', t('IRC'), '\Kanboard\Plugin\IRC\Notification\IrcHandler');
|
||||
$this->projectNotificationType->setType('irc', t('IRC'), '\Kanboard\Plugin\IRC\Notification\IrcHandler');
|
||||
```
|
||||
|
||||
Your handler can be registered for user or project notification. You don't necessary need to support both.
|
||||
|
||||
When your handler is registered, the end-user can choose to receive the new notification type or not.
|
||||
|
||||
Notification Handler
|
||||
--------------------
|
||||
|
||||
Your notification handler must implements the interface `Kanboard\Notification\NotificationInterface`:
|
||||
|
||||
```php
|
||||
interface NotificationInterface
|
||||
{
|
||||
/**
|
||||
* Send notification to a user
|
||||
*
|
||||
* @access public
|
||||
* @param array $user
|
||||
* @param string $event_name
|
||||
* @param array $event_data
|
||||
*/
|
||||
public function notifyUser(array $user, $event_name, array $event_data);
|
||||
|
||||
/**
|
||||
* Send notification to a project
|
||||
*
|
||||
* @access public
|
||||
* @param array $project
|
||||
* @param string $event_name
|
||||
* @param array $event_data
|
||||
*/
|
||||
public function notifyProject(array $project, $event_name, array $event_data);
|
||||
}
|
||||
```
|
||||
|
||||
Example of notification plugins
|
||||
-------------------------------
|
||||
|
||||
- [Slack](https://github.com/kanboard/plugin-slack)
|
||||
- [Hipchat](https://github.com/kanboard/plugin-hipchat)
|
||||
- [Jabber](https://github.com/kanboard/plugin-jabber)
|
||||
|
||||
|
|
@ -156,8 +156,8 @@ class Plugin extends Base
|
|||
public function initialize()
|
||||
{
|
||||
$this->action->extendActions(
|
||||
'\Kanboard\Plugin\AutomaticAction\Action\SendSlackMessage', // Use absolute namespace
|
||||
t('Send a message to Slack when the task color change')
|
||||
'\Kanboard\Plugin\AutomaticAction\Action\DoSomething', // Use absolute namespace
|
||||
t('Do something when the task color change')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,10 +12,14 @@ Plugin creators should specify explicitly the compatible versions of Kanboard. I
|
|||
- [Override default application behaviors](plugin-overrides.markdown)
|
||||
- [Add schema migrations for plugins](plugin-schema-migrations.markdown)
|
||||
- [Add mail transports](plugin-mail-transports.markdown)
|
||||
- [Add notification types](plugin-notifications.markdown)
|
||||
|
||||
Examples of plugins
|
||||
-------------------
|
||||
|
||||
- [Slack](https://github.com/kanboard/plugin-slack)
|
||||
- [Hipchat](https://github.com/kanboard/plugin-hipchat)
|
||||
- [Jabber](https://github.com/kanboard/plugin-jabber)
|
||||
- [Sendgrid](https://github.com/kanboard/plugin-sendgrid)
|
||||
- [Mailgun](https://github.com/kanboard/plugin-mailgun)
|
||||
- [Postmark](https://github.com/kanboard/plugin-postmark)
|
||||
|
|
|
|||
|
|
@ -1,38 +0,0 @@
|
|||
Slack integration
|
||||
=================
|
||||
|
||||
You can send notifications to Slack for all projects or only for specific projects.
|
||||
|
||||
- To send notifications for all projects, go to **Settings > Integrations > Slack**
|
||||
- To send notifications for only some projects, go to **Project settings > Integrations > Slack**
|
||||
|
||||
Each project can send notifications to a separate channel.
|
||||
|
||||
Send notifications to a channel
|
||||
-------------------------------
|
||||
|
||||
Example of notifications:
|
||||
|
||||

|
||||
|
||||
This feature use the [Incoming webhook](https://api.slack.com/incoming-webhooks) system of Slack.
|
||||
|
||||
### Slack configuration
|
||||
|
||||

|
||||
|
||||
1. Click on the Team dropdown and choose **Configure Integrations**
|
||||
2. On the list of services, scroll-down and choose **DIY Integrations & Customizations > Incoming WebHooks**
|
||||
3. Copy the webhook url to the Kanboard settings page: **Settings > Integrations > Slack** or **Project settings > Integrations > Slack**
|
||||
|
||||
Now, Kanboard events will be sent to the Slack channel.
|
||||
|
||||
### Overriding Channel (Optional)
|
||||
|
||||
Optionally you can override the channel, private group or send direct messages by filling up **Channel/Group/User** text box. Leaving it empty will post to the channel configured during webhook configuration.
|
||||
|
||||
Examples:
|
||||
|
||||
- Send messages to another channel: **#mychannel1**
|
||||
- Send messages to a private group: **#myprivategroup1**
|
||||
- Send messages directly to someone: **@anotheruser1**
|
||||
|
|
@ -91,7 +91,7 @@ abstract class Base extends PHPUnit_Framework_TestCase
|
|||
$this->container['userNotificationType'] = $this
|
||||
->getMockBuilder('\Kanboard\Model\UserNotificationType')
|
||||
->setConstructorArgs(array($this->container))
|
||||
->setMethods(array('getType'))
|
||||
->setMethods(array('getType', 'getSelectedTypes'))
|
||||
->getMock();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,377 +0,0 @@
|
|||
<?php
|
||||
|
||||
require_once __DIR__.'/../Base.php';
|
||||
|
||||
use Kanboard\Integration\SlackWebhook;
|
||||
use Kanboard\Model\Project;
|
||||
use Kanboard\Model\Task;
|
||||
|
||||
class SlackWebhookTest extends Base
|
||||
{
|
||||
public function testIsActivatedFromGlobalConfig()
|
||||
{
|
||||
$slack = new SlackWebhook($this->container);
|
||||
|
||||
$this->container['config'] = $this
|
||||
->getMockBuilder('\Kanboard\Model\Config')
|
||||
->setConstructorArgs(array($this->container))
|
||||
->setMethods(array(
|
||||
'get',
|
||||
))
|
||||
->getMock();
|
||||
|
||||
$this->container['config']
|
||||
->expects($this->once())
|
||||
->method('get')
|
||||
->with($this->equalTo('integration_slack_webhook'))
|
||||
->will($this->returnValue(1));
|
||||
|
||||
$this->assertTrue($slack->isActivated(1));
|
||||
}
|
||||
|
||||
public function testIsActivatedFromProjectConfig()
|
||||
{
|
||||
$slack = new SlackWebhook($this->container);
|
||||
|
||||
$this->container['config'] = $this
|
||||
->getMockBuilder('\Kanboard\Model\Config')
|
||||
->setConstructorArgs(array($this->container))
|
||||
->setMethods(array(
|
||||
'get',
|
||||
))
|
||||
->getMock();
|
||||
|
||||
$this->container['projectIntegration'] = $this
|
||||
->getMockBuilder('\Kanboard\Model\ProjectIntegration')
|
||||
->setConstructorArgs(array($this->container))
|
||||
->setMethods(array(
|
||||
'hasValue',
|
||||
))
|
||||
->getMock();
|
||||
|
||||
$this->container['config']
|
||||
->expects($this->once())
|
||||
->method('get')
|
||||
->with($this->equalTo('integration_slack_webhook'))
|
||||
->will($this->returnValue(0));
|
||||
|
||||
$this->container['projectIntegration']
|
||||
->expects($this->once())
|
||||
->method('hasValue')
|
||||
->with(
|
||||
$this->equalTo(1),
|
||||
$this->equalTo('slack'),
|
||||
$this->equalTo(1)
|
||||
)
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$this->assertTrue($slack->isActivated(1));
|
||||
}
|
||||
|
||||
public function testIsNotActivated()
|
||||
{
|
||||
$slack = new SlackWebhook($this->container);
|
||||
|
||||
$this->container['config'] = $this
|
||||
->getMockBuilder('\Kanboard\Model\Config')
|
||||
->setConstructorArgs(array($this->container))
|
||||
->setMethods(array(
|
||||
'get',
|
||||
))
|
||||
->getMock();
|
||||
|
||||
$this->container['projectIntegration'] = $this
|
||||
->getMockBuilder('\Kanboard\Model\ProjectIntegration')
|
||||
->setConstructorArgs(array($this->container))
|
||||
->setMethods(array(
|
||||
'hasValue',
|
||||
))
|
||||
->getMock();
|
||||
|
||||
$this->container['config']
|
||||
->expects($this->once())
|
||||
->method('get')
|
||||
->with($this->equalTo('integration_slack_webhook'))
|
||||
->will($this->returnValue(0));
|
||||
|
||||
$this->container['projectIntegration']
|
||||
->expects($this->once())
|
||||
->method('hasValue')
|
||||
->with(
|
||||
$this->equalTo(1),
|
||||
$this->equalTo('slack'),
|
||||
$this->equalTo(1)
|
||||
)
|
||||
->will($this->returnValue(false));
|
||||
|
||||
$this->assertFalse($slack->isActivated(1));
|
||||
}
|
||||
|
||||
public function testGetChannelFromGlobalConfig()
|
||||
{
|
||||
$slack = new SlackWebhook($this->container);
|
||||
|
||||
$this->container['config'] = $this
|
||||
->getMockBuilder('\Kanboard\Model\Config')
|
||||
->setConstructorArgs(array($this->container))
|
||||
->setMethods(array(
|
||||
'get',
|
||||
))
|
||||
->getMock();
|
||||
|
||||
$this->container['config']
|
||||
->expects($this->once())
|
||||
->method('get')
|
||||
->with($this->equalTo('integration_slack_webhook_channel'))
|
||||
->will($this->returnValue('mychannel'));
|
||||
|
||||
$this->assertEquals('mychannel', $slack->getChannel(1));
|
||||
}
|
||||
|
||||
public function testGetChannelFromProjectConfig()
|
||||
{
|
||||
$slack = new SlackWebhook($this->container);
|
||||
|
||||
$this->container['config'] = $this
|
||||
->getMockBuilder('\Kanboard\Model\Config')
|
||||
->setConstructorArgs(array($this->container))
|
||||
->setMethods(array(
|
||||
'get',
|
||||
))
|
||||
->getMock();
|
||||
|
||||
$this->container['projectIntegration'] = $this
|
||||
->getMockBuilder('\Kanboard\Model\ProjectIntegration')
|
||||
->setConstructorArgs(array($this->container))
|
||||
->setMethods(array(
|
||||
'getParameters',
|
||||
))
|
||||
->getMock();
|
||||
|
||||
$this->container['config']
|
||||
->expects($this->once())
|
||||
->method('get')
|
||||
->with($this->equalTo('integration_slack_webhook_channel'))
|
||||
->will($this->returnValue(''));
|
||||
|
||||
$this->container['projectIntegration']
|
||||
->expects($this->once())
|
||||
->method('getParameters')
|
||||
->with($this->equalTo(1))
|
||||
->will($this->returnValue(array('slack_webhook_channel' => 'my_project_channel')));
|
||||
|
||||
$this->assertEquals('my_project_channel', $slack->getChannel(1));
|
||||
}
|
||||
|
||||
public function testGetWebhoookUrlFromGlobalConfig()
|
||||
{
|
||||
$slack = new SlackWebhook($this->container);
|
||||
|
||||
$this->container['config'] = $this
|
||||
->getMockBuilder('\Kanboard\Model\Config')
|
||||
->setConstructorArgs(array($this->container))
|
||||
->setMethods(array(
|
||||
'get',
|
||||
))
|
||||
->getMock();
|
||||
|
||||
$this->container['config']
|
||||
->expects($this->at(0))
|
||||
->method('get')
|
||||
->with($this->equalTo('integration_slack_webhook'))
|
||||
->will($this->returnValue(1));
|
||||
|
||||
$this->container['config']
|
||||
->expects($this->at(1))
|
||||
->method('get')
|
||||
->with($this->equalTo('integration_slack_webhook_url'))
|
||||
->will($this->returnValue('url'));
|
||||
|
||||
$this->assertEquals('url', $slack->getWebhookUrl(1));
|
||||
}
|
||||
|
||||
public function testGetWebhookUrlFromProjectConfig()
|
||||
{
|
||||
$slack = new SlackWebhook($this->container);
|
||||
|
||||
$this->container['config'] = $this
|
||||
->getMockBuilder('\Kanboard\Model\Config')
|
||||
->setConstructorArgs(array($this->container))
|
||||
->setMethods(array(
|
||||
'get',
|
||||
))
|
||||
->getMock();
|
||||
|
||||
$this->container['projectIntegration'] = $this
|
||||
->getMockBuilder('\Kanboard\Model\ProjectIntegration')
|
||||
->setConstructorArgs(array($this->container))
|
||||
->setMethods(array(
|
||||
'getParameters',
|
||||
))
|
||||
->getMock();
|
||||
|
||||
$this->container['config']
|
||||
->expects($this->once())
|
||||
->method('get')
|
||||
->with($this->equalTo('integration_slack_webhook'))
|
||||
->will($this->returnValue(0));
|
||||
|
||||
$this->container['projectIntegration']
|
||||
->expects($this->once())
|
||||
->method('getParameters')
|
||||
->with($this->equalTo(1))
|
||||
->will($this->returnValue(array('slack_webhook_url' => 'my_project_url')));
|
||||
|
||||
$this->assertEquals('my_project_url', $slack->getWebhookUrl(1));
|
||||
}
|
||||
|
||||
public function testSendPayloadWithChannel()
|
||||
{
|
||||
$this->container['httpClient'] = $this
|
||||
->getMockBuilder('\Kanboard\Core\HttpClient')
|
||||
->setConstructorArgs(array($this->container))
|
||||
->setMethods(array(
|
||||
'postJson',
|
||||
))
|
||||
->getMock();
|
||||
|
||||
$slack = $this
|
||||
->getMockBuilder('\Kanboard\Integration\SlackWebhook')
|
||||
->setConstructorArgs(array($this->container))
|
||||
->setMethods(array(
|
||||
'getChannel',
|
||||
'getWebhookUrl',
|
||||
))
|
||||
->getMock();
|
||||
|
||||
$slack
|
||||
->expects($this->at(0))
|
||||
->method('getChannel')
|
||||
->with(
|
||||
$this->equalTo(1)
|
||||
)
|
||||
->will($this->returnValue('mychannel'));
|
||||
|
||||
$slack
|
||||
->expects($this->at(1))
|
||||
->method('getWebhookUrl')
|
||||
->with(
|
||||
$this->equalTo(1)
|
||||
)
|
||||
->will($this->returnValue('url'));
|
||||
|
||||
$this->container['httpClient']
|
||||
->expects($this->once())
|
||||
->method('postJson')
|
||||
->with(
|
||||
$this->equalTo('url'),
|
||||
$this->equalTo(array('text' => 'test', 'channel' => 'mychannel'))
|
||||
);
|
||||
|
||||
$slack->sendPayload(1, array('text' => 'test'));
|
||||
}
|
||||
|
||||
public function testSendPayloadWithoutChannel()
|
||||
{
|
||||
$this->container['httpClient'] = $this
|
||||
->getMockBuilder('\Kanboard\Core\HttpClient')
|
||||
->setConstructorArgs(array($this->container))
|
||||
->setMethods(array(
|
||||
'postJson',
|
||||
))
|
||||
->getMock();
|
||||
|
||||
$slack = $this
|
||||
->getMockBuilder('\Kanboard\Integration\SlackWebhook')
|
||||
->setConstructorArgs(array($this->container))
|
||||
->setMethods(array(
|
||||
'getChannel',
|
||||
'getWebhookUrl',
|
||||
))
|
||||
->getMock();
|
||||
|
||||
$slack
|
||||
->expects($this->at(0))
|
||||
->method('getChannel')
|
||||
->with(
|
||||
$this->equalTo(1)
|
||||
)
|
||||
->will($this->returnValue(''));
|
||||
|
||||
$slack
|
||||
->expects($this->at(1))
|
||||
->method('getWebhookUrl')
|
||||
->with(
|
||||
$this->equalTo(1)
|
||||
)
|
||||
->will($this->returnValue('url'));
|
||||
|
||||
$this->container['httpClient']
|
||||
->expects($this->once())
|
||||
->method('postJson')
|
||||
->with(
|
||||
$this->equalTo('url'),
|
||||
$this->equalTo(array('text' => 'test'))
|
||||
);
|
||||
|
||||
$slack->sendPayload(1, array('text' => 'test'));
|
||||
}
|
||||
|
||||
public function testSendMessage()
|
||||
{
|
||||
$message = 'test';
|
||||
|
||||
$payload = array(
|
||||
'text' => $message,
|
||||
'username' => 'Kanboard',
|
||||
'icon_url' => 'http://kanboard.net/assets/img/favicon.png',
|
||||
);
|
||||
|
||||
$slack = $this
|
||||
->getMockBuilder('\Kanboard\Integration\SlackWebhook')
|
||||
->setConstructorArgs(array($this->container))
|
||||
->setMethods(array(
|
||||
'sendPayload',
|
||||
))
|
||||
->getMock();
|
||||
|
||||
$slack
|
||||
->expects($this->once())
|
||||
->method('sendPayload')
|
||||
->with(
|
||||
$this->equalTo(1),
|
||||
$this->equalTo($payload)
|
||||
);
|
||||
|
||||
$slack->sendMessage(1, $message);
|
||||
}
|
||||
|
||||
public function testNotify()
|
||||
{
|
||||
$message = '*[foobar]* FooBar created the task #1 (task #1)';
|
||||
|
||||
$this->container['session']['user'] = array('username' => 'foobar', 'name' => 'FooBar');
|
||||
|
||||
$p = new Project($this->container);
|
||||
$this->assertEquals(1, $p->create(array('name' => 'foobar')));
|
||||
$this->assertTrue($this->container['config']->save(array('integration_slack_webhook' => 1)));
|
||||
|
||||
$slack = $this
|
||||
->getMockBuilder('\Kanboard\Integration\SlackWebhook')
|
||||
->setConstructorArgs(array($this->container))
|
||||
->setMethods(array(
|
||||
'sendMessage',
|
||||
))
|
||||
->getMock();
|
||||
|
||||
$slack
|
||||
->expects($this->once())
|
||||
->method('sendMessage')
|
||||
->with(
|
||||
$this->equalTo(1),
|
||||
$this->equalTo($message)
|
||||
);
|
||||
|
||||
$slack->notify(1, 1, Task::EVENT_CREATE, array('task' => array('id' => 1, 'title' => 'task #1')));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
require_once __DIR__.'/../Base.php';
|
||||
|
||||
use Kanboard\Model\TaskFinder;
|
||||
use Kanboard\Model\TaskCreation;
|
||||
use Kanboard\Model\Subtask;
|
||||
use Kanboard\Model\Comment;
|
||||
use Kanboard\Model\User;
|
||||
use Kanboard\Model\File;
|
||||
use Kanboard\Model\Task;
|
||||
use Kanboard\Model\Project;
|
||||
use Kanboard\Model\Notification;
|
||||
use Kanboard\Subscriber\NotificationSubscriber;
|
||||
|
||||
class NotificationTest extends Base
|
||||
{
|
||||
public function testGetTitle()
|
||||
{
|
||||
$wn = new Notification($this->container);
|
||||
$p = new Project($this->container);
|
||||
$tf = new TaskFinder($this->container);
|
||||
$tc = new TaskCreation($this->container);
|
||||
$s = new Subtask($this->container);
|
||||
$c = new Comment($this->container);
|
||||
$f = new File($this->container);
|
||||
|
||||
$this->assertEquals(1, $p->create(array('name' => 'test')));
|
||||
$this->assertEquals(1, $tc->create(array('title' => 'test', 'project_id' => 1)));
|
||||
$this->assertEquals(1, $s->create(array('title' => 'test', 'task_id' => 1)));
|
||||
$this->assertEquals(1, $c->create(array('comment' => 'test', 'task_id' => 1, 'user_id' => 1)));
|
||||
$this->assertEquals(1, $f->create(1, 'test', 'blah', 123));
|
||||
|
||||
$task = $tf->getDetails(1);
|
||||
$subtask = $s->getById(1, true);
|
||||
$comment = $c->getById(1);
|
||||
$file = $c->getById(1);
|
||||
|
||||
$this->assertNotEmpty($task);
|
||||
$this->assertNotEmpty($subtask);
|
||||
$this->assertNotEmpty($comment);
|
||||
$this->assertNotEmpty($file);
|
||||
|
||||
foreach (NotificationSubscriber::getSubscribedEvents() as $event_name => $values) {
|
||||
$title = $wn->getTitleWithoutAuthor($event_name, array(
|
||||
'task' => $task,
|
||||
'comment' => $comment,
|
||||
'subtask' => $subtask,
|
||||
'file' => $file,
|
||||
'changes' => array()
|
||||
));
|
||||
|
||||
$this->assertNotEmpty($title);
|
||||
|
||||
$title = $wn->getTitleWithAuthor('foobar', $event_name, array(
|
||||
'task' => $task,
|
||||
'comment' => $comment,
|
||||
'subtask' => $subtask,
|
||||
'file' => $file,
|
||||
'changes' => array()
|
||||
));
|
||||
|
||||
$this->assertNotEmpty($title);
|
||||
}
|
||||
|
||||
$this->assertNotEmpty($wn->getTitleWithoutAuthor(Task::EVENT_OVERDUE, array('tasks' => array(array('id' => 1)))));
|
||||
$this->assertNotEmpty($wn->getTitleWithoutAuthor('unkown', array()));
|
||||
}
|
||||
}
|
||||
|
|
@ -10,49 +10,9 @@ use Kanboard\Model\Project;
|
|||
use Kanboard\Model\Subtask;
|
||||
use Kanboard\Model\Comment;
|
||||
use Kanboard\Model\File;
|
||||
use Kanboard\Subscriber\NotificationSubscriber;
|
||||
|
||||
class ProjectActivityTest extends Base
|
||||
{
|
||||
public function testGetTitle()
|
||||
{
|
||||
$pa = new ProjectActivity($this->container);
|
||||
$p = new Project($this->container);
|
||||
$tf = new TaskFinder($this->container);
|
||||
$tc = new TaskCreation($this->container);
|
||||
$s = new Subtask($this->container);
|
||||
$c = new Comment($this->container);
|
||||
$f = new File($this->container);
|
||||
|
||||
$this->assertEquals(1, $p->create(array('name' => 'test')));
|
||||
$this->assertEquals(1, $tc->create(array('title' => 'test', 'project_id' => 1)));
|
||||
$this->assertEquals(1, $s->create(array('title' => 'test', 'task_id' => 1)));
|
||||
$this->assertEquals(1, $c->create(array('comment' => 'test', 'task_id' => 1, 'user_id' => 1)));
|
||||
$this->assertEquals(1, $f->create(1, 'test', 'blah', 123));
|
||||
|
||||
$task = $tf->getDetails(1);
|
||||
$subtask = $s->getById(1, true);
|
||||
$comment = $c->getById(1);
|
||||
$file = $c->getById(1);
|
||||
|
||||
$this->assertNotEmpty($task);
|
||||
$this->assertNotEmpty($subtask);
|
||||
$this->assertNotEmpty($comment);
|
||||
$this->assertNotEmpty($file);
|
||||
|
||||
foreach (NotificationSubscriber::getSubscribedEvents() as $event_name => $listeners) {
|
||||
$this->assertNotEmpty($pa->getTitle(array(
|
||||
'event_name' => $event_name,
|
||||
'task' => $task,
|
||||
'comment' => $comment,
|
||||
'subtask' => $subtask,
|
||||
'file' => $file,
|
||||
'author' => 'bob',
|
||||
'changes' => array())
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
public function testDecode()
|
||||
{
|
||||
$e = new ProjectActivity($this->container);
|
||||
|
|
|
|||
|
|
@ -32,10 +32,15 @@ class ProjectNotificationTypeTest extends Base
|
|||
|
||||
// Hidden type
|
||||
$nt->setType('baz', 'Baz', 'Something3', true);
|
||||
$this->assertEquals(array('baz'), $nt->getSelectedTypes(1));
|
||||
$this->assertEmpty($nt->getSelectedTypes(1));
|
||||
|
||||
// User defined types
|
||||
// User defined types but not registered
|
||||
$this->assertTrue($nt->saveSelectedTypes(1, array('foo', 'bar')));
|
||||
$this->assertEquals(array('baz', 'bar', 'foo'), $nt->getSelectedTypes(1));
|
||||
$this->assertEmpty($nt->getSelectedTypes(1));
|
||||
|
||||
// User defined types and registered
|
||||
$nt->setType('bar', 'Bar', 'Something4');
|
||||
$nt->setType('foo', 'Foo', 'Something3');
|
||||
$this->assertEquals(array('bar', 'foo'), $nt->getSelectedTypes(1));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,6 +50,22 @@ class UserNotificationTest extends Base
|
|||
'notification_projects' => array(),
|
||||
));
|
||||
|
||||
$this->container['userNotificationType']
|
||||
->expects($this->at(0))
|
||||
->method('getSelectedTypes')
|
||||
->will($this->returnValue(array('email')));
|
||||
|
||||
$this->container['userNotificationType']
|
||||
->expects($this->at(1))
|
||||
->method('getSelectedTypes')
|
||||
->will($this->returnValue(array('email')));
|
||||
|
||||
$this->container['userNotificationType']
|
||||
->expects($this->at(2))
|
||||
->method('getSelectedTypes')
|
||||
->with($this->equalTo(1))
|
||||
->will($this->returnValue(array('email', 'web')));
|
||||
|
||||
$settings = $n->readSettings(1);
|
||||
$this->assertNotEmpty($settings);
|
||||
$this->assertEquals(1, $settings['notifications_enabled']);
|
||||
|
|
@ -183,12 +199,17 @@ class UserNotificationTest extends Base
|
|||
|
||||
$this->container['userNotificationType']
|
||||
->expects($this->at(0))
|
||||
->method('getSelectedTypes')
|
||||
->will($this->returnValue(array('email', 'web')));
|
||||
|
||||
$this->container['userNotificationType']
|
||||
->expects($this->at(1))
|
||||
->method('getType')
|
||||
->with($this->equalTo('email'))
|
||||
->will($this->returnValue($notifier));
|
||||
|
||||
$this->container['userNotificationType']
|
||||
->expects($this->at(1))
|
||||
->expects($this->at(2))
|
||||
->method('getType')
|
||||
->with($this->equalTo('web'))
|
||||
->will($this->returnValue($notifier));
|
||||
|
|
|
|||
|
|
@ -19,12 +19,21 @@ class UserNotificationTypeTest extends Base
|
|||
public function testGetSelectedTypes()
|
||||
{
|
||||
$nt = new UserNotificationType($this->container);
|
||||
$types = $nt->getSelectedTypes(1);
|
||||
$this->assertEmpty($types);
|
||||
|
||||
$this->assertTrue($nt->saveSelectedTypes(1, array('email', 'web')));
|
||||
$types = $nt->getSelectedTypes(1);
|
||||
$this->assertNotEmpty($types);
|
||||
$this->assertEquals(array('email', 'web'), $types);
|
||||
// No type defined
|
||||
$this->assertEmpty($nt->getSelectedTypes(1));
|
||||
|
||||
// Hidden type
|
||||
$nt->setType('baz', 'Baz', 'Something3', true);
|
||||
$this->assertEmpty($nt->getSelectedTypes(1));
|
||||
|
||||
// User defined types but not registered
|
||||
$this->assertTrue($nt->saveSelectedTypes(1, array('foo', 'bar')));
|
||||
$this->assertEmpty($nt->getSelectedTypes(1));
|
||||
|
||||
// User defined types and registered
|
||||
$nt->setType('bar', 'Bar', 'Something4');
|
||||
$nt->setType('foo', 'Foo', 'Something3');
|
||||
$this->assertEquals(array('bar', 'foo'), $nt->getSelectedTypes(1));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,52 +11,9 @@ use Kanboard\Model\File;
|
|||
use Kanboard\Model\Task;
|
||||
use Kanboard\Model\Project;
|
||||
use Kanboard\Model\UserUnreadNotification;
|
||||
use Kanboard\Subscriber\NotificationSubscriber;
|
||||
|
||||
class UserUnreadNotificationTest extends Base
|
||||
{
|
||||
public function testGetTitle()
|
||||
{
|
||||
$wn = new UserUnreadNotification($this->container);
|
||||
$p = new Project($this->container);
|
||||
$tf = new TaskFinder($this->container);
|
||||
$tc = new TaskCreation($this->container);
|
||||
$s = new Subtask($this->container);
|
||||
$c = new Comment($this->container);
|
||||
$f = new File($this->container);
|
||||
|
||||
$this->assertEquals(1, $p->create(array('name' => 'test')));
|
||||
$this->assertEquals(1, $tc->create(array('title' => 'test', 'project_id' => 1)));
|
||||
$this->assertEquals(1, $s->create(array('title' => 'test', 'task_id' => 1)));
|
||||
$this->assertEquals(1, $c->create(array('comment' => 'test', 'task_id' => 1, 'user_id' => 1)));
|
||||
$this->assertEquals(1, $f->create(1, 'test', 'blah', 123));
|
||||
|
||||
$task = $tf->getDetails(1);
|
||||
$subtask = $s->getById(1, true);
|
||||
$comment = $c->getById(1);
|
||||
$file = $c->getById(1);
|
||||
|
||||
$this->assertNotEmpty($task);
|
||||
$this->assertNotEmpty($subtask);
|
||||
$this->assertNotEmpty($comment);
|
||||
$this->assertNotEmpty($file);
|
||||
|
||||
foreach (NotificationSubscriber::getSubscribedEvents() as $event_name => $values) {
|
||||
$title = $wn->getTitleFromEvent($event_name, array(
|
||||
'task' => $task,
|
||||
'comment' => $comment,
|
||||
'subtask' => $subtask,
|
||||
'file' => $file,
|
||||
'changes' => array()
|
||||
));
|
||||
|
||||
$this->assertNotEmpty($title);
|
||||
}
|
||||
|
||||
$this->assertNotEmpty($wn->getTitleFromEvent(Task::EVENT_OVERDUE, array('tasks' => array(array('id' => 1)))));
|
||||
$this->assertNotEmpty($wn->getTitleFromEvent('unkown', array()));
|
||||
}
|
||||
|
||||
public function testHasNotification()
|
||||
{
|
||||
$wn = new UserUnreadNotification($this->container);
|
||||
|
|
|
|||
Loading…
Reference in New Issue