1
0
Fork 0
mirror of https://github.com/YunoHost-Apps/kanboard_ynh.git synced 2024-09-03 19:36:17 +02:00

Update kanboard v1.0.11

This commit is contained in:
mbugeia 2015-01-16 14:23:05 +01:00
parent 1acd2f8689
commit ce6c8e2aa9
938 changed files with 11336 additions and 119656 deletions

View file

@ -2,9 +2,8 @@
namespace Action; namespace Action;
use Event\GenericEvent;
use Pimple\Container; use Pimple\Container;
use Core\Listener;
use Core\Tool;
/** /**
* Base class for automatic actions * Base class for automatic actions
@ -12,7 +11,7 @@ use Core\Tool;
* @package action * @package action
* @author Frederic Guillot * @author Frederic Guillot
* *
* @property \Model\Acl $acl * @property \Model\UserSession $userSession
* @property \Model\Comment $comment * @property \Model\Comment $comment
* @property \Model\Task $task * @property \Model\Task $task
* @property \Model\TaskCreation $taskCreation * @property \Model\TaskCreation $taskCreation
@ -21,8 +20,16 @@ use Core\Tool;
* @property \Model\TaskFinder $taskFinder * @property \Model\TaskFinder $taskFinder
* @property \Model\TaskStatus $taskStatus * @property \Model\TaskStatus $taskStatus
*/ */
abstract class Base implements Listener abstract class Base
{ {
/**
* Flag for called listener
*
* @access private
* @var boolean
*/
private $called = false;
/** /**
* Project id * Project id
* *
@ -114,6 +121,7 @@ abstract class Base implements Listener
$this->container = $container; $this->container = $container;
$this->project_id = $project_id; $this->project_id = $project_id;
$this->event_name = $event_name; $this->event_name = $event_name;
$this->called = false;
} }
/** /**
@ -136,7 +144,7 @@ abstract class Base implements Listener
*/ */
public function __get($name) public function __get($name)
{ {
return Tool::loadModel($this->container, $name); return $this->container[$name];
} }
/** /**
@ -183,7 +191,6 @@ abstract class Base implements Listener
* Check if the event is compatible with the action * Check if the event is compatible with the action
* *
* @access public * @access public
* @param array $data Event data dictionary
* @return bool * @return bool
*/ */
public function hasCompatibleEvent() public function hasCompatibleEvent()
@ -225,12 +232,20 @@ abstract class Base implements Listener
* Execute the action * Execute the action
* *
* @access public * @access public
* @param array $data Event data dictionary * @param \Event\GenericEvent $event Event data dictionary
* @return bool True if the action was executed or false when not executed * @return bool True if the action was executed or false when not executed
*/ */
public function execute(array $data) public function execute(GenericEvent $event)
{ {
// Avoid infinite loop, a listener instance can be called only one time
if ($this->called) {
return false;
}
$data = $event->getAll();
if ($this->isExecutable($data)) { if ($this->isExecutable($data)) {
$this->called = true;
return $this->doAction($data); return $this->doAction($data);
} }

View file

@ -2,7 +2,7 @@
namespace Action; namespace Action;
use Model\GithubWebhook; use Integration\GithubWebhook;
/** /**
* Create automatically a comment from a webhook * Create automatically a comment from a webhook
@ -16,7 +16,7 @@ class CommentCreation extends Base
* Get the list of compatible events * Get the list of compatible events
* *
* @access public * @access public
* @return array * @return string[]
*/ */
public function getCompatibleEvents() public function getCompatibleEvents()
{ {
@ -29,7 +29,7 @@ class CommentCreation extends Base
* Get the required parameter for the action (defined by the user) * Get the required parameter for the action (defined by the user)
* *
* @access public * @access public
* @return array * @return string[]
*/ */
public function getActionRequiredParameters() public function getActionRequiredParameters()
{ {

View file

@ -67,7 +67,7 @@ class TaskAssignCategoryColor extends Base
'category_id' => $this->getParam('category_id'), 'category_id' => $this->getParam('category_id'),
); );
return $this->taskModification->update($values, false); return $this->taskModification->update($values);
} }
/** /**

View file

@ -2,7 +2,7 @@
namespace Action; namespace Action;
use Model\GithubWebhook; use Integration\GithubWebhook;
/** /**
* Set a category automatically according to a label * Set a category automatically according to a label
@ -67,7 +67,7 @@ class TaskAssignCategoryLabel extends Base
'category_id' => isset($data['category_id']) ? $data['category_id'] : $this->getParam('category_id'), 'category_id' => isset($data['category_id']) ? $data['category_id'] : $this->getParam('category_id'),
); );
return $this->taskModification->update($values, false); return $this->taskModification->update($values);
} }
/** /**

View file

@ -67,7 +67,7 @@ class TaskAssignColorCategory extends Base
'color_id' => $this->getParam('color_id'), 'color_id' => $this->getParam('color_id'),
); );
return $this->taskModification->update($values, false); return $this->taskModification->update($values);
} }
/** /**

View file

@ -68,7 +68,7 @@ class TaskAssignColorUser extends Base
'color_id' => $this->getParam('color_id'), 'color_id' => $this->getParam('color_id'),
); );
return $this->taskModification->update($values, false); return $this->taskModification->update($values);
} }
/** /**

View file

@ -62,12 +62,16 @@ class TaskAssignCurrentUser extends Base
*/ */
public function doAction(array $data) public function doAction(array $data)
{ {
if (! $this->userSession->isLogged()) {
return false;
}
$values = array( $values = array(
'id' => $data['task_id'], 'id' => $data['task_id'],
'owner_id' => $this->acl->getUserId(), 'owner_id' => $this->userSession->getId(),
); );
return $this->taskModification->update($values, false); return $this->taskModification->update($values);
} }
/** /**

View file

@ -68,7 +68,7 @@ class TaskAssignSpecificUser extends Base
'owner_id' => $this->getParam('user_id'), 'owner_id' => $this->getParam('user_id'),
); );
return $this->taskModification->update($values, false); return $this->taskModification->update($values);
} }
/** /**

View file

@ -2,7 +2,7 @@
namespace Action; namespace Action;
use Model\GithubWebhook; use Integration\GithubWebhook;
/** /**
* Assign a task to someone * Assign a task to someone
@ -64,7 +64,7 @@ class TaskAssignUser extends Base
'owner_id' => $data['owner_id'], 'owner_id' => $data['owner_id'],
); );
return $this->taskModification->update($values, false); return $this->taskModification->update($values);
} }
/** /**

View file

@ -2,7 +2,8 @@
namespace Action; namespace Action;
use Model\GithubWebhook; use Integration\GitlabWebhook;
use Integration\GithubWebhook;
use Model\Task; use Model\Task;
/** /**
@ -25,6 +26,8 @@ class TaskClose extends Base
Task::EVENT_MOVE_COLUMN, Task::EVENT_MOVE_COLUMN,
GithubWebhook::EVENT_COMMIT, GithubWebhook::EVENT_COMMIT,
GithubWebhook::EVENT_ISSUE_CLOSED, GithubWebhook::EVENT_ISSUE_CLOSED,
GitlabWebhook::EVENT_COMMIT,
GitlabWebhook::EVENT_ISSUE_CLOSED,
); );
} }
@ -39,6 +42,8 @@ class TaskClose extends Base
switch ($this->event_name) { switch ($this->event_name) {
case GithubWebhook::EVENT_COMMIT: case GithubWebhook::EVENT_COMMIT:
case GithubWebhook::EVENT_ISSUE_CLOSED: case GithubWebhook::EVENT_ISSUE_CLOSED:
case GitlabWebhook::EVENT_COMMIT:
case GitlabWebhook::EVENT_ISSUE_CLOSED:
return array(); return array();
default: default:
return array('column_id' => t('Column')); return array('column_id' => t('Column'));
@ -56,6 +61,8 @@ class TaskClose extends Base
switch ($this->event_name) { switch ($this->event_name) {
case GithubWebhook::EVENT_COMMIT: case GithubWebhook::EVENT_COMMIT:
case GithubWebhook::EVENT_ISSUE_CLOSED: case GithubWebhook::EVENT_ISSUE_CLOSED:
case GitlabWebhook::EVENT_COMMIT:
case GitlabWebhook::EVENT_ISSUE_CLOSED:
return array('task_id'); return array('task_id');
default: default:
return array('task_id', 'column_id'); return array('task_id', 'column_id');
@ -86,6 +93,8 @@ class TaskClose extends Base
switch ($this->event_name) { switch ($this->event_name) {
case GithubWebhook::EVENT_COMMIT: case GithubWebhook::EVENT_COMMIT:
case GithubWebhook::EVENT_ISSUE_CLOSED: case GithubWebhook::EVENT_ISSUE_CLOSED:
case GitlabWebhook::EVENT_COMMIT:
case GitlabWebhook::EVENT_ISSUE_CLOSED:
return true; return true;
default: default:
return $data['column_id'] == $this->getParam('column_id'); return $data['column_id'] == $this->getParam('column_id');

View file

@ -2,7 +2,8 @@
namespace Action; namespace Action;
use Model\GithubWebhook; use Integration\GithubWebhook;
use Integration\GitlabWebhook;
/** /**
* Create automatically a task from a webhook * Create automatically a task from a webhook
@ -22,6 +23,7 @@ class TaskCreation extends Base
{ {
return array( return array(
GithubWebhook::EVENT_ISSUE_OPENED, GithubWebhook::EVENT_ISSUE_OPENED,
GitlabWebhook::EVENT_ISSUE_OPENED,
); );
} }
@ -63,7 +65,7 @@ class TaskCreation extends Base
'project_id' => $data['project_id'], 'project_id' => $data['project_id'],
'title' => $data['title'], 'title' => $data['title'],
'reference' => $data['reference'], 'reference' => $data['reference'],
'description' => $data['description'], 'description' => isset($data['description']) ? $data['description'] : '',
)); ));
} }

View file

@ -2,7 +2,7 @@
namespace Action; namespace Action;
use Model\GithubWebhook; use Integration\GithubWebhook;
/** /**
* Open automatically a task * Open automatically a task

View file

@ -2,7 +2,6 @@
namespace Auth; namespace Auth;
use Core\Tool;
use Pimple\Container; use Pimple\Container;
/** /**
@ -14,6 +13,7 @@ use Pimple\Container;
* @property \Model\Acl $acl * @property \Model\Acl $acl
* @property \Model\LastLogin $lastLogin * @property \Model\LastLogin $lastLogin
* @property \Model\User $user * @property \Model\User $user
* @property \Model\UserSession $userSession
*/ */
abstract class Base abstract class Base
{ {
@ -54,6 +54,6 @@ abstract class Base
*/ */
public function __get($name) public function __get($name)
{ {
return Tool::loadModel($this->container, $name); return $this->container[$name];
} }
} }

View file

@ -3,7 +3,7 @@
namespace Auth; namespace Auth;
use Model\User; use Model\User;
use Core\Request; use Event\AuthEvent;
/** /**
* Database authentication * Database authentication
@ -33,18 +33,8 @@ class Database extends Base
$user = $this->db->table(User::TABLE)->eq('username', $username)->eq('is_ldap_user', 0)->findOne(); $user = $this->db->table(User::TABLE)->eq('username', $username)->eq('is_ldap_user', 0)->findOne();
if ($user && password_verify($password, $user['password'])) { if ($user && password_verify($password, $user['password'])) {
$this->userSession->refresh($user);
// Update user session $this->container['dispatcher']->dispatch('auth.success', new AuthEvent(self::AUTH_NAME, $user['id']));
$this->user->updateSession($user);
// Update login history
$this->lastLogin->create(
self::AUTH_NAME,
$user['id'],
Request::getIpAddress(),
Request::getUserAgent()
);
return true; return true;
} }

View file

@ -2,7 +2,7 @@
namespace Auth; namespace Auth;
use Core\Request; use Event\AuthEvent;
use OAuth\Common\Storage\Session; use OAuth\Common\Storage\Session;
use OAuth\Common\Consumer\Credentials; use OAuth\Common\Consumer\Credentials;
use OAuth\Common\Http\Uri\UriFactory; use OAuth\Common\Http\Uri\UriFactory;
@ -35,18 +35,8 @@ class GitHub extends Base
$user = $this->user->getByGitHubId($github_id); $user = $this->user->getByGitHubId($github_id);
if ($user) { if ($user) {
$this->userSession->refresh($user);
// Create the user session $this->container['dispatcher']->dispatch('auth.success', new AuthEvent(self::AUTH_NAME, $user['id']));
$this->user->updateSession($user);
// Update login history
$this->lastLogin->create(
self::AUTH_NAME,
$user['id'],
Request::getIpAddress(),
Request::getUserAgent()
);
return true; return true;
} }

View file

@ -2,7 +2,7 @@
namespace Auth; namespace Auth;
use Core\Request; use Event\AuthEvent;
use OAuth\Common\Storage\Session; use OAuth\Common\Storage\Session;
use OAuth\Common\Consumer\Credentials; use OAuth\Common\Consumer\Credentials;
use OAuth\Common\Http\Uri\UriFactory; use OAuth\Common\Http\Uri\UriFactory;
@ -36,18 +36,8 @@ class Google extends Base
$user = $this->user->getByGoogleId($google_id); $user = $this->user->getByGoogleId($google_id);
if ($user) { if ($user) {
$this->userSession->refresh($user);
// Create the user session $this->container['dispatcher']->dispatch('auth.success', new AuthEvent(self::AUTH_NAME, $user['id']));
$this->user->updateSession($user);
// Update login history
$this->lastLogin->create(
self::AUTH_NAME,
$user['id'],
Request::getIpAddress(),
Request::getUserAgent()
);
return true; return true;
} }

View file

@ -2,7 +2,7 @@
namespace Auth; namespace Auth;
use Core\Request; use Event\AuthEvent;
/** /**
* LDAP model * LDAP model
@ -54,15 +54,8 @@ class Ldap extends Base
} }
// We open the session // We open the session
$this->user->updateSession($user); $this->userSession->refresh($user);
$this->container['dispatcher']->dispatch('auth.success', new AuthEvent(self::AUTH_NAME, $user['id']));
// Update login history
$this->lastLogin->create(
self::AUTH_NAME,
$user['id'],
Request::getIpAddress(),
Request::getUserAgent()
);
return true; return true;
} }

View file

@ -3,6 +3,7 @@
namespace Auth; namespace Auth;
use Core\Request; use Core\Request;
use Event\AuthEvent;
use Core\Security; use Core\Security;
/** /**
@ -100,15 +101,11 @@ class RememberMe extends Base
); );
// Create the session // Create the session
$this->user->updateSession($this->user->getById($record['user_id'])); $this->userSession->refresh($this->user->getById($record['user_id']));
$this->acl->isRememberMe(true);
// Update last login infos $this->container['dispatcher']->dispatch(
$this->lastLogin->create( 'auth.success',
self::AUTH_NAME, new AuthEvent(self::AUTH_NAME, $this->userSession->getId())
$this->acl->getUserId(),
Request::getIpAddress(),
Request::getUserAgent()
); );
return true; return true;

View file

@ -2,8 +2,7 @@
namespace Auth; namespace Auth;
use Core\Request; use Event\AuthEvent;
use Core\Security;
/** /**
* ReverseProxy backend * ReverseProxy backend
@ -38,16 +37,8 @@ class ReverseProxy extends Base
$user = $this->user->getByUsername($login); $user = $this->user->getByUsername($login);
} }
// Create the user session $this->userSession->refresh($user);
$this->user->updateSession($user); $this->container['dispatcher']->dispatch('auth.success', new AuthEvent(self::AUTH_NAME, $user['id']));
// Update login history
$this->lastLogin->create(
self::AUTH_NAME,
$user['id'],
Request::getIpAddress(),
Request::getUserAgent()
);
return true; return true;
} }

View file

@ -2,7 +2,6 @@
namespace Console; namespace Console;
use Core\Tool;
use Pimple\Container; use Pimple\Container;
use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Command\Command;
@ -17,6 +16,7 @@ use Symfony\Component\Console\Command\Command;
* @property \Model\ProjectPermission $projectPermission * @property \Model\ProjectPermission $projectPermission
* @property \Model\ProjectAnalytic $projectAnalytic * @property \Model\ProjectAnalytic $projectAnalytic
* @property \Model\ProjectDailySummary $projectDailySummary * @property \Model\ProjectDailySummary $projectDailySummary
* @property \Model\SubtaskExport $subtaskExport
* @property \Model\Task $task * @property \Model\Task $task
* @property \Model\TaskExport $taskExport * @property \Model\TaskExport $taskExport
* @property \Model\TaskFinder $taskFinder * @property \Model\TaskFinder $taskFinder
@ -52,6 +52,6 @@ abstract class Base extends Command
*/ */
public function __get($name) public function __get($name)
{ {
return Tool::loadModel($this->container, $name); return $this->container[$name];
} }
} }

View file

@ -3,9 +3,7 @@
namespace Console; namespace Console;
use Model\Project; use Model\Project;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
class ProjectDailySummaryCalculation extends Base class ProjectDailySummaryCalculation extends Base

View file

@ -5,7 +5,6 @@ namespace Console;
use Core\Tool; use Core\Tool;
use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
class ProjectDailySummaryExport extends Base class ProjectDailySummaryExport extends Base

View file

@ -0,0 +1,34 @@
<?php
namespace Console;
use Core\Tool;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class SubtaskExport extends Base
{
protected function configure()
{
$this
->setName('export:subtasks')
->setDescription('Subtasks CSV export')
->addArgument('project_id', InputArgument::REQUIRED, 'Project id')
->addArgument('start_date', InputArgument::REQUIRED, 'Start date (YYYY-MM-DD)')
->addArgument('end_date', InputArgument::REQUIRED, 'End date (YYYY-MM-DD)');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$data = $this->subtaskExport->export(
$input->getArgument('project_id'),
$input->getArgument('start_date'),
$input->getArgument('end_date')
);
if (is_array($data)) {
Tool::csv($data);
}
}
}

View file

@ -5,7 +5,6 @@ namespace Console;
use Core\Tool; use Core\Tool;
use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
class TaskExport extends Base class TaskExport extends Base

View file

@ -3,7 +3,6 @@
namespace Console; namespace Console;
use Symfony\Component\Console\Helper\Table; use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;

View file

@ -17,7 +17,7 @@ class Action extends Base
*/ */
public function index() public function index()
{ {
$project = $this->getProjectManagement(); $project = $this->getProject();
$this->response->html($this->projectLayout('action/index', array( $this->response->html($this->projectLayout('action/index', array(
'values' => array('project_id' => $project['id']), 'values' => array('project_id' => $project['id']),
@ -42,7 +42,7 @@ class Action extends Base
*/ */
public function event() public function event()
{ {
$project = $this->getProjectManagement(); $project = $this->getProject();
$values = $this->request->getValues(); $values = $this->request->getValues();
if (empty($values['action_name']) || empty($values['project_id'])) { if (empty($values['action_name']) || empty($values['project_id'])) {
@ -64,7 +64,7 @@ class Action extends Base
*/ */
public function params() public function params()
{ {
$project = $this->getProjectManagement(); $project = $this->getProject();
$values = $this->request->getValues(); $values = $this->request->getValues();
if (empty($values['action_name']) || empty($values['project_id']) || empty($values['event_name'])) { if (empty($values['action_name']) || empty($values['project_id']) || empty($values['event_name'])) {
@ -101,7 +101,7 @@ class Action extends Base
*/ */
public function create() public function create()
{ {
$this->doCreation($this->getProjectManagement(), $this->request->getValues()); $this->doCreation($this->getProject(), $this->request->getValues());
} }
/** /**
@ -135,7 +135,7 @@ class Action extends Base
*/ */
public function confirm() public function confirm()
{ {
$project = $this->getProjectManagement(); $project = $this->getProject();
$this->response->html($this->projectLayout('action/remove', array( $this->response->html($this->projectLayout('action/remove', array(
'action' => $this->action->getById($this->request->getIntegerParam('action_id')), 'action' => $this->action->getById($this->request->getIntegerParam('action_id')),
@ -154,7 +154,7 @@ class Action extends Base
public function remove() public function remove()
{ {
$this->checkCSRFParam(); $this->checkCSRFParam();
$project = $this->getProjectManagement(); $project = $this->getProject();
$action = $this->action->getById($this->request->getIntegerParam('action_id')); $action = $this->action->getById($this->request->getIntegerParam('action_id'));
if ($action && $this->action->remove($action['id'])) { if ($action && $this->action->remove($action['id'])) {

View file

@ -20,8 +20,8 @@ class Analytic extends Base
*/ */
private function layout($template, array $params) private function layout($template, array $params)
{ {
$params['board_selector'] = $this->projectPermission->getAllowedProjects($this->acl->getUserId()); $params['board_selector'] = $this->projectPermission->getAllowedProjects($this->userSession->getId());
$params['analytic_content_for_layout'] = $this->template->load($template, $params); $params['analytic_content_for_layout'] = $this->template->render($template, $params);
return $this->template->layout('analytic/layout', $params); return $this->template->layout('analytic/layout', $params);
} }

View file

@ -2,9 +2,7 @@
namespace Controller; namespace Controller;
use Model\Project as ProjectModel;
use Model\SubTask as SubTaskModel; use Model\SubTask as SubTaskModel;
use Helper;
/** /**
* Application controller * Application controller
@ -36,7 +34,7 @@ class App extends Base
$direction = $this->request->getStringParam('direction'); $direction = $this->request->getStringParam('direction');
$order = $this->request->getStringParam('order'); $order = $this->request->getStringParam('order');
$user_id = $this->acl->getUserId(); $user_id = $this->userSession->getId();
$projects = $this->projectPermission->getMemberProjects($user_id); $projects = $this->projectPermission->getMemberProjects($user_id);
$project_ids = array_keys($projects); $project_ids = array_keys($projects);
@ -57,6 +55,11 @@ class App extends Base
* Get tasks pagination * Get tasks pagination
* *
* @access public * @access public
* @param integer $user_id
* @param string $paginate
* @param integer $offset
* @param string $order
* @param string $direction
*/ */
private function getTaskPagination($user_id, $paginate, $offset, $order, $direction) private function getTaskPagination($user_id, $paginate, $offset, $order, $direction)
{ {
@ -94,6 +97,11 @@ class App extends Base
* Get subtasks pagination * Get subtasks pagination
* *
* @access public * @access public
* @param integer $user_id
* @param string $paginate
* @param integer $offset
* @param string $order
* @param string $direction
*/ */
private function getSubtaskPagination($user_id, $paginate, $offset, $order, $direction) private function getSubtaskPagination($user_id, $paginate, $offset, $order, $direction)
{ {
@ -132,10 +140,15 @@ class App extends Base
* Get projects pagination * Get projects pagination
* *
* @access public * @access public
* @param array $project_ids
* @param string $paginate
* @param integer $offset
* @param string $order
* @param string $direction
*/ */
private function getProjectPagination($project_ids, $paginate, $offset, $order, $direction) private function getProjectPagination(array $project_ids, $paginate, $offset, $order, $direction)
{ {
$limit = 5; $limit = 10;
if (! in_array($order, array('id', 'name'))) { if (! in_array($order, array('id', 'name'))) {
$order = 'name'; $order = 'name';
@ -178,8 +191,9 @@ class App extends Base
$this->response->html('<p>'.t('Nothing to preview...').'</p>'); $this->response->html('<p>'.t('Nothing to preview...').'</p>');
} }
else { else {
$this->response->html(Helper\markdown($payload['text'])); $this->response->html(
$this->template->markdown($payload['text'])
);
} }
} }
} }

View file

@ -3,13 +3,13 @@
namespace Controller; namespace Controller;
use Pimple\Container; use Pimple\Container;
use Core\Tool;
use Core\Security; use Core\Security;
use Core\Request; use Core\Request;
use Core\Response; use Core\Response;
use Core\Template; use Core\Template;
use Core\Session; use Core\Session;
use Model\LastLogin; use Model\LastLogin;
use Symfony\Component\EventDispatcher\Event;
/** /**
* Base controller * Base controller
@ -17,6 +17,8 @@ use Model\LastLogin;
* @package controller * @package controller
* @author Frederic Guillot * @author Frederic Guillot
* *
* @property \Core\Session $session
* @property \Core\Template $template
* @property \Model\Acl $acl * @property \Model\Acl $acl
* @property \Model\Authentication $authentication * @property \Model\Authentication $authentication
* @property \Model\Action $action * @property \Model\Action $action
@ -49,6 +51,7 @@ use Model\LastLogin;
* @property \Model\SubtaskHistory $subtaskHistory * @property \Model\SubtaskHistory $subtaskHistory
* @property \Model\TimeTracking $timeTracking * @property \Model\TimeTracking $timeTracking
* @property \Model\User $user * @property \Model\User $user
* @property \Model\UserSession $userSession
* @property \Model\Webhook $webhook * @property \Model\Webhook $webhook
*/ */
abstract class Base abstract class Base
@ -69,22 +72,6 @@ abstract class Base
*/ */
protected $response; protected $response;
/**
* Template instance
*
* @accesss protected
* @var \Core\Template
*/
protected $template;
/**
* Session instance
*
* @accesss public
* @var \Core\Session
*/
protected $session;
/** /**
* Container instance * Container instance
* *
@ -104,8 +91,6 @@ abstract class Base
$this->container = $container; $this->container = $container;
$this->request = new Request; $this->request = new Request;
$this->response = new Response; $this->response = new Response;
$this->session = new Session;
$this->template = new Template;
} }
/** /**
@ -115,9 +100,15 @@ abstract class Base
*/ */
public function __destruct() public function __destruct()
{ {
// foreach ($this->container['db']->getLogMessages() as $message) { if (DEBUG) {
// $this->container['logger']->addDebug($message);
// } foreach ($this->container['db']->getLogMessages() as $message) {
$this->container['logger']->debug($message);
}
$this->container['logger']->debug('SQL_QUERIES={nb}', array('nb' => $this->container['db']->nb_queries));
$this->container['logger']->debug('RENDERING={time}', array('time' => microtime(true) - $_SERVER['REQUEST_TIME_FLOAT']));
}
} }
/** /**
@ -129,19 +120,16 @@ abstract class Base
*/ */
public function __get($name) public function __get($name)
{ {
return Tool::loadModel($this->container, $name); return $this->container[$name];
} }
/** /**
* Method executed before each action * Send HTTP headers
* *
* @access public * @access private
*/ */
public function beforeAction($controller, $action) private function sendHeaders($action)
{ {
// Start the session
$this->session->open(BASE_URL_DIRECTORY);
// HTTP secure headers // HTTP secure headers
$this->response->csp(array('style-src' => "'self' 'unsafe-inline'")); $this->response->csp(array('style-src' => "'self' 'unsafe-inline'"));
$this->response->nosniff(); $this->response->nosniff();
@ -155,12 +143,33 @@ abstract class Base
if (ENABLE_HSTS) { if (ENABLE_HSTS) {
$this->response->hsts(); $this->response->hsts();
} }
}
$this->config->setupTranslations(); /**
$this->config->setupTimezone(); * Method executed before each action
*
* @access public
*/
public function beforeAction($controller, $action)
{
// Start the session
$this->session->open(BASE_URL_DIRECTORY);
$this->sendHeaders($action);
$this->container['dispatcher']->dispatch('session.bootstrap', new Event);
// Authentication if (! $this->acl->isPublicAction($controller, $action)) {
if (! $this->authentication->isAuthenticated($controller, $action)) { $this->handleAuthenticatedUser($controller, $action);
}
}
/**
* Check page access and authentication
*
* @access public
*/
public function handleAuthenticatedUser($controller, $action)
{
if (! $this->authentication->isAuthenticated()) {
if ($this->request->isAjax()) { if ($this->request->isAjax()) {
$this->response->text('Not Authorized', 401); $this->response->text('Not Authorized', 401);
@ -169,33 +178,8 @@ abstract class Base
$this->response->redirect('?controller=user&action=login&redirect_query='.urlencode($this->request->getQueryString())); $this->response->redirect('?controller=user&action=login&redirect_query='.urlencode($this->request->getQueryString()));
} }
// Check if the user is allowed to see this page if (! $this->acl->isAllowed($controller, $action, $this->request->getIntegerParam('project_id', 0))) {
if (! $this->acl->isPageAccessAllowed($controller, $action)) { $this->forbidden();
$this->response->redirect('?controller=user&action=forbidden');
}
// Attach events
$this->attachEvents();
}
/**
* Attach events
*
* @access private
*/
private function attachEvents()
{
$models = array(
'projectActivity', // Order is important
'projectDailySummary',
'action',
'project',
'webhook',
'notification',
);
foreach ($models as $model) {
$this->$model->attachEvents();
} }
} }
@ -239,19 +223,6 @@ abstract class Base
} }
} }
/**
* Check if the current user have access to the given project
*
* @access protected
* @param integer $project_id Project id
*/
protected function checkProjectPermissions($project_id)
{
if ($this->acl->isRegularUser() && ! $this->projectPermission->isUserAllowed($project_id, $this->acl->getUserId())) {
$this->forbidden();
}
}
/** /**
* Redirection when there is no project in the database * Redirection when there is no project in the database
* *
@ -273,14 +244,10 @@ abstract class Base
*/ */
protected function taskLayout($template, array $params) protected function taskLayout($template, array $params)
{ {
if (isset($params['task']) && $this->taskPermission->canRemoveTask($params['task']) === false) { $content = $this->template->render($template, $params);
$params['hide_remove_menu'] = true;
}
$content = $this->template->load($template, $params);
$params['task_content_for_layout'] = $content; $params['task_content_for_layout'] = $content;
$params['title'] = $params['task']['project_name'].' &gt; '.$params['task']['title']; $params['title'] = $params['task']['project_name'].' &gt; '.$params['task']['title'];
$params['board_selector'] = $this->projectPermission->getAllowedProjects($this->acl->getUserId()); $params['board_selector'] = $this->projectPermission->getAllowedProjects($this->userSession->getId());
return $this->template->layout('task/layout', $params); return $this->template->layout('task/layout', $params);
} }
@ -295,10 +262,10 @@ abstract class Base
*/ */
protected function projectLayout($template, array $params) protected function projectLayout($template, array $params)
{ {
$content = $this->template->load($template, $params); $content = $this->template->render($template, $params);
$params['project_content_for_layout'] = $content; $params['project_content_for_layout'] = $content;
$params['title'] = $params['project']['name'] === $params['title'] ? $params['title'] : $params['project']['name'].' &gt; '.$params['title']; $params['title'] = $params['project']['name'] === $params['title'] ? $params['title'] : $params['project']['name'].' &gt; '.$params['title'];
$params['board_selector'] = $this->projectPermission->getAllowedProjects($this->acl->getUserId()); $params['board_selector'] = $this->projectPermission->getAllowedProjects($this->userSession->getId());
return $this->template->layout('project/layout', $params); return $this->template->layout('project/layout', $params);
} }
@ -313,12 +280,10 @@ abstract class Base
{ {
$task = $this->taskFinder->getDetails($this->request->getIntegerParam('task_id')); $task = $this->taskFinder->getDetails($this->request->getIntegerParam('task_id'));
if (! $task) { if (! $task || $task['project_id'] != $this->request->getIntegerParam('project_id')) {
$this->notfound(); $this->notfound();
} }
$this->checkProjectPermissions($task['project_id']);
return $task; return $task;
} }
@ -339,29 +304,6 @@ abstract class Base
$this->response->redirect('?controller=project'); $this->response->redirect('?controller=project');
} }
$this->checkProjectPermissions($project['id']);
return $project;
}
/**
* Common method to get a project with administration rights
*
* @access protected
* @return array
*/
protected function getProjectManagement()
{
$project = $this->project->getById($this->request->getIntegerParam('project_id'));
if (! $project) {
$this->notfound();
}
if ($this->acl->isRegularUser() && ! $this->projectPermission->adminAllowed($project['id'], $this->acl->getUserId())) {
$this->forbidden();
}
return $project; return $project;
} }
} }

View file

@ -2,10 +2,6 @@
namespace Controller; namespace Controller;
use Model\Project as ProjectModel;
use Model\User as UserModel;
use Core\Security;
/** /**
* Board controller * Board controller
* *
@ -22,7 +18,7 @@ class Board extends Base
public function moveColumn() public function moveColumn()
{ {
$this->checkCSRFParam(); $this->checkCSRFParam();
$project = $this->getProjectManagement(); $project = $this->getProject();
$column_id = $this->request->getIntegerParam('column_id'); $column_id = $this->request->getIntegerParam('column_id');
$direction = $this->request->getStringParam('direction'); $direction = $this->request->getStringParam('direction');
@ -43,7 +39,7 @@ class Board extends Base
$task = $this->getTask(); $task = $this->getTask();
$project = $this->project->getById($task['project_id']); $project = $this->project->getById($task['project_id']);
$this->response->html($this->template->load('board/assignee', array( $this->response->html($this->template->render('board/assignee', array(
'values' => $task, 'values' => $task,
'users_list' => $this->projectPermission->getMemberList($project['id']), 'users_list' => $this->projectPermission->getMemberList($project['id']),
'project' => $project, 'project' => $project,
@ -58,7 +54,6 @@ class Board extends Base
public function updateAssignee() public function updateAssignee()
{ {
$values = $this->request->getValues(); $values = $this->request->getValues();
$this->checkProjectPermissions($values['project_id']);
list($valid,) = $this->taskValidator->validateAssigneeModification($values); list($valid,) = $this->taskValidator->validateAssigneeModification($values);
@ -82,7 +77,7 @@ class Board extends Base
$task = $this->getTask(); $task = $this->getTask();
$project = $this->project->getById($task['project_id']); $project = $this->project->getById($task['project_id']);
$this->response->html($this->template->load('board/category', array( $this->response->html($this->template->render('board/category', array(
'values' => $task, 'values' => $task,
'categories_list' => $this->category->getList($project['id']), 'categories_list' => $this->category->getList($project['id']),
'project' => $project, 'project' => $project,
@ -97,7 +92,6 @@ class Board extends Base
public function updateCategory() public function updateCategory()
{ {
$values = $this->request->getValues(); $values = $this->request->getValues();
$this->checkProjectPermissions($values['project_id']);
list($valid,) = $this->taskValidator->validateCategoryModification($values); list($valid,) = $this->taskValidator->validateCategoryModification($values);
@ -130,12 +124,14 @@ class Board extends Base
// Display the board with a specific layout // Display the board with a specific layout
$this->response->html($this->template->layout('board/public', array( $this->response->html($this->template->layout('board/public', array(
'project' => $project, 'project' => $project,
'columns' => $this->board->get($project['id']), 'swimlanes' => $this->board->getBoard($project['id']),
'categories' => $this->category->getList($project['id'], false), 'categories' => $this->category->getList($project['id'], false),
'title' => $project['name'], 'title' => $project['name'],
'no_layout' => true, 'no_layout' => true,
'not_editable' => true, 'not_editable' => true,
'board_public_refresh_interval' => $this->config->get('board_public_refresh_interval'), 'board_public_refresh_interval' => $this->config->get('board_public_refresh_interval'),
'board_private_refresh_interval' => $this->config->get('board_private_refresh_interval'),
'board_highlight_period' => $this->config->get('board_highlight_period'),
))); )));
} }
@ -146,16 +142,16 @@ class Board extends Base
*/ */
public function index() public function index()
{ {
$last_seen_project_id = $this->user->getLastSeenProjectId(); $last_seen_project_id = $this->userSession->getLastSeenProjectId();
$favorite_project_id = $this->user->getFavoriteProjectId(); $favorite_project_id = $this->userSession->getFavoriteProjectId();
$project_id = $last_seen_project_id ?: $favorite_project_id; $project_id = $last_seen_project_id ?: $favorite_project_id;
if (! $project_id) { if (! $project_id) {
$projects = $this->projectPermission->getAllowedProjects($this->acl->getUserId()); $projects = $this->projectPermission->getAllowedProjects($this->userSession->getId());
if (empty($projects)) { if (empty($projects)) {
if ($this->acl->isAdminUser()) { if ($this->userSession->isAdmin()) {
$this->redirectNoProject(); $this->redirectNoProject();
} }
@ -177,18 +173,18 @@ class Board extends Base
public function show($project_id = 0) public function show($project_id = 0)
{ {
$project = $this->getProject($project_id); $project = $this->getProject($project_id);
$projects = $this->projectPermission->getAllowedProjects($this->acl->getUserId()); $projects = $this->projectPermission->getAllowedProjects($this->userSession->getId());
$board_selector = $projects; $board_selector = $projects;
unset($board_selector[$project['id']]); unset($board_selector[$project['id']]);
$this->user->storeLastSeenProjectId($project['id']); $this->userSession->storeLastSeenProjectId($project['id']);
$this->response->html($this->template->layout('board/index', array( $this->response->html($this->template->layout('board/index', array(
'users' => $this->projectPermission->getMemberList($project['id'], true, true), 'users' => $this->projectPermission->getMemberList($project['id'], true, true),
'projects' => $projects, 'projects' => $projects,
'project' => $project, 'project' => $project,
'board' => $this->board->get($project['id']), 'swimlanes' => $this->board->getBoard($project['id']),
'categories' => $this->category->getList($project['id'], true, true), 'categories' => $this->category->getList($project['id'], true, true),
'title' => $project['name'], 'title' => $project['name'],
'board_selector' => $board_selector, 'board_selector' => $board_selector,
@ -202,11 +198,10 @@ class Board extends Base
* *
* @access public * @access public
*/ */
public function edit() public function edit(array $values = array(), array $errors = array())
{ {
$project = $this->getProjectManagement(); $project = $this->getProject();
$columns = $this->board->getColumns($project['id']); $columns = $this->board->getColumns($project['id']);
$values = array();
foreach ($columns as $column) { foreach ($columns as $column) {
$values['title['.$column['id'].']'] = $column['title']; $values['title['.$column['id'].']'] = $column['title'];
@ -214,7 +209,7 @@ class Board extends Base
} }
$this->response->html($this->projectLayout('board/edit', array( $this->response->html($this->projectLayout('board/edit', array(
'errors' => array(), 'errors' => $errors,
'values' => $values + array('project_id' => $project['id']), 'values' => $values + array('project_id' => $project['id']),
'columns' => $columns, 'columns' => $columns,
'project' => $project, 'project' => $project,
@ -229,7 +224,7 @@ class Board extends Base
*/ */
public function update() public function update()
{ {
$project = $this->getProjectManagement(); $project = $this->getProject();
$columns = $this->board->getColumns($project['id']); $columns = $this->board->getColumns($project['id']);
$data = $this->request->getValues(); $data = $this->request->getValues();
$values = $columns_list = array(); $values = $columns_list = array();
@ -253,13 +248,7 @@ class Board extends Base
} }
} }
$this->response->html($this->projectLayout('board/edit', array( $this->edit($values, $errors);
'errors' => $errors,
'values' => $values + array('project_id' => $project['id']),
'columns' => $columns,
'project' => $project,
'title' => t('Edit board')
)));
} }
/** /**
@ -269,7 +258,7 @@ class Board extends Base
*/ */
public function add() public function add()
{ {
$project = $this->getProjectManagement(); $project = $this->getProject();
$columns = $this->board->getColumnsList($project['id']); $columns = $this->board->getColumnsList($project['id']);
$data = $this->request->getValues(); $data = $this->request->getValues();
$values = array(); $values = array();
@ -291,13 +280,7 @@ class Board extends Base
} }
} }
$this->response->html($this->projectLayout('board/edit', array( $this->edit($values, $errors);
'errors' => $errors,
'values' => $values + $data,
'columns' => $columns,
'project' => $project,
'title' => t('Edit board')
)));
} }
/** /**
@ -307,7 +290,7 @@ class Board extends Base
*/ */
public function remove() public function remove()
{ {
$project = $this->getProjectManagement(); $project = $this->getProject();
if ($this->request->getStringParam('remove') === 'yes') { if ($this->request->getStringParam('remove') === 'yes') {
@ -339,35 +322,38 @@ class Board extends Base
{ {
$project_id = $this->request->getIntegerParam('project_id'); $project_id = $this->request->getIntegerParam('project_id');
if ($project_id > 0 && $this->request->isAjax()) { if (! $project_id || ! $this->request->isAjax()) {
return $this->response->status(403);
if (! $this->projectPermission->isUserAllowed($project_id, $this->acl->getUserId())) {
$this->response->text('Forbidden', 403);
}
$values = $this->request->getJson();
if ($this->taskPosition->movePosition($project_id, $values['task_id'], $values['column_id'], $values['position'])) {
$this->response->html(
$this->template->load('board/show', array(
'project' => $this->project->getById($project_id),
'board' => $this->board->get($project_id),
'categories' => $this->category->getList($project_id, false),
'board_private_refresh_interval' => $this->config->get('board_private_refresh_interval'),
'board_highlight_period' => $this->config->get('board_highlight_period'),
)),
201
);
}
else {
$this->response->status(400);
}
} }
else {
$this->response->status(403); if (! $this->projectPermission->isUserAllowed($project_id, $this->userSession->getId())) {
$this->response->text('Forbidden', 403);
} }
$values = $this->request->getJson();
$result =$this->taskPosition->movePosition(
$project_id,
$values['task_id'],
$values['column_id'],
$values['position'],
$values['swimlane_id']
);
if (! $result) {
return $this->response->status(400);
}
$this->response->html(
$this->template->render('board/show', array(
'project' => $this->project->getById($project_id),
'swimlanes' => $this->board->getBoard($project_id),
'categories' => $this->category->getList($project_id, false),
'board_private_refresh_interval' => $this->config->get('board_private_refresh_interval'),
'board_highlight_period' => $this->config->get('board_highlight_period'),
)),
201
);
} }
/** /**
@ -377,33 +363,30 @@ class Board extends Base
*/ */
public function check() public function check()
{ {
if ($this->request->isAjax()) { if (! $this->request->isAjax()) {
return $this->response->status(403);
$project_id = $this->request->getIntegerParam('project_id');
$timestamp = $this->request->getIntegerParam('timestamp');
if ($project_id > 0 && ! $this->projectPermission->isUserAllowed($project_id, $this->acl->getUserId())) {
$this->response->text('Forbidden', 403);
}
if ($this->project->isModifiedSince($project_id, $timestamp)) {
$this->response->html(
$this->template->load('board/show', array(
'project' => $this->project->getById($project_id),
'board' => $this->board->get($project_id),
'categories' => $this->category->getList($project_id, false),
'board_private_refresh_interval' => $this->config->get('board_private_refresh_interval'),
'board_highlight_period' => $this->config->get('board_highlight_period'),
))
);
}
else {
$this->response->status(304);
}
} }
else {
$this->response->status(403); $project_id = $this->request->getIntegerParam('project_id');
$timestamp = $this->request->getIntegerParam('timestamp');
if (! $this->projectPermission->isUserAllowed($project_id, $this->userSession->getId())) {
$this->response->text('Forbidden', 403);
} }
if (! $this->project->isModifiedSince($project_id, $timestamp)) {
return $this->response->status(304);
}
$this->response->html(
$this->template->render('board/show', array(
'project' => $this->project->getById($project_id),
'swimlanes' => $this->board->getBoard($project_id),
'categories' => $this->category->getList($project_id, false),
'board_private_refresh_interval' => $this->config->get('board_private_refresh_interval'),
'board_highlight_period' => $this->config->get('board_highlight_period'),
))
);
} }
/** /**
@ -414,8 +397,9 @@ class Board extends Base
public function subtasks() public function subtasks()
{ {
$task = $this->getTask(); $task = $this->getTask();
$this->response->html($this->template->load('board/subtasks', array( $this->response->html($this->template->render('board/subtasks', array(
'subtasks' => $this->subTask->getAll($task['id']) 'subtasks' => $this->subTask->getAll($task['id']),
'task' => $task,
))); )));
} }
@ -429,8 +413,9 @@ class Board extends Base
$task = $this->getTask(); $task = $this->getTask();
$this->subTask->toggleStatus($this->request->getIntegerParam('subtask_id')); $this->subTask->toggleStatus($this->request->getIntegerParam('subtask_id'));
$this->response->html($this->template->load('board/subtasks', array( $this->response->html($this->template->render('board/subtasks', array(
'subtasks' => $this->subTask->getAll($task['id']) 'subtasks' => $this->subTask->getAll($task['id']),
'task' => $task,
))); )));
} }
@ -443,8 +428,9 @@ class Board extends Base
{ {
$task = $this->getTask(); $task = $this->getTask();
$this->response->html($this->template->load('board/files', array( $this->response->html($this->template->render('board/files', array(
'files' => $this->file->getAll($task['id']) 'files' => $this->file->getAll($task['id']),
'task' => $task,
))); )));
} }
@ -457,7 +443,7 @@ class Board extends Base
{ {
$task = $this->getTask(); $task = $this->getTask();
$this->response->html($this->template->load('board/comments', array( $this->response->html($this->template->render('board/comments', array(
'comments' => $this->comment->getAll($task['id']) 'comments' => $this->comment->getAll($task['id'])
))); )));
} }
@ -471,7 +457,7 @@ class Board extends Base
{ {
$task = $this->getTask(); $task = $this->getTask();
$this->response->html($this->template->load('board/description', array( $this->response->html($this->template->render('board/description', array(
'task' => $task 'task' => $task
))); )));
} }

View file

@ -14,7 +14,7 @@ class Category extends Base
* Get the category (common method between actions) * Get the category (common method between actions)
* *
* @access private * @access private
* @param $project_id * @param integer $project_id
* @return array * @return array
*/ */
private function getCategory($project_id) private function getCategory($project_id)
@ -36,7 +36,7 @@ class Category extends Base
*/ */
public function index(array $values = array(), array $errors = array()) public function index(array $values = array(), array $errors = array())
{ {
$project = $this->getProjectManagement(); $project = $this->getProject();
$this->response->html($this->projectLayout('category/index', array( $this->response->html($this->projectLayout('category/index', array(
'categories' => $this->category->getList($project['id'], false), 'categories' => $this->category->getList($project['id'], false),
@ -48,13 +48,13 @@ class Category extends Base
} }
/** /**
* Validate and save a new project * Validate and save a new category
* *
* @access public * @access public
*/ */
public function save() public function save()
{ {
$project = $this->getProjectManagement(); $project = $this->getProject();
$values = $this->request->getValues(); $values = $this->request->getValues();
list($valid, $errors) = $this->category->validateCreation($values); list($valid, $errors) = $this->category->validateCreation($values);
@ -80,7 +80,7 @@ class Category extends Base
*/ */
public function edit(array $values = array(), array $errors = array()) public function edit(array $values = array(), array $errors = array())
{ {
$project = $this->getProjectManagement(); $project = $this->getProject();
$category = $this->getCategory($project['id']); $category = $this->getCategory($project['id']);
$this->response->html($this->projectLayout('category/edit', array( $this->response->html($this->projectLayout('category/edit', array(
@ -98,7 +98,7 @@ class Category extends Base
*/ */
public function update() public function update()
{ {
$project = $this->getProjectManagement(); $project = $this->getProject();
$values = $this->request->getValues(); $values = $this->request->getValues();
list($valid, $errors) = $this->category->validateModification($values); list($valid, $errors) = $this->category->validateModification($values);
@ -124,7 +124,7 @@ class Category extends Base
*/ */
public function confirm() public function confirm()
{ {
$project = $this->getProjectManagement(); $project = $this->getProject();
$category = $this->getCategory($project['id']); $category = $this->getCategory($project['id']);
$this->response->html($this->projectLayout('category/remove', array( $this->response->html($this->projectLayout('category/remove', array(
@ -142,7 +142,7 @@ class Category extends Base
public function remove() public function remove()
{ {
$this->checkCSRFParam(); $this->checkCSRFParam();
$project = $this->getProjectManagement(); $project = $this->getProject();
$category = $this->getCategory($project['id']); $category = $this->getCategory($project['id']);
if ($this->category->remove($category['id'])) { if ($this->category->remove($category['id'])) {

View file

@ -24,7 +24,7 @@ class Comment extends Base
$this->notfound(); $this->notfound();
} }
if (! $this->acl->isAdminUser() && $comment['user_id'] != $this->acl->getUserId()) { if (! $this->userSession->isAdmin() && $comment['user_id'] != $this->userSession->getId()) {
$this->response->html($this->template->layout('comment/forbidden', array( $this->response->html($this->template->layout('comment/forbidden', array(
'title' => t('Access Forbidden') 'title' => t('Access Forbidden')
))); )));
@ -44,7 +44,7 @@ class Comment extends Base
if (empty($values)) { if (empty($values)) {
$values = array( $values = array(
'user_id' => $this->acl->getUserId(), 'user_id' => $this->userSession->getId(),
'task_id' => $task['id'], 'task_id' => $task['id'],
); );
} }
@ -78,7 +78,7 @@ class Comment extends Base
$this->session->flashError(t('Unable to create your comment.')); $this->session->flashError(t('Unable to create your comment.'));
} }
$this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'#comments'); $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id'].'#comments');
} }
$this->create($values, $errors); $this->create($values, $errors);
@ -125,7 +125,7 @@ class Comment extends Base
$this->session->flashError(t('Unable to update your comment.')); $this->session->flashError(t('Unable to update your comment.'));
} }
$this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'#comment-'.$comment['id']); $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id'].'#comment-'.$comment['id']);
} }
$this->edit($values, $errors); $this->edit($values, $errors);
@ -166,6 +166,6 @@ class Comment extends Base
$this->session->flashError(t('Unable to remove this comment.')); $this->session->flashError(t('Unable to remove this comment.'));
} }
$this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'#comments'); $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id'].'#comments');
} }
} }

View file

@ -20,10 +20,10 @@ class Config extends Base
*/ */
private function layout($template, array $params) private function layout($template, array $params)
{ {
$params['board_selector'] = $this->projectPermission->getAllowedProjects($this->acl->getUserId()); $params['board_selector'] = $this->projectPermission->getAllowedProjects($this->userSession->getId());
$params['values'] = $this->config->getAll(); $params['values'] = $this->config->getAll();
$params['errors'] = array(); $params['errors'] = array();
$params['config_content_for_layout'] = $this->template->load($template, $params); $params['config_content_for_layout'] = $this->template->render($template, $params);
return $this->template->layout('config/layout', $params); return $this->template->layout('config/layout', $params);
} }

View file

@ -0,0 +1,75 @@
<?php
namespace Controller;
/**
* Export controller
*
* @package controller
* @author Frederic Guillot
*/
class Export extends Base
{
/**
* Common export method
*
* @access private
*/
private function common($model, $method, $filename, $action, $page_title)
{
$project = $this->getProject();
$from = $this->request->getStringParam('from');
$to = $this->request->getStringParam('to');
if ($from && $to) {
$data = $this->$model->$method($project['id'], $from, $to);
$this->response->forceDownload($filename.'.csv');
$this->response->csv($data);
}
$this->response->html($this->projectLayout('export/'.$action, array(
'values' => array(
'controller' => 'export',
'action' => $action,
'project_id' => $project['id'],
'from' => $from,
'to' => $to,
),
'errors' => array(),
'date_format' => $this->config->get('application_date_format'),
'date_formats' => $this->dateParser->getAvailableFormats(),
'project' => $project,
'title' => $page_title,
)));
}
/**
* Task export
*
* @access public
*/
public function tasks()
{
$this->common('taskExport', 'export', t('Tasks'), 'tasks', t('Tasks Export'));
}
/**
* Subtask export
*
* @access public
*/
public function subtasks()
{
$this->common('subtaskExport', 'export', t('Subtasks'), 'subtasks', t('Subtasks Export'));
}
/**
* Daily project summary export
*
* @access public
*/
public function summary()
{
$this->common('projectDailySummary', 'getAggregatedMetrics', t('Summary'), 'summary', t('Daily project summary export'));
}
}

View file

@ -37,11 +37,11 @@ class File extends Base
$task = $this->getTask(); $task = $this->getTask();
if ($this->file->upload($task['project_id'], $task['id'], 'files') === true) { if ($this->file->upload($task['project_id'], $task['id'], 'files') === true) {
$this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'#attachments'); $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id'].'#attachments');
} }
else { else {
$this->session->flashError(t('Unable to upload the file.')); $this->session->flashError(t('Unable to upload the file.'));
$this->response->redirect('?controller=file&action=create&task_id='.$task['id']); $this->response->redirect('?controller=file&action=create&task_id='.$task['id'].'&project_id='.$task['project_id']);
} }
} }
@ -61,7 +61,7 @@ class File extends Base
$this->response->binary(file_get_contents($filename)); $this->response->binary(file_get_contents($filename));
} }
$this->response->redirect('?controller=task&action=show&task_id='.$task['id']); $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id']);
} }
/** /**
@ -75,8 +75,9 @@ class File extends Base
$file = $this->file->getById($this->request->getIntegerParam('file_id')); $file = $this->file->getById($this->request->getIntegerParam('file_id'));
if ($file['task_id'] == $task['id']) { if ($file['task_id'] == $task['id']) {
$this->response->html($this->template->load('file/open', array( $this->response->html($this->template->render('file/open', array(
'file' => $file 'file' => $file,
'task' => $task,
))); )));
} }
} }
@ -119,7 +120,7 @@ class File extends Base
$this->session->flashError(t('Unable to remove this file.')); $this->session->flashError(t('Unable to remove this file.'));
} }
$this->response->redirect('?controller=task&action=show&task_id='.$task['id']); $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id']);
} }
/** /**

View file

@ -2,8 +2,6 @@
namespace Controller; namespace Controller;
use Model\Task as TaskModel;
/** /**
* Project controller * Project controller
* *
@ -19,7 +17,7 @@ class Project extends Base
*/ */
public function index() public function index()
{ {
$projects = $this->project->getAll($this->acl->isRegularUser()); $projects = $this->project->getAll(! $this->userSession->isAdmin());
$nb_projects = count($projects); $nb_projects = count($projects);
$active_projects = array(); $active_projects = array();
$inactive_projects = array(); $inactive_projects = array();
@ -34,7 +32,7 @@ class Project extends Base
} }
$this->response->html($this->template->layout('project/index', array( $this->response->html($this->template->layout('project/index', array(
'board_selector' => $this->projectPermission->getAllowedProjects($this->acl->getUserId()), 'board_selector' => $this->projectPermission->getAllowedProjects($this->userSession->getId()),
'active_projects' => $active_projects, 'active_projects' => $active_projects,
'inactive_projects' => $inactive_projects, 'inactive_projects' => $inactive_projects,
'nb_projects' => $nb_projects, 'nb_projects' => $nb_projects,
@ -54,77 +52,10 @@ class Project extends Base
$this->response->html($this->projectLayout('project/show', array( $this->response->html($this->projectLayout('project/show', array(
'project' => $project, 'project' => $project,
'stats' => $this->project->getStats($project['id']), 'stats' => $this->project->getStats($project['id']),
'webhook_token' => $this->config->get('webhook_token'),
'title' => $project['name'], 'title' => $project['name'],
))); )));
} }
/**
* Task export
*
* @access public
*/
public function exportTasks()
{
$project = $this->getProjectManagement();
$from = $this->request->getStringParam('from');
$to = $this->request->getStringParam('to');
if ($from && $to) {
$data = $this->taskExport->export($project['id'], $from, $to);
$this->response->forceDownload('Tasks_'.date('Y_m_d_H_i').'.csv');
$this->response->csv($data);
}
$this->response->html($this->projectLayout('project/export_tasks', array(
'values' => array(
'controller' => 'project',
'action' => 'exportTasks',
'project_id' => $project['id'],
'from' => $from,
'to' => $to,
),
'errors' => array(),
'date_format' => $this->config->get('application_date_format'),
'date_formats' => $this->dateParser->getAvailableFormats(),
'project' => $project,
'title' => t('Tasks Export')
)));
}
/**
* Daily project summary export
*
* @access public
*/
public function exportDailyProjectSummary()
{
$project = $this->getProjectManagement();
$from = $this->request->getStringParam('from');
$to = $this->request->getStringParam('to');
if ($from && $to) {
$data = $this->projectDailySummary->getAggregatedMetrics($project['id'], $from, $to);
$this->response->forceDownload('Daily_Summary_'.date('Y_m_d_H_i').'.csv');
$this->response->csv($data);
}
$this->response->html($this->projectLayout('project/export_daily_summary', array(
'values' => array(
'controller' => 'project',
'action' => 'exportDailyProjectSummary',
'project_id' => $project['id'],
'from' => $from,
'to' => $to,
),
'errors' => array(),
'date_format' => $this->config->get('application_date_format'),
'date_formats' => $this->dateParser->getAvailableFormats(),
'project' => $project,
'title' => t('Daily project summary export')
)));
}
/** /**
* Public access management * Public access management
* *
@ -132,7 +63,7 @@ class Project extends Base
*/ */
public function share() public function share()
{ {
$project = $this->getProjectManagement(); $project = $this->getProject();
$switch = $this->request->getStringParam('switch'); $switch = $this->request->getStringParam('switch');
if ($switch === 'enable' || $switch === 'disable') { if ($switch === 'enable' || $switch === 'disable') {
@ -154,6 +85,22 @@ class Project extends Base
))); )));
} }
/**
* Integrations page
*
* @access public
*/
public function integration()
{
$project = $this->getProject();
$this->response->html($this->projectLayout('project/integrations', array(
'project' => $project,
'title' => t('Integrations'),
'webhook_token' => $this->config->get('webhook_token'),
)));
}
/** /**
* Display a form to edit a project * Display a form to edit a project
* *
@ -161,7 +108,7 @@ class Project extends Base
*/ */
public function edit(array $values = array(), array $errors = array()) public function edit(array $values = array(), array $errors = array())
{ {
$project = $this->getProjectManagement(); $project = $this->getProject();
$this->response->html($this->projectLayout('project/edit', array( $this->response->html($this->projectLayout('project/edit', array(
'values' => empty($values) ? $project : $values, 'values' => empty($values) ? $project : $values,
@ -178,7 +125,7 @@ class Project extends Base
*/ */
public function update() public function update()
{ {
$project = $this->getProjectManagement(); $project = $this->getProject();
$values = $this->request->getValues(); $values = $this->request->getValues();
list($valid, $errors) = $this->project->validateModification($values); list($valid, $errors) = $this->project->validateModification($values);
@ -203,7 +150,7 @@ class Project extends Base
*/ */
public function users() public function users()
{ {
$project = $this->getProjectManagement(); $project = $this->getProject();
$this->response->html($this->projectLayout('project/users', array( $this->response->html($this->projectLayout('project/users', array(
'project' => $project, 'project' => $project,
@ -219,7 +166,7 @@ class Project extends Base
*/ */
public function allowEverybody() public function allowEverybody()
{ {
$project = $this->getProjectManagement(); $project = $this->getProject();
$values = $this->request->getValues() + array('is_everybody_allowed' => 0); $values = $this->request->getValues() + array('is_everybody_allowed' => 0);
list($valid,) = $this->projectPermission->validateProjectModification($values); list($valid,) = $this->projectPermission->validateProjectModification($values);
@ -248,7 +195,37 @@ class Project extends Base
if ($valid) { if ($valid) {
if ($this->projectPermission->allowUser($values['project_id'], $values['user_id'])) { if ($this->projectPermission->addMember($values['project_id'], $values['user_id'])) {
$this->session->flash(t('Project updated successfully.'));
}
else {
$this->session->flashError(t('Unable to update this project.'));
}
}
$this->response->redirect('?controller=project&action=users&project_id='.$values['project_id']);
}
/**
* Change the role of a project member
*
* @access public
*/
public function role()
{
$this->checkCSRFParam();
$values = array(
'project_id' => $this->request->getIntegerParam('project_id'),
'user_id' => $this->request->getIntegerParam('user_id'),
'is_owner' => $this->request->getIntegerParam('is_owner'),
);
list($valid,) = $this->projectPermission->validateUserModification($values);
if ($valid) {
if ($this->projectPermission->changeRole($values['project_id'], $values['user_id'], $values['is_owner'])) {
$this->session->flash(t('Project updated successfully.')); $this->session->flash(t('Project updated successfully.'));
} }
else { else {
@ -277,7 +254,7 @@ class Project extends Base
if ($valid) { if ($valid) {
if ($this->projectPermission->revokeUser($values['project_id'], $values['user_id'])) { if ($this->projectPermission->revokeMember($values['project_id'], $values['user_id'])) {
$this->session->flash(t('Project updated successfully.')); $this->session->flash(t('Project updated successfully.'));
} }
else { else {
@ -295,7 +272,7 @@ class Project extends Base
*/ */
public function remove() public function remove()
{ {
$project = $this->getProjectManagement(); $project = $this->getProject();
if ($this->request->getStringParam('remove') === 'yes') { if ($this->request->getStringParam('remove') === 'yes') {
@ -324,7 +301,7 @@ class Project extends Base
*/ */
public function duplicate() public function duplicate()
{ {
$project = $this->getProjectManagement(); $project = $this->getProject();
if ($this->request->getStringParam('duplicate') === 'yes') { if ($this->request->getStringParam('duplicate') === 'yes') {
@ -352,7 +329,7 @@ class Project extends Base
*/ */
public function disable() public function disable()
{ {
$project = $this->getProjectManagement(); $project = $this->getProject();
if ($this->request->getStringParam('disable') === 'yes') { if ($this->request->getStringParam('disable') === 'yes') {
@ -380,7 +357,7 @@ class Project extends Base
*/ */
public function enable() public function enable()
{ {
$project = $this->getProjectManagement(); $project = $this->getProject();
if ($this->request->getStringParam('enable') === 'yes') { if ($this->request->getStringParam('enable') === 'yes') {
@ -416,7 +393,7 @@ class Project extends Base
$this->forbidden(true); $this->forbidden(true);
} }
$this->response->xml($this->template->load('project/feed', array( $this->response->xml($this->template->render('project/feed', array(
'events' => $this->projectActivity->getProject($project['id']), 'events' => $this->projectActivity->getProject($project['id']),
'project' => $project, 'project' => $project,
))); )));
@ -432,7 +409,7 @@ class Project extends Base
$project = $this->getProject(); $project = $this->getProject();
$this->response->html($this->template->layout('project/activity', array( $this->response->html($this->template->layout('project/activity', array(
'board_selector' => $this->projectPermission->getAllowedProjects($this->acl->getUserId()), 'board_selector' => $this->projectPermission->getAllowedProjects($this->userSession->getId()),
'events' => $this->projectActivity->getProject($project['id']), 'events' => $this->projectActivity->getProject($project['id']),
'project' => $project, 'project' => $project,
'title' => t('%s\'s activity', $project['name']) 'title' => t('%s\'s activity', $project['name'])
@ -461,7 +438,7 @@ class Project extends Base
} }
$this->response->html($this->template->layout('project/search', array( $this->response->html($this->template->layout('project/search', array(
'board_selector' => $this->projectPermission->getAllowedProjects($this->acl->getUserId()), 'board_selector' => $this->projectPermission->getAllowedProjects($this->userSession->getId()),
'tasks' => $tasks, 'tasks' => $tasks,
'nb_tasks' => $nb_tasks, 'nb_tasks' => $nb_tasks,
'pagination' => array( 'pagination' => array(
@ -504,7 +481,7 @@ class Project extends Base
$nb_tasks = $this->taskPaginator->countClosedTasks($project['id']); $nb_tasks = $this->taskPaginator->countClosedTasks($project['id']);
$this->response->html($this->template->layout('project/tasks', array( $this->response->html($this->template->layout('project/tasks', array(
'board_selector' => $this->projectPermission->getAllowedProjects($this->acl->getUserId()), 'board_selector' => $this->projectPermission->getAllowedProjects($this->userSession->getId()),
'pagination' => array( 'pagination' => array(
'controller' => 'project', 'controller' => 'project',
'action' => 'tasks', 'action' => 'tasks',
@ -531,10 +508,10 @@ class Project extends Base
*/ */
public function create(array $values = array(), array $errors = array()) public function create(array $values = array(), array $errors = array())
{ {
$is_private = $this->request->getIntegerParam('private', $this->acl->isRegularUser()); $is_private = $this->request->getIntegerParam('private', $this->userSession->isAdmin() ? 0 : 1);
$this->response->html($this->template->layout('project/new', array( $this->response->html($this->template->layout('project/new', array(
'board_selector' => $this->projectPermission->getAllowedProjects($this->acl->getUserId()), 'board_selector' => $this->projectPermission->getAllowedProjects($this->userSession->getId()),
'values' => empty($values) ? array('is_private' => $is_private) : $values, 'values' => empty($values) ? array('is_private' => $is_private) : $values,
'errors' => $errors, 'errors' => $errors,
'title' => $is_private ? t('New private project') : t('New project'), 'title' => $is_private ? t('New private project') : t('New project'),
@ -553,7 +530,7 @@ class Project extends Base
if ($valid) { if ($valid) {
$project_id = $this->project->create($values, $this->acl->getUserId(), true); $project_id = $this->project->create($values, $this->userSession->getId(), true);
if ($project_id) { if ($project_id) {
$this->session->flash(t('Your project have been created successfully.')); $this->session->flash(t('Your project have been created successfully.'));

View file

@ -73,10 +73,10 @@ class Subtask extends Base
} }
if (isset($values['another_subtask']) && $values['another_subtask'] == 1) { if (isset($values['another_subtask']) && $values['another_subtask'] == 1) {
$this->response->redirect('?controller=subtask&action=create&task_id='.$task['id'].'&another_subtask=1'); $this->response->redirect('?controller=subtask&action=create&task_id='.$task['id'].'&another_subtask=1&project_id='.$task['project_id']);
} }
$this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'#subtasks'); $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id'].'#subtasks');
} }
$this->create($values, $errors); $this->create($values, $errors);
@ -110,7 +110,7 @@ class Subtask extends Base
public function update() public function update()
{ {
$task = $this->getTask(); $task = $this->getTask();
$subtask = $this->getSubtask(); $this->getSubtask();
$values = $this->request->getValues(); $values = $this->request->getValues();
list($valid, $errors) = $this->subTask->validateModification($values); list($valid, $errors) = $this->subTask->validateModification($values);
@ -124,7 +124,7 @@ class Subtask extends Base
$this->session->flashError(t('Unable to update your sub-task.')); $this->session->flashError(t('Unable to update your sub-task.'));
} }
$this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'#subtasks'); $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id'].'#subtasks');
} }
$this->edit($values, $errors); $this->edit($values, $errors);
@ -164,7 +164,7 @@ class Subtask extends Base
$this->session->flashError(t('Unable to remove this sub-task.')); $this->session->flashError(t('Unable to remove this sub-task.'));
} }
$this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'#subtasks'); $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id'].'#subtasks');
} }
/** /**
@ -181,6 +181,6 @@ class Subtask extends Base
$this->session->flashError(t('Unable to update your sub-task.')); $this->session->flashError(t('Unable to update your sub-task.'));
} }
$this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'#subtasks'); $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id'].'#subtasks');
} }
} }

View file

@ -0,0 +1,256 @@
<?php
namespace Controller;
use Model\Swimlane as SwimlaneModel;
/**
* Swimlanes
*
* @package controller
* @author Frederic Guillot
*/
class Swimlane extends Base
{
/**
* Get the swimlane (common method between actions)
*
* @access private
* @param integer $project_id
* @return array
*/
private function getSwimlane($project_id)
{
$swimlane = $this->swimlane->getById($this->request->getIntegerParam('swimlane_id'));
if (! $swimlane) {
$this->session->flashError(t('Swimlane not found.'));
$this->response->redirect('?controller=swimlane&action=index&project_id='.$project_id);
}
return $swimlane;
}
/**
* List of swimlanes for a given project
*
* @access public
*/
public function index(array $values = array(), array $errors = array())
{
$project = $this->getProject();
$this->response->html($this->projectLayout('swimlane/index', array(
'default_swimlane' => $this->swimlane->getDefault($project['id']),
'active_swimlanes' => $this->swimlane->getAllByStatus($project['id'], SwimlaneModel::ACTIVE),
'inactive_swimlanes' => $this->swimlane->getAllByStatus($project['id'], SwimlaneModel::INACTIVE),
'values' => $values + array('project_id' => $project['id']),
'errors' => $errors,
'project' => $project,
'title' => t('Swimlanes')
)));
}
/**
* Validate and save a new swimlane
*
* @access public
*/
public function save()
{
$project = $this->getProject();
$values = $this->request->getValues();
list($valid, $errors) = $this->swimlane->validateCreation($values);
if ($valid) {
if ($this->swimlane->create($project['id'], $values['name'])) {
$this->session->flash(t('Your swimlane have been created successfully.'));
$this->response->redirect('?controller=swimlane&action=index&project_id='.$project['id']);
}
else {
$this->session->flashError(t('Unable to create your swimlane.'));
}
}
$this->index($values, $errors);
}
/**
* Change the default swimlane
*
* @access public
*/
public function change()
{
$project = $this->getProject();
$values = $this->request->getValues();
list($valid,) = $this->swimlane->validateDefaultModification($values);
if ($valid) {
if ($this->swimlane->updateDefault($values)) {
$this->session->flash(t('The default swimlane have been updated successfully.'));
$this->response->redirect('?controller=swimlane&action=index&project_id='.$project['id']);
}
else {
$this->session->flashError(t('Unable to update this swimlane.'));
}
}
$this->index();
}
/**
* Edit a swimlane (display the form)
*
* @access public
*/
public function edit(array $values = array(), array $errors = array())
{
$project = $this->getProject();
$swimlane = $this->getSwimlane($project['id']);
$this->response->html($this->projectLayout('swimlane/edit', array(
'values' => empty($values) ? $swimlane : $values,
'errors' => $errors,
'project' => $project,
'title' => t('Swimlanes')
)));
}
/**
* Edit a swimlane (validate the form and update the database)
*
* @access public
*/
public function update()
{
$project = $this->getProject();
$values = $this->request->getValues();
list($valid, $errors) = $this->swimlane->validateModification($values);
if ($valid) {
if ($this->swimlane->rename($values['id'], $values['name'])) {
$this->session->flash(t('Swimlane updated successfully.'));
$this->response->redirect('?controller=swimlane&action=index&project_id='.$project['id']);
}
else {
$this->session->flashError(t('Unable to update this swimlane.'));
}
}
$this->edit($values, $errors);
}
/**
* Confirmation dialog before removing a swimlane
*
* @access public
*/
public function confirm()
{
$project = $this->getProject();
$swimlane = $this->getSwimlane($project['id']);
$this->response->html($this->projectLayout('swimlane/remove', array(
'project' => $project,
'swimlane' => $swimlane,
'title' => t('Remove a swimlane')
)));
}
/**
* Remove a swimlane
*
* @access public
*/
public function remove()
{
$this->checkCSRFParam();
$project = $this->getProject();
$swimlane_id = $this->request->getIntegerParam('swimlane_id');
if ($this->swimlane->remove($project['id'], $swimlane_id)) {
$this->session->flash(t('Swimlane removed successfully.'));
} else {
$this->session->flashError(t('Unable to remove this swimlane.'));
}
$this->response->redirect('?controller=swimlane&action=index&project_id='.$project['id']);
}
/**
* Disable a swimlane
*
* @access public
*/
public function disable()
{
$this->checkCSRFParam();
$project = $this->getProject();
$swimlane_id = $this->request->getIntegerParam('swimlane_id');
if ($this->swimlane->disable($project['id'], $swimlane_id)) {
$this->session->flash(t('Swimlane updated successfully.'));
} else {
$this->session->flashError(t('Unable to update this swimlane.'));
}
$this->response->redirect('?controller=swimlane&action=index&project_id='.$project['id']);
}
/**
* Enable a swimlane
*
* @access public
*/
public function enable()
{
$this->checkCSRFParam();
$project = $this->getProject();
$swimlane_id = $this->request->getIntegerParam('swimlane_id');
if ($this->swimlane->enable($project['id'], $swimlane_id)) {
$this->session->flash(t('Swimlane updated successfully.'));
} else {
$this->session->flashError(t('Unable to update this swimlane.'));
}
$this->response->redirect('?controller=swimlane&action=index&project_id='.$project['id']);
}
/**
* Move up a swimlane
*
* @access public
*/
public function moveup()
{
$this->checkCSRFParam();
$project = $this->getProject();
$swimlane_id = $this->request->getIntegerParam('swimlane_id');
$this->swimlane->moveUp($project['id'], $swimlane_id);
$this->response->redirect('?controller=swimlane&action=index&project_id='.$project['id']);
}
/**
* Move down a swimlane
*
* @access public
*/
public function movedown()
{
$this->checkCSRFParam();
$project = $this->getProject();
$swimlane_id = $this->request->getIntegerParam('swimlane_id');
$this->swimlane->moveDown($project['id'], $swimlane_id);
$this->response->redirect('?controller=swimlane&action=index&project_id='.$project['id']);
}
}

View file

@ -89,11 +89,12 @@ class Task extends Base
public function create(array $values = array(), array $errors = array()) public function create(array $values = array(), array $errors = array())
{ {
$project = $this->getProject(); $project = $this->getProject();
$method = $this->request->isAjax() ? 'load' : 'layout'; $method = $this->request->isAjax() ? 'render' : 'layout';
if (empty($values)) { if (empty($values)) {
$values = array( $values = array(
'swimlane_id' => $this->request->getIntegerParam('swimlane_id'),
'column_id' => $this->request->getIntegerParam('column_id'), 'column_id' => $this->request->getIntegerParam('column_id'),
'color_id' => $this->request->getStringParam('color_id'), 'color_id' => $this->request->getStringParam('color_id'),
'owner_id' => $this->request->getIntegerParam('owner_id'), 'owner_id' => $this->request->getIntegerParam('owner_id'),
@ -125,9 +126,7 @@ class Task extends Base
{ {
$project = $this->getProject(); $project = $this->getProject();
$values = $this->request->getValues(); $values = $this->request->getValues();
$values['creator_id'] = $this->acl->getUserId(); $values['creator_id'] = $this->userSession->getId();
$this->checkProjectPermissions($project['id']);
list($valid, $errors) = $this->taskValidator->validateCreation($values); list($valid, $errors) = $this->taskValidator->validateCreation($values);
@ -142,7 +141,7 @@ class Task extends Base
$this->response->redirect('?controller=task&action=create&'.http_build_query($values)); $this->response->redirect('?controller=task&action=create&'.http_build_query($values));
} }
else { else {
$this->response->redirect('?controller=board&action=show&project_id='.$values['project_id']); $this->response->redirect('?controller=board&action=show&project_id='.$project['id']);
} }
} }
else { else {
@ -158,16 +157,20 @@ class Task extends Base
* *
* @access public * @access public
*/ */
public function edit() public function edit(array $values = array(), array $errors = array())
{ {
$task = $this->getTask(); $task = $this->getTask();
$ajax = $this->request->isAjax(); $ajax = $this->request->isAjax();
$this->dateParser->format($task, array('date_due')); if (empty($values)) {
$values = $task;
}
$this->dateParser->format($values, array('date_due'));
$params = array( $params = array(
'values' => $task, 'values' => $values,
'errors' => array(), 'errors' => $errors,
'task' => $task, 'task' => $task,
'users_list' => $this->projectPermission->getMemberList($task['project_id']), 'users_list' => $this->projectPermission->getMemberList($task['project_id']),
'colors_list' => $this->color->getList(), 'colors_list' => $this->color->getList(),
@ -178,7 +181,7 @@ class Task extends Base
); );
if ($ajax) { if ($ajax) {
$this->response->html($this->template->load('task/edit', $params)); $this->response->html($this->template->render('task/edit', $params));
} }
else { else {
$this->response->html($this->taskLayout('task/edit', $params)); $this->response->html($this->taskLayout('task/edit', $params));
@ -206,7 +209,7 @@ class Task extends Base
$this->response->redirect('?controller=board&action=show&project_id='.$task['project_id']); $this->response->redirect('?controller=board&action=show&project_id='.$task['project_id']);
} }
else { else {
$this->response->redirect('?controller=task&action=show&task_id='.$task['id']); $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id']);
} }
} }
else { else {
@ -214,18 +217,7 @@ class Task extends Base
} }
} }
$this->response->html($this->taskLayout('task/edit', array( $this->edit($values, $errors);
'values' => $values,
'errors' => $errors,
'task' => $task,
'columns_list' => $this->board->getColumnsList($values['project_id']),
'users_list' => $this->projectPermission->getMemberList($values['project_id']),
'colors_list' => $this->color->getList(),
'categories_list' => $this->category->getList($values['project_id']),
'date_format' => $this->config->get('application_date_format'),
'date_formats' => $this->dateParser->getAvailableFormats(),
'ajax' => $this->request->isAjax(),
)));
} }
/** /**
@ -247,7 +239,7 @@ class Task extends Base
$this->session->flashError(t('Unable to update your task.')); $this->session->flashError(t('Unable to update your task.'));
} }
$this->response->redirect('?controller=task&action=show&task_id='.$task['id']); $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id']);
} }
/** /**
@ -269,7 +261,7 @@ class Task extends Base
$this->session->flashError(t('Unable to close this task.')); $this->session->flashError(t('Unable to close this task.'));
} }
$this->response->redirect('?controller=task&action=show&task_id='.$task['id']); $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id']);
} }
$this->response->html($this->taskLayout('task/close', array( $this->response->html($this->taskLayout('task/close', array(
@ -296,7 +288,7 @@ class Task extends Base
$this->session->flashError(t('Unable to open this task.')); $this->session->flashError(t('Unable to open this task.'));
} }
$this->response->redirect('?controller=task&action=show&task_id='.$task['id']); $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id']);
} }
$this->response->html($this->taskLayout('task/open', array( $this->response->html($this->taskLayout('task/open', array(
@ -351,10 +343,10 @@ class Task extends Base
if ($task_id) { if ($task_id) {
$this->session->flash(t('Task created successfully.')); $this->session->flash(t('Task created successfully.'));
$this->response->redirect('?controller=task&action=show&task_id='.$task_id); $this->response->redirect('?controller=task&action=show&task_id='.$task_id.'&project_id='.$task['project_id']);
} else { } else {
$this->session->flashError(t('Unable to create this task.')); $this->session->flashError(t('Unable to create this task.'));
$this->response->redirect('?controller=task&action=duplicate&task_id='.$task['id']); $this->response->redirect('?controller=task&action=duplicate&task_id='.$task['id'].'&project_id='.$task['project_id']);
} }
} }
@ -392,7 +384,7 @@ class Task extends Base
$this->response->redirect('?controller=board&action=show&project_id='.$task['project_id']); $this->response->redirect('?controller=board&action=show&project_id='.$task['project_id']);
} }
else { else {
$this->response->redirect('?controller=task&action=show&task_id='.$task['id']); $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id']);
} }
} }
} }
@ -409,7 +401,7 @@ class Task extends Base
); );
if ($ajax) { if ($ajax) {
$this->response->html($this->template->load('task/edit_description', $params)); $this->response->html($this->template->render('task/edit_description', $params));
} }
else { else {
$this->response->html($this->taskLayout('task/edit_description', $params)); $this->response->html($this->taskLayout('task/edit_description', $params));
@ -426,7 +418,7 @@ class Task extends Base
$task = $this->getTask(); $task = $this->getTask();
$values = $task; $values = $task;
$errors = array(); $errors = array();
$projects_list = $this->projectPermission->getMemberProjects($this->acl->getUserId()); $projects_list = $this->projectPermission->getMemberProjects($this->userSession->getId());
unset($projects_list[$task['project_id']]); unset($projects_list[$task['project_id']]);
@ -439,7 +431,7 @@ class Task extends Base
if ($this->taskDuplication->moveToProject($task['id'], $values['project_id'])) { if ($this->taskDuplication->moveToProject($task['id'], $values['project_id'])) {
$this->session->flash(t('Task updated successfully.')); $this->session->flash(t('Task updated successfully.'));
$this->response->redirect('?controller=task&action=show&task_id='.$task['id']); $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$values['project_id']);
} }
else { else {
$this->session->flashError(t('Unable to update your task.')); $this->session->flashError(t('Unable to update your task.'));
@ -465,7 +457,7 @@ class Task extends Base
$task = $this->getTask(); $task = $this->getTask();
$values = $task; $values = $task;
$errors = array(); $errors = array();
$projects_list = $this->projectPermission->getMemberProjects($this->acl->getUserId()); $projects_list = $this->projectPermission->getMemberProjects($this->userSession->getId());
unset($projects_list[$task['project_id']]); unset($projects_list[$task['project_id']]);
@ -478,7 +470,7 @@ class Task extends Base
$task_id = $this->taskDuplication->duplicateToProject($task['id'], $values['project_id']); $task_id = $this->taskDuplication->duplicateToProject($task['id'], $values['project_id']);
if ($task_id) { if ($task_id) {
$this->session->flash(t('Task created successfully.')); $this->session->flash(t('Task created successfully.'));
$this->response->redirect('?controller=task&action=show&task_id='.$task_id); $this->response->redirect('?controller=task&action=show&task_id='.$task_id.'&project_id='.$values['project_id']);
} }
else { else {
$this->session->flashError(t('Unable to create your task.')); $this->session->flashError(t('Unable to create your task.'));

View file

@ -18,7 +18,7 @@ class User extends Base
public function logout() public function logout()
{ {
$this->checkCSRFParam(); $this->checkCSRFParam();
$this->authentication->backend('rememberMe')->destroy($this->acl->getUserId()); $this->authentication->backend('rememberMe')->destroy($this->userSession->getId());
$this->session->close(); $this->session->close();
$this->response->redirect('?controller=user&action=login'); $this->response->redirect('?controller=user&action=login');
} }
@ -30,7 +30,7 @@ class User extends Base
*/ */
public function login(array $values = array(), array $errors = array()) public function login(array $values = array(), array $errors = array())
{ {
if ($this->acl->isLogged()) { if ($this->userSession->isLogged()) {
$this->response->redirect('?controller=app'); $this->response->redirect('?controller=app');
} }
@ -76,9 +76,9 @@ class User extends Base
*/ */
private function layout($template, array $params) private function layout($template, array $params)
{ {
$content = $this->template->load($template, $params); $content = $this->template->render($template, $params);
$params['user_content_for_layout'] = $content; $params['user_content_for_layout'] = $content;
$params['board_selector'] = $this->projectPermission->getAllowedProjects($this->acl->getUserId()); $params['board_selector'] = $this->projectPermission->getAllowedProjects($this->userSession->getId());
if (isset($params['user'])) { if (isset($params['user'])) {
$params['title'] = ($params['user']['name'] ?: $params['user']['username']).' (#'.$params['user']['id'].')'; $params['title'] = ($params['user']['name'] ?: $params['user']['username']).' (#'.$params['user']['id'].')';
@ -101,7 +101,7 @@ class User extends Base
$this->notfound(); $this->notfound();
} }
if ($this->acl->isRegularUser() && $this->acl->getUserId() != $user['id']) { if (! $this->userSession->isAdmin() && $this->userSession->getId() != $user['id']) {
$this->forbidden(); $this->forbidden();
} }
@ -125,7 +125,7 @@ class User extends Base
$this->response->html( $this->response->html(
$this->template->layout('user/index', array( $this->template->layout('user/index', array(
'board_selector' => $this->projectPermission->getAllowedProjects($this->acl->getUserId()), 'board_selector' => $this->projectPermission->getAllowedProjects($this->userSession->getId()),
'projects' => $this->project->getList(), 'projects' => $this->project->getList(),
'nb_users' => $nb_users, 'nb_users' => $nb_users,
'users' => $users, 'users' => $users,
@ -151,7 +151,9 @@ class User extends Base
public function create(array $values = array(), array $errors = array()) public function create(array $values = array(), array $errors = array())
{ {
$this->response->html($this->template->layout('user/new', array( $this->response->html($this->template->layout('user/new', array(
'board_selector' => $this->projectPermission->getAllowedProjects($this->acl->getUserId()), 'timezones' => $this->config->getTimezones(true),
'languages' => $this->config->getLanguages(true),
'board_selector' => $this->projectPermission->getAllowedProjects($this->userSession->getId()),
'projects' => $this->project->getList(), 'projects' => $this->project->getList(),
'errors' => $errors, 'errors' => $errors,
'values' => $values, 'values' => $values,
@ -194,6 +196,8 @@ class User extends Base
$this->response->html($this->layout('user/show', array( $this->response->html($this->layout('user/show', array(
'projects' => $this->projectPermission->getAllowedProjects($user['id']), 'projects' => $this->projectPermission->getAllowedProjects($user['id']),
'user' => $user, 'user' => $user,
'timezones' => $this->config->getTimezones(true),
'languages' => $this->config->getLanguages(true),
))); )));
} }
@ -328,7 +332,7 @@ class User extends Base
$values = $this->request->getValues(); $values = $this->request->getValues();
if ($this->acl->isAdminUser()) { if ($this->userSession->isAdmin()) {
$values += array('is_admin' => 0); $values += array('is_admin' => 0);
} }
else { else {
@ -358,6 +362,8 @@ class User extends Base
'errors' => $errors, 'errors' => $errors,
'projects' => $this->projectPermission->filterProjects($this->project->getList(), $user['id']), 'projects' => $this->projectPermission->filterProjects($this->project->getList(), $user['id']),
'user' => $user, 'user' => $user,
'timezones' => $this->config->getTimezones(true),
'languages' => $this->config->getLanguages(true),
))); )));
} }
@ -404,16 +410,16 @@ class User extends Base
if (is_array($profile)) { if (is_array($profile)) {
// If the user is already logged, link the account otherwise authenticate // If the user is already logged, link the account otherwise authenticate
if ($this->acl->isLogged()) { if ($this->userSession->isLogged()) {
if ($this->authentication->backend('google')->updateUser($this->acl->getUserId(), $profile)) { if ($this->authentication->backend('google')->updateUser($this->userSession->getId(), $profile)) {
$this->session->flash(t('Your Google Account is linked to your profile successfully.')); $this->session->flash(t('Your Google Account is linked to your profile successfully.'));
} }
else { else {
$this->session->flashError(t('Unable to link your Google Account.')); $this->session->flashError(t('Unable to link your Google Account.'));
} }
$this->response->redirect('?controller=user&action=external&user_id='.$this->acl->getUserId()); $this->response->redirect('?controller=user&action=external&user_id='.$this->userSession->getId());
} }
else if ($this->authentication->backend('google')->authenticate($profile['id'])) { else if ($this->authentication->backend('google')->authenticate($profile['id'])) {
$this->response->redirect('?controller=app'); $this->response->redirect('?controller=app');
@ -441,14 +447,14 @@ class User extends Base
public function unlinkGoogle() public function unlinkGoogle()
{ {
$this->checkCSRFParam(); $this->checkCSRFParam();
if ($this->authentication->backend('google')->unlink($this->acl->getUserId())) { if ($this->authentication->backend('google')->unlink($this->userSession->getId())) {
$this->session->flash(t('Your Google Account is not linked anymore to your profile.')); $this->session->flash(t('Your Google Account is not linked anymore to your profile.'));
} }
else { else {
$this->session->flashError(t('Unable to unlink your Google Account.')); $this->session->flashError(t('Unable to unlink your Google Account.'));
} }
$this->response->redirect('?controller=user&action=external&user_id='.$this->acl->getUserId()); $this->response->redirect('?controller=user&action=external&user_id='.$this->userSession->getId());
} }
/** /**
@ -466,16 +472,16 @@ class User extends Base
if (is_array($profile)) { if (is_array($profile)) {
// If the user is already logged, link the account otherwise authenticate // If the user is already logged, link the account otherwise authenticate
if ($this->acl->isLogged()) { if ($this->userSession->isLogged()) {
if ($this->authentication->backend('gitHub')->updateUser($this->acl->getUserId(), $profile)) { if ($this->authentication->backend('gitHub')->updateUser($this->userSession->getId(), $profile)) {
$this->session->flash(t('Your GitHub account was successfully linked to your profile.')); $this->session->flash(t('Your GitHub account was successfully linked to your profile.'));
} }
else { else {
$this->session->flashError(t('Unable to link your GitHub Account.')); $this->session->flashError(t('Unable to link your GitHub Account.'));
} }
$this->response->redirect('?controller=user&action=external&user_id='.$this->acl->getUserId()); $this->response->redirect('?controller=user&action=external&user_id='.$this->userSession->getId());
} }
else if ($this->authentication->backend('gitHub')->authenticate($profile['id'])) { else if ($this->authentication->backend('gitHub')->authenticate($profile['id'])) {
$this->response->redirect('?controller=app'); $this->response->redirect('?controller=app');
@ -506,13 +512,13 @@ class User extends Base
$this->authentication->backend('gitHub')->revokeGitHubAccess(); $this->authentication->backend('gitHub')->revokeGitHubAccess();
if ($this->authentication->backend('gitHub')->unlink($this->acl->getUserId())) { if ($this->authentication->backend('gitHub')->unlink($this->userSession->getId())) {
$this->session->flash(t('Your GitHub account is no longer linked to your profile.')); $this->session->flash(t('Your GitHub account is no longer linked to your profile.'));
} }
else { else {
$this->session->flashError(t('Unable to unlink your GitHub Account.')); $this->session->flashError(t('Unable to unlink your GitHub Account.'));
} }
$this->response->redirect('?controller=user&action=external&user_id='.$this->acl->getUserId()); $this->response->redirect('?controller=user&action=external&user_id='.$this->userSession->getId());
} }
} }

View file

@ -57,7 +57,27 @@ class Webhook extends Base
$result = $this->githubWebhook->parsePayload( $result = $this->githubWebhook->parsePayload(
$this->request->getHeader('X-Github-Event'), $this->request->getHeader('X-Github-Event'),
$this->request->getJson() $this->request->getJson() ?: array()
);
echo $result ? 'PARSED' : 'IGNORED';
}
/**
* Handle Gitlab webhooks
*
* @access public
*/
public function gitlab()
{
if ($this->config->get('webhook_token') !== $this->request->getStringParam('token')) {
$this->response->text('Not Authorized', 401);
}
$this->gitlabWebhook->setProjectId($this->request->getIntegerParam('project_id'));
$result = $this->gitlabWebhook->parsePayload(
$this->request->getJson() ?: array()
); );
echo $result ? 'PARSED' : 'IGNORED'; echo $result ? 'PARSED' : 'IGNORED';

View file

@ -0,0 +1,58 @@
<?php
namespace Core;
use Pimple\Container;
abstract class Cache
{
/**
* Container instance
*
* @access protected
* @var \Pimple\Container
*/
protected $container;
abstract public function init();
abstract public function set($key, $value);
abstract public function get($key);
abstract public function flush();
abstract public function remove($key);
/**
* Constructor
*
* @access public
* @param \Pimple\Container $container
*/
public function __construct(Container $container)
{
$this->container = $container;
$this->init();
}
/**
* Proxy cache
*
* Note: Arguments must be scalar types
*
* @access public
* @param string $container Container name
* @param string $method Container method
* @return mixed
*/
public function proxy($container, $method)
{
$args = func_get_args();
$key = 'proxy_'.implode('_', $args);
$result = $this->get($key);
if ($result === null) {
$result = call_user_func_array(array($this->container[$container], $method), array_splice($args, 2));
$this->set($key, $result);
}
return $result;
}
}

View file

@ -1,175 +0,0 @@
<?php
namespace Core;
/**
* Event dispatcher class
*
* @package core
* @author Frederic Guillot
*/
class Event
{
/**
* Contains all listeners
*
* @access private
* @var array
*/
private $listeners = array();
/**
* The last listener executed
*
* @access private
* @var string
*/
private $lastListener = '';
/**
* The last triggered event
*
* @access private
* @var string
*/
private $lastEvent = '';
/**
* Triggered events list
*
* @access private
* @var array
*/
private $events = array();
/**
* Attach a listener object to an event
*
* @access public
* @param string $eventName Event name
* @param Listener $listener Object that implements the Listener interface
*/
public function attach($eventName, Listener $listener)
{
if (! isset($this->listeners[$eventName])) {
$this->listeners[$eventName] = array();
}
$this->listeners[$eventName][] = $listener;
}
/**
* Trigger an event
*
* @access public
* @param string $eventName Event name
* @param array $data Event data
*/
public function trigger($eventName, array $data)
{
if (! $this->isEventTriggered($eventName)) {
$this->events[$eventName] = $data;
if (isset($this->listeners[$eventName])) {
foreach ($this->listeners[$eventName] as $listener) {
$this->lastEvent = $eventName;
if ($listener->execute($data)) {
$this->lastListener = get_class($listener);
}
}
}
}
}
/**
* Get the last listener executed
*
* @access public
* @return string Event name
*/
public function getLastListenerExecuted()
{
return $this->lastListener;
}
/**
* Get the last fired event
*
* @access public
* @return string Event name
*/
public function getLastTriggeredEvent()
{
return $this->lastEvent;
}
/**
* Get a list of triggered events
*
* @access public
* @return array
*/
public function getTriggeredEvents()
{
return $this->events;
}
/**
* Get a list of triggered events
*
* @access public
* @return array
*/
public function getEventData($eventName)
{
return isset($this->events[$eventName]) ? $this->events[$eventName] : array();
}
/**
* Check if an event have been triggered
*
* @access public
* @param string $eventName Event name
* @return bool
*/
public function isEventTriggered($eventName)
{
return isset($this->events[$eventName]);
}
/**
* Flush the list of triggered events
*
* @access public
*/
public function clearTriggeredEvents()
{
$this->events = array();
$this->lastEvent = '';
}
/**
* Check if a listener bind to an event
*
* @access public
* @param string $eventName Event name
* @param mixed $instance Instance name or object itself
* @return bool Yes or no
*/
public function hasListener($eventName, $instance)
{
if (isset($this->listeners[$eventName])) {
foreach ($this->listeners[$eventName] as $listener) {
if ($listener instanceof $instance) {
return true;
}
}
}
return false;
}
}

View file

@ -0,0 +1,41 @@
<?php
namespace Core;
class FileCache extends Cache
{
const CACHE_FOLDER = 'data/cache/';
public function init()
{
if (! is_dir(self::CACHE_FOLDER)) {
mkdir(self::CACHE_FOLDER);
}
}
public function set($key, $value)
{
file_put_contents(self::CACHE_FOLDER.$key, json_encode($value));
}
public function get($key)
{
if (file_exists(self::CACHE_FOLDER.$key)) {
return json_decode(file_get_contents(self::CACHE_FOLDER.$key), true);
}
return null;
}
public function flush()
{
foreach (glob(self::CACHE_FOLDER.'*') as $filename) {
@unlink($filename);
}
}
public function remove($key)
{
@unlink(self::CACHE_FOLDER.$key);
}
}

659
sources/app/Core/Helper.php Normal file
View file

@ -0,0 +1,659 @@
<?php
namespace Core;
use Pimple\Container;
use Parsedown;
/**
* Template helpers
*
* @package core
* @author Frederic Guillot
*
* @property \Core\Session $session
* @property \Model\Acl $acl
* @property \Model\User $user
* @property \Model\UserSession $userSession
*/
class Helper
{
/**
* Container instance
*
* @access protected
* @var \Pimple\Container
*/
protected $container;
/**
* Constructor
*
* @access public
* @param \Pimple\Container $container
*/
public function __construct(Container $container)
{
$this->container = $container;
}
/**
* Load automatically models
*
* @access public
* @param string $name Model name
* @return mixed
*/
public function __get($name)
{
return $this->container[$name];
}
/**
* Proxy cache helper for acl::isManagerActionAllowed()
*
* @access public
* @param integer $project_id
* @return boolean
*/
public function isManager($project_id)
{
if ($this->userSession->isAdmin()) {
return true;
}
return $this->container['memoryCache']->proxy('acl', 'isManagerActionAllowed', $project_id);
}
/**
* Return the user full name
*
* @param array $user User properties
* @return string
*/
public function getFullname(array $user = array())
{
return $this->user->getFullname(empty($user) ? $_SESSION['user'] : $user);
}
/**
* HTML escaping
*
* @param string $value Value to escape
* @return string
*/
public function e($value)
{
return htmlspecialchars($value, ENT_QUOTES, 'UTF-8', false);
}
/**
* Add a Javascript asset
*
* @param string $filename Filename
* @return string
*/
public function js($filename)
{
return '<script type="text/javascript" src="'.$filename.'?'.filemtime($filename).'"></script>';
}
/**
* Add a stylesheet asset
*
* @param string $filename Filename
* @return string
*/
public function css($filename)
{
return '<link rel="stylesheet" href="'.$filename.'?'.filemtime($filename).'" media="screen">';
}
/**
* Display the form error class
*
* @param array $errors Error list
* @param string $name Field name
* @return string
*/
public function errorClass(array $errors, $name)
{
return ! isset($errors[$name]) ? '' : ' form-error';
}
/**
* Display a list of form errors
*
* @param array $errors List of errors
* @param string $name Field name
* @return string
*/
public function errorList(array $errors, $name)
{
$html = '';
if (isset($errors[$name])) {
$html .= '<ul class="form-errors">';
foreach ($errors[$name] as $error) {
$html .= '<li>'.$this->e($error).'</li>';
}
$html .= '</ul>';
}
return $html;
}
/**
* Get an escaped form value
*
* @param mixed $values Values
* @param string $name Field name
* @return string
*/
public function formValue($values, $name)
{
if (isset($values->$name)) {
return 'value="'.$this->e($values->$name).'"';
}
return isset($values[$name]) ? 'value="'.$this->e($values[$name]).'"' : '';
}
/**
* Hidden CSRF token field
*
* @return string
*/
public function formCsrf()
{
return '<input type="hidden" name="csrf_token" value="'.Security::getCSRFToken().'"/>';
}
/**
* Display a hidden form field
*
* @param string $name Field name
* @param array $values Form values
* @return string
*/
public function formHidden($name, array $values = array())
{
return '<input type="hidden" name="'.$name.'" id="form-'.$name.'" '.$this->formValue($values, $name).'/>';
}
/**
* Display a select field
*
* @param string $name Field name
* @param array $options Options
* @param array $values Form values
* @param array $errors Form errors
* @param string $class CSS class
* @return string
*/
public function formSelect($name, array $options, array $values = array(), array $errors = array(), $class = '')
{
$html = '<select name="'.$name.'" id="form-'.$name.'" class="'.$class.'">';
foreach ($options as $id => $value) {
$html .= '<option value="'.$this->e($id).'"';
if (isset($values->$name) && $id == $values->$name) $html .= ' selected="selected"';
if (isset($values[$name]) && $id == $values[$name]) $html .= ' selected="selected"';
$html .= '>'.$this->e($value).'</option>';
}
$html .= '</select>';
$html .= $this->errorList($errors, $name);
return $html;
}
/**
* Display a radio field group
*
* @param string $name Field name
* @param array $options Options
* @param array $values Form values
* @return string
*/
public function formRadios($name, array $options, array $values = array())
{
$html = '';
foreach ($options as $value => $label) {
$html .= $this->formRadio($name, $label, $value, isset($values[$name]) && $values[$name] == $value);
}
return $html;
}
/**
* Display a radio field
*
* @param string $name Field name
* @param string $label Form label
* @param string $value Form value
* @param boolean $selected Field selected or not
* @param string $class CSS class
* @return string
*/
public function formRadio($name, $label, $value, $selected = false, $class = '')
{
return '<label><input type="radio" name="'.$name.'" class="'.$class.'" value="'.$this->e($value).'" '.($selected ? 'selected="selected"' : '').'>'.$this->e($label).'</label>';
}
/**
* Display a checkbox field
*
* @param string $name Field name
* @param string $label Form label
* @param string $value Form value
* @param boolean $checked Field selected or not
* @param string $class CSS class
* @return string
*/
public function formCheckbox($name, $label, $value, $checked = false, $class = '')
{
return '<label><input type="checkbox" name="'.$name.'" class="'.$class.'" value="'.$this->e($value).'" '.($checked ? 'checked="checked"' : '').'>&nbsp;'.$this->e($label).'</label>';
}
/**
* Display a form label
*
* @param string $name Field name
* @param string $label Form label
* @param array $attributes HTML attributes
* @return string
*/
public function formLabel($label, $name, array $attributes = array())
{
return '<label for="form-'.$name.'" '.implode(' ', $attributes).'>'.$this->e($label).'</label>';
}
/**
* Display a textarea
*
* @param string $name Field name
* @param array $values Form values
* @param array $errors Form errors
* @param array $attributes HTML attributes
* @param string $class CSS class
* @return string
*/
public function formTextarea($name, $values = array(), array $errors = array(), array $attributes = array(), $class = '')
{
$class .= $this->errorClass($errors, $name);
$html = '<textarea name="'.$name.'" id="form-'.$name.'" class="'.$class.'" ';
$html .= implode(' ', $attributes).'>';
$html .= isset($values->$name) ? $this->e($values->$name) : isset($values[$name]) ? $values[$name] : '';
$html .= '</textarea>';
$html .= $this->errorList($errors, $name);
return $html;
}
/**
* Display a input field
*
* @param string $type HMTL input tag type
* @param string $name Field name
* @param array $values Form values
* @param array $errors Form errors
* @param array $attributes HTML attributes
* @param string $class CSS class
* @return string
*/
public function formInput($type, $name, $values = array(), array $errors = array(), array $attributes = array(), $class = '')
{
$class .= $this->errorClass($errors, $name);
$html = '<input type="'.$type.'" name="'.$name.'" id="form-'.$name.'" '.$this->formValue($values, $name).' class="'.$class.'" ';
$html .= implode(' ', $attributes).'/>';
if (in_array('required', $attributes)) $html .= '<span class="form-required">*</span>';
$html .= $this->errorList($errors, $name);
return $html;
}
/**
* Display a text field
*
* @param string $name Field name
* @param array $values Form values
* @param array $errors Form errors
* @param array $attributes HTML attributes
* @param string $class CSS class
* @return string
*/
public function formText($name, $values = array(), array $errors = array(), array $attributes = array(), $class = '')
{
return $this->formInput('text', $name, $values, $errors, $attributes, $class);
}
/**
* Display a password field
*
* @param string $name Field name
* @param array $values Form values
* @param array $errors Form errors
* @param array $attributes HTML attributes
* @param string $class CSS class
* @return string
*/
public function formPassword($name, $values = array(), array $errors = array(), array $attributes = array(), $class = '')
{
return $this->formInput('password', $name, $values, $errors, $attributes, $class);
}
/**
* Display an email field
*
* @param string $name Field name
* @param array $values Form values
* @param array $errors Form errors
* @param array $attributes HTML attributes
* @param string $class CSS class
* @return string
*/
public function formEmail($name, $values = array(), array $errors = array(), array $attributes = array(), $class = '')
{
return $this->formInput('email', $name, $values, $errors, $attributes, $class);
}
/**
* Display a number field
*
* @param string $name Field name
* @param array $values Form values
* @param array $errors Form errors
* @param array $attributes HTML attributes
* @param string $class CSS class
* @return string
*/
public function formNumber($name, $values = array(), array $errors = array(), array $attributes = array(), $class = '')
{
return $this->formInput('number', $name, $values, $errors, $attributes, $class);
}
/**
* Display a numeric field (allow decimal number)
*
* @param string $name Field name
* @param array $values Form values
* @param array $errors Form errors
* @param array $attributes HTML attributes
* @param string $class CSS class
* @return string
*/
public function formNumeric($name, $values = array(), array $errors = array(), array $attributes = array(), $class = '')
{
return $this->formInput('text', $name, $values, $errors, $attributes, $class.' form-numeric');
}
/**
* Link
*
* a('link', 'task', 'show', array('task_id' => $task_id))
*
* @param string $label Link label
* @param string $controller Controller name
* @param string $action Action name
* @param array $params Url parameters
* @param boolean $csrf Add a CSRF token
* @param string $class CSS class attribute
* @param boolean $new_tab Open the link in a new tab
* @return string
*/
public function a($label, $controller, $action, array $params = array(), $csrf = false, $class = '', $title = '', $new_tab = false)
{
return '<a href="'.$this->u($controller, $action, $params, $csrf).'" class="'.$class.'" title="'.$title.'" '.($new_tab ? 'target="_blank"' : '').'>'.$label.'</a>';
}
/**
* URL query string
*
* u('task', 'show', array('task_id' => $task_id))
*
* @param string $controller Controller name
* @param string $action Action name
* @param array $params Url parameters
* @param boolean $csrf Add a CSRF token
* @return string
*/
public function u($controller, $action, array $params = array(), $csrf = false)
{
$html = '?controller='.$controller.'&amp;action='.$action;
if ($csrf) {
$params['csrf_token'] = Security::getCSRFToken();
}
foreach ($params as $key => $value) {
$html .= '&amp;'.$key.'='.$value;
}
return $html;
}
/**
* Pagination links
*
* @param array $pagination Pagination information
* @return string
*/
public function paginate(array $pagination)
{
extract($pagination);
if ($pagination['offset'] === 0 && ($total - $pagination['offset']) <= $limit) {
return '';
}
$html = '<div class="pagination">';
$html .= '<span class="pagination-previous">';
if ($pagination['offset'] > 0) {
$offset = $pagination['offset'] - $limit;
$html .= $this->a('&larr; '.t('Previous'), $controller, $action, $params + compact('offset', 'order', 'direction'));
}
else {
$html .= '&larr; '.t('Previous');
}
$html .= '</span>';
$html .= '<span class="pagination-next">';
if (($total - $pagination['offset']) > $limit) {
$offset = $pagination['offset'] + $limit;
$html .= $this->a(t('Next').' &rarr;', $controller, $action, $params + compact('offset', 'order', 'direction'));
}
else {
$html .= t('Next').' &rarr;';
}
$html .= '</span>';
$html .= '</div>';
return $html;
}
/**
* Column sorting (work with pagination)
*
* @param string $label Column title
* @param string $column SQL column name
* @param array $pagination Pagination information
* @return string
*/
public function order($label, $column, array $pagination)
{
extract($pagination);
$prefix = '';
if ($order === $column) {
$prefix = $direction === 'DESC' ? '&#9660; ' : '&#9650; ';
$direction = $direction === 'DESC' ? 'ASC' : 'DESC';
}
$order = $column;
return $prefix.$this->a($label, $controller, $action, $params + compact('offset', 'order', 'direction'));
}
/**
* Markdown transformation
*
* @param string $text Markdown content
* @param array $link Link parameters for replacement
* @return string
*/
public function markdown($text, array $link = array())
{
$html = Parsedown::instance()
->setMarkupEscaped(true) # escapes markup (HTML)
->text($text);
// Replace task #123 by a link to the task
if (! empty($link) && preg_match_all('!#(\d+)!i', $html, $matches, PREG_SET_ORDER)) {
foreach ($matches as $match) {
$html = str_replace(
$match[0],
$this->a($match[0], $link['controller'], $link['action'], $link['params'] + array('task_id' => $match[1])),
$html
);
}
}
return $html;
}
/**
* Get the current URL without the querystring
*
* @return string
*/
public function getCurrentBaseUrl()
{
$url = Request::isHTTPS() ? 'https://' : 'http://';
$url .= $_SERVER['SERVER_NAME'];
$url .= $_SERVER['SERVER_PORT'] == 80 || $_SERVER['SERVER_PORT'] == 443 ? '' : ':'.$_SERVER['SERVER_PORT'];
$url .= dirname($_SERVER['PHP_SELF']) !== '/' ? dirname($_SERVER['PHP_SELF']).'/' : '/';
return $url;
}
/**
* Dispplay the flash session message
*
* @param string $html HTML wrapper
* @return string
*/
public function flash($html)
{
return $this->flashMessage('flash_message', $html);
}
/**
* Display the flash session error message
*
* @param string $html HTML wrapper
* @return string
*/
public function flashError($html)
{
return $this->flashMessage('flash_error_message', $html);
}
/**
* Fetch and remove a flash session message
*
* @access private
* @param string $name Message name
* @param string $html HTML wrapper
* @return string
*/
private function flashMessage($name, $html)
{
$data = '';
if (isset($this->session[$name])) {
$data = sprintf($html, $this->e($this->session[$name]));
unset($this->session[$name]);
}
return $data;
}
/**
* Format a file size
*
* @param integer $size Size in bytes
* @param integer $precision Precision
* @return string
*/
public function formatBytes($size, $precision = 2)
{
$base = log($size) / log(1024);
$suffixes = array('', 'k', 'M', 'G', 'T');
return round(pow(1024, $base - floor($base)), $precision).$suffixes[(int)floor($base)];
}
/**
* Truncate a long text
*
* @param string $value Text
* @param integer $max_length Max Length
* @param string $end Text end
* @return string
*/
public function summary($value, $max_length = 85, $end = '[...]')
{
$length = strlen($value);
if ($length > $max_length) {
return substr($value, 0, $max_length).' '.$end;
}
return $value;
}
/**
* Return true if needle is contained in the haystack
*
* @param string $haystack Haystack
* @param string $needle Needle
* @return boolean
*/
public function contains($haystack, $needle)
{
return strpos($haystack, $needle) !== false;
}
/**
* Return a value from a dictionary
*
* @param mixed $id Key
* @param array $listing Dictionary
* @param string $default_value Value displayed when the key doesn't exists
* @return string
*/
public function inList($id, array $listing, $default_value = '?')
{
if (isset($listing[$id])) {
return $this->e($listing[$id]);
}
return $default_value;
}
}

View file

@ -1,21 +0,0 @@
<?php
namespace Core;
/**
* Event listener interface
*
* @package core
* @author Frederic Guillot
*/
interface Listener
{
/**
* Execute the listener
*
* @access public
* @param array $data Event data
* @return boolean
*/
public function execute(array $data);
}

View file

@ -0,0 +1,32 @@
<?php
namespace Core;
class MemoryCache extends Cache
{
private $storage = array();
public function init()
{
}
public function set($key, $value)
{
$this->storage[$key] = $value;
}
public function get($key)
{
return isset($this->storage[$key]) ? $this->storage[$key] : null;
}
public function flush()
{
$this->storage = array();
}
public function remove($key)
{
unset($this->storage[$key]);
}
}

View file

@ -2,13 +2,15 @@
namespace Core; namespace Core;
use ArrayAccess;
/** /**
* Session class * Session class
* *
* @package core * @package core
* @author Frederic Guillot * @author Frederic Guillot
*/ */
class Session class Session implements ArrayAccess
{ {
/** /**
* Sesion lifetime * Sesion lifetime
@ -59,7 +61,7 @@ class Session
ini_set('session.entropy_length', '32'); ini_set('session.entropy_length', '32');
ini_set('session.hash_bits_per_character', 6); ini_set('session.hash_bits_per_character', 6);
// If session was autostarted with session.auto_start = 1 in php.ini destroy it // If the session was autostarted with session.auto_start = 1 in php.ini destroy it
if (isset($_SESSION)) { if (isset($_SESSION)) {
session_destroy(); session_destroy();
} }
@ -88,19 +90,17 @@ class Session
$_SESSION = array(); $_SESSION = array();
// Destroy the session cookie // Destroy the session cookie
if (ini_get('session.use_cookies')) { $params = session_get_cookie_params();
$params = session_get_cookie_params();
setcookie( setcookie(
session_name(), session_name(),
'', '',
time() - 42000, time() - 42000,
$params['path'], $params['path'],
$params['domain'], $params['domain'],
$params['secure'], $params['secure'],
$params['httponly'] $params['httponly']
); );
}
// Destroy session data // Destroy session data
session_destroy(); session_destroy();
@ -127,4 +127,24 @@ class Session
{ {
$_SESSION['flash_error_message'] = $message; $_SESSION['flash_error_message'] = $message;
} }
public function offsetSet($offset, $value)
{
$_SESSION[$offset] = $value;
}
public function offsetExists($offset)
{
return isset($_SESSION[$offset]);
}
public function offsetUnset($offset)
{
unset($_SESSION[$offset]);
}
public function offsetGet($offset)
{
return isset($_SESSION[$offset]) ? $_SESSION[$offset] : null;
}
} }

View file

@ -10,7 +10,7 @@ use LogicException;
* @package core * @package core
* @author Frederic Guillot * @author Frederic Guillot
*/ */
class Template class Template extends Helper
{ {
/** /**
* Template path * Template path
@ -20,18 +20,18 @@ class Template
const PATH = 'app/Template/'; const PATH = 'app/Template/';
/** /**
* Load a template * Render a template
* *
* Example: * Example:
* *
* $template->load('template_name', ['bla' => 'value']); * $template->render('template_name', ['bla' => 'value']);
* *
* @access public * @access public
* @params string $__template_name Template name * @params string $__template_name Template name
* @params array $__template_args Key/Value map of template variables * @params array $__template_args Key/Value map of template variables
* @return string * @return string
*/ */
public function load($__template_name, array $__template_args = array()) public function render($__template_name, array $__template_args = array())
{ {
$__template_file = self::PATH.$__template_name.'.php'; $__template_file = self::PATH.$__template_name.'.php';
@ -57,9 +57,9 @@ class Template
*/ */
public function layout($template_name, array $template_args = array(), $layout_name = 'layout') public function layout($template_name, array $template_args = array(), $layout_name = 'layout')
{ {
return $this->load( return $this->render(
$layout_name, $layout_name,
$template_args + array('content_for_layout' => $this->load($template_name, $template_args)) $template_args + array('content_for_layout' => $this->render($template_name, $template_args))
); );
} }
} }

View file

@ -2,8 +2,6 @@
namespace Core; namespace Core;
use Pimple\Container;
/** /**
* Tool class * Tool class
* *
@ -33,23 +31,4 @@ class Tool
fclose($fp); fclose($fp);
} }
} }
/**
* Load and register a model
*
* @static
* @access public
* @param Pimple\Container $container Container instance
* @param string $name Model name
* @return mixed
*/
public static function loadModel(Container $container, $name)
{
if (! isset($container[$name])) {
$class = '\Model\\'.ucfirst($name);
$container[$name] = new $class($container);
}
return $container[$name];
}
} }

View file

@ -181,5 +181,8 @@ class Translator
if (file_exists($filename)) { if (file_exists($filename)) {
self::$locales = require $filename; self::$locales = require $filename;
} }
else {
self::$locales = array();
}
} }
} }

View file

@ -0,0 +1,27 @@
<?php
namespace Event;
use Symfony\Component\EventDispatcher\Event as BaseEvent;
class AuthEvent extends BaseEvent
{
private $auth_name;
private $user_id;
public function __construct($auth_name, $user_id)
{
$this->auth_name = $auth_name;
$this->user_id = $user_id;
}
public function getUserId()
{
return $this->user_id;
}
public function getAuthType()
{
return $this->auth_name;
}
}

View file

@ -1,79 +0,0 @@
<?php
namespace Event;
use Pimple\Container;
use Core\Listener;
use Core\Tool;
/**
* Base Listener
*
* @package event
* @author Frederic Guillot
*
* @property \Model\Comment $comment
* @property \Model\Project $project
* @property \Model\ProjectActivity $projectActivity
* @property \Model\SubTask $subTask
* @property \Model\Task $task
* @property \Model\TaskFinder $taskFinder
*/
abstract class Base implements Listener
{
/**
* Container instance
*
* @access protected
* @var \Pimple\Container
*/
protected $container;
/**
* Constructor
*
* @access public
* @param \Pimple\Container $container
*/
public function __construct(Container $container)
{
$this->container = $container;
}
/**
* Return class information
*
* @access public
* @return string
*/
public function __toString()
{
return get_called_class();
}
/**
* Load automatically models
*
* @access public
* @param string $name Model name
* @return mixed
*/
public function __get($name)
{
return Tool::loadModel($this->container, $name);
}
/**
* Get event namespace
*
* Event = task.close | Namespace = task
*
* @access public
* @return string
*/
public function getEventNamespace()
{
$event_name = $this->container['event']->getLastTriggeredEvent();
return substr($event_name, 0, strpos($event_name, '.'));
}
}

View file

@ -0,0 +1,7 @@
<?php
namespace Event;
class CommentEvent extends GenericEvent
{
}

View file

@ -0,0 +1,7 @@
<?php
namespace Event;
class FileEvent extends GenericEvent
{
}

View file

@ -0,0 +1,45 @@
<?php
namespace Event;
use ArrayAccess;
use Symfony\Component\EventDispatcher\Event as BaseEvent;
class GenericEvent extends BaseEvent implements ArrayAccess
{
private $container = array();
public function __construct(array $values = array())
{
$this->container = $values;
}
public function getAll()
{
return $this->container;
}
public function offsetSet($offset, $value)
{
if (is_null($offset)) {
$this->container[] = $value;
} else {
$this->container[$offset] = $value;
}
}
public function offsetExists($offset)
{
return isset($this->container[$offset]);
}
public function offsetUnset($offset)
{
unset($this->container[$offset]);
}
public function offsetGet($offset)
{
return isset($this->container[$offset]) ? $this->container[$offset] : null;
}
}

View file

@ -1,83 +0,0 @@
<?php
namespace Event;
/**
* Notification listener
*
* @package event
* @author Frederic Guillot
*/
class NotificationListener extends Base
{
/**
* Template name
*
* @accesss private
* @var string
*/
private $template = '';
/**
* Set template name
*
* @access public
* @param string $template Template name
*/
public function setTemplate($template)
{
$this->template = $template;
}
/**
* Execute the action
*
* @access public
* @param array $data Event data dictionary
* @return bool True if the action was executed or false when not executed
*/
public function execute(array $data)
{
$values = $this->getTemplateData($data);
$users = $this->notification->getUsersList($values['task']['project_id']);
if ($users) {
$this->notification->sendEmails($this->template, $users, $values);
return true;
}
return false;
}
/**
* Fetch data for the mail template
*
* @access public
* @param array $data Event data
* @return array
*/
public function getTemplateData(array $data)
{
$values = array();
switch ($this->getEventNamespace()) {
case 'task':
$values['task'] = $this->taskFinder->getDetails($data['task_id']);
break;
case 'subtask':
$values['subtask'] = $this->subtask->getById($data['id'], true);
$values['task'] = $this->taskFinder->getDetails($data['task_id']);
break;
case 'file':
$values['file'] = $data;
$values['task'] = $this->taskFinder->getDetails($data['task_id']);
break;
case 'comment':
$values['comment'] = $this->comment->getById($data['id']);
$values['task'] = $this->taskFinder->getDetails($values['comment']['task_id']);
break;
}
return $values;
}
}

View file

@ -1,61 +0,0 @@
<?php
namespace Event;
/**
* Project activity listener
*
* @package event
* @author Frederic Guillot
*/
class ProjectActivityListener extends Base
{
/**
* Execute the action
*
* @access public
* @param array $data Event data dictionary
* @return bool True if the action was executed or false when not executed
*/
public function execute(array $data)
{
if (isset($data['task_id'])) {
$values = $this->getValues($data);
return $this->projectActivity->createEvent(
$values['task']['project_id'],
$values['task']['id'],
$this->acl->getUserId(),
$this->container['event']->getLastTriggeredEvent(),
$values
);
}
return false;
}
/**
* Get event activity data
*
* @access private
* @param array $data Event data dictionary
* @return array
*/
private function getValues(array $data)
{
$values = array();
$values['task'] = $this->taskFinder->getDetails($data['task_id']);
switch ($this->getEventNamespace()) {
case 'subtask':
$values['subtask'] = $this->subTask->getById($data['id'], true);
break;
case 'comment':
$values['comment'] = $this->comment->getById($data['id']);
break;
}
return $values;
}
}

View file

@ -1,28 +0,0 @@
<?php
namespace Event;
/**
* Project daily summary listener
*
* @package event
* @author Frederic Guillot
*/
class ProjectDailySummaryListener extends Base
{
/**
* Execute the action
*
* @access public
* @param array $data Event data dictionary
* @return bool True if the action was executed or false when not executed
*/
public function execute(array $data)
{
if (isset($data['project_id'])) {
return $this->projectDailySummary->updateTotals($data['project_id'], date('Y-m-d'));
}
return false;
}
}

View file

@ -1,30 +0,0 @@
<?php
namespace Event;
/**
* Project modification date listener
*
* Update the "last_modified" field for a project
*
* @package event
* @author Frederic Guillot
*/
class ProjectModificationDateListener extends Base
{
/**
* Execute the action
*
* @access public
* @param array $data Event data dictionary
* @return bool True if the action was executed or false when not executed
*/
public function execute(array $data)
{
if (isset($data['project_id'])) {
return $this->project->updateModificationDate($data['project_id']);
}
return false;
}
}

View file

@ -0,0 +1,7 @@
<?php
namespace Event;
class SubtaskEvent extends GenericEvent
{
}

View file

@ -0,0 +1,7 @@
<?php
namespace Event;
class TaskEvent extends GenericEvent
{
}

View file

@ -1,44 +0,0 @@
<?php
namespace Event;
/**
* Webhook task events
*
* @package event
* @author Frederic Guillot
*/
class WebhookListener extends Base
{
/**
* Url to call
*
* @access private
* @var string
*/
private $url = '';
/**
* Set webhook url
*
* @access public
* @param string $url URL to call
*/
public function setUrl($url)
{
$this->url = $url;
}
/**
* Execute the action
*
* @access public
* @param array $data Event data dictionary
* @return bool True if the action was executed or false when not executed
*/
public function execute(array $data)
{
$this->webhook->notify($this->url, $data);
return true;
}
}

View file

@ -0,0 +1,49 @@
<?php
namespace Integration;
use Pimple\Container;
/**
* Base class
*
* @package integration
* @author Frederic Guillot
*
* @property \Model\Task $task
* @property \Model\TaskFinder $taskFinder
* @property \Model\User $user
*/
abstract class Base
{
/**
* Container instance
*
* @access protected
* @var \Pimple\Container
*/
protected $container;
/**
* Constructor
*
* @access public
* @param \Pimple\Container $container
*/
public function __construct(Container $container)
{
$this->container = $container;
}
/**
* Load automatically class from the container
*
* @access public
* @param string $name
* @return mixed
*/
public function __get($name)
{
return $this->container[$name];
}
}

View file

@ -1,11 +1,14 @@
<?php <?php
namespace Model; namespace Integration;
use Event\GenericEvent;
use Model\Task;
/** /**
* Github Webhook model * Github Webhook
* *
* @package model * @package integration
* @author Frederic Guillot * @author Frederic Guillot
*/ */
class GithubWebhook extends Base class GithubWebhook extends Base
@ -87,8 +90,11 @@ class GithubWebhook extends Base
continue; continue;
} }
if ($task['is_active'] == Task::STATUS_OPEN) { if ($task['is_active'] == Task::STATUS_OPEN && $task['project_id'] == $this->project_id) {
$this->event->trigger(self::EVENT_COMMIT, array('task_id' => $task_id) + $task); $this->container['dispatcher']->dispatch(
self::EVENT_COMMIT,
new GenericEvent(array('task_id' => $task_id) + $task)
);
} }
} }
@ -146,7 +152,11 @@ class GithubWebhook extends Base
'task_id' => $task['id'], 'task_id' => $task['id'],
); );
$this->event->trigger(self::EVENT_ISSUE_COMMENT, $event); $this->container['dispatcher']->dispatch(
self::EVENT_ISSUE_COMMENT,
new GenericEvent($event)
);
return true; return true;
} }
@ -169,7 +179,11 @@ class GithubWebhook extends Base
'description' => $issue['body']."\n\n[".t('Github Issue').']('.$issue['html_url'].')', 'description' => $issue['body']."\n\n[".t('Github Issue').']('.$issue['html_url'].')',
); );
$this->event->trigger(self::EVENT_ISSUE_OPENED, $event); $this->container['dispatcher']->dispatch(
self::EVENT_ISSUE_OPENED,
new GenericEvent($event)
);
return true; return true;
} }
@ -191,7 +205,11 @@ class GithubWebhook extends Base
'reference' => $issue['number'], 'reference' => $issue['number'],
); );
$this->event->trigger(self::EVENT_ISSUE_CLOSED, $event); $this->container['dispatcher']->dispatch(
self::EVENT_ISSUE_CLOSED,
new GenericEvent($event)
);
return true; return true;
} }
@ -216,7 +234,11 @@ class GithubWebhook extends Base
'reference' => $issue['number'], 'reference' => $issue['number'],
); );
$this->event->trigger(self::EVENT_ISSUE_REOPENED, $event); $this->container['dispatcher']->dispatch(
self::EVENT_ISSUE_REOPENED,
new GenericEvent($event)
);
return true; return true;
} }
@ -244,7 +266,11 @@ class GithubWebhook extends Base
'reference' => $issue['number'], 'reference' => $issue['number'],
); );
$this->event->trigger(self::EVENT_ISSUE_ASSIGNEE_CHANGE, $event); $this->container['dispatcher']->dispatch(
self::EVENT_ISSUE_ASSIGNEE_CHANGE,
new GenericEvent($event)
);
return true; return true;
} }
@ -271,7 +297,11 @@ class GithubWebhook extends Base
'reference' => $issue['number'], 'reference' => $issue['number'],
); );
$this->event->trigger(self::EVENT_ISSUE_ASSIGNEE_CHANGE, $event); $this->container['dispatcher']->dispatch(
self::EVENT_ISSUE_ASSIGNEE_CHANGE,
new GenericEvent($event)
);
return true; return true;
} }
@ -299,7 +329,11 @@ class GithubWebhook extends Base
'label' => $label['name'], 'label' => $label['name'],
); );
$this->event->trigger(self::EVENT_ISSUE_LABEL_CHANGE, $event); $this->container['dispatcher']->dispatch(
self::EVENT_ISSUE_LABEL_CHANGE,
new GenericEvent($event)
);
return true; return true;
} }
@ -328,7 +362,11 @@ class GithubWebhook extends Base
'category_id' => 0, 'category_id' => 0,
); );
$this->event->trigger(self::EVENT_ISSUE_LABEL_CHANGE, $event); $this->container['dispatcher']->dispatch(
self::EVENT_ISSUE_LABEL_CHANGE,
new GenericEvent($event)
);
return true; return true;
} }

View file

@ -0,0 +1,213 @@
<?php
namespace Integration;
use Event\GenericEvent;
use Event\TaskEvent;
use Model\Task;
/**
* Gitlab Webhook
*
* @package integration
* @author Frederic Guillot
*/
class GitlabWebhook extends Base
{
/**
* Events
*
* @var string
*/
const EVENT_ISSUE_OPENED = 'gitlab.webhook.issue.opened';
const EVENT_ISSUE_CLOSED = 'gitlab.webhook.issue.closed';
const EVENT_COMMIT = 'gitlab.webhook.commit';
/**
* Supported webhook events
*
* @var string
*/
const TYPE_PUSH = 'push';
const TYPE_ISSUE = 'issue';
/**
* Project id
*
* @access private
* @var integer
*/
private $project_id = 0;
/**
* Set the project id
*
* @access public
* @param integer $project_id Project id
*/
public function setProjectId($project_id)
{
$this->project_id = $project_id;
}
/**
* Parse events
*
* @access public
* @param array $payload Gitlab event
* @return boolean
*/
public function parsePayload(array $payload)
{
switch ($this->getType($payload)) {
case self::TYPE_PUSH:
return $this->handlePushEvent($payload);
case self::TYPE_ISSUE;
return $this->handleIssueEvent($payload);
}
return false;
}
/**
* Get event type
*
* @access public
* @param array $payload Gitlab event
* @return string
*/
public function getType(array $payload)
{
if (isset($payload['object_kind']) && $payload['object_kind'] === 'issue') {
return self::TYPE_ISSUE;
}
if (isset($payload['commits'])) {
return self::TYPE_PUSH;
}
return '';
}
/**
* Parse push event
*
* @access public
* @param array $payload Gitlab event
* @return boolean
*/
public function handlePushEvent(array $payload)
{
foreach ($payload['commits'] as $commit) {
$this->handleCommit($commit);
}
return true;
}
/**
* Parse commit
*
* @access public
* @param array $commit Gitlab commit
* @return boolean
*/
public function handleCommit(array $commit)
{
$task_id = $this->task->getTaskIdFromText($commit['message']);
if (! $task_id) {
return false;
}
$task = $this->taskFinder->getById($task_id);
if (! $task) {
return false;
}
if ($task['is_active'] == Task::STATUS_OPEN && $task['project_id'] == $this->project_id) {
$this->container['dispatcher']->dispatch(
self::EVENT_COMMIT,
new TaskEvent(array('task_id' => $task_id) + $task)
);
return true;
}
return false;
}
/**
* Parse issue event
*
* @access public
* @param array $payload Gitlab event
* @return boolean
*/
public function handleIssueEvent(array $payload)
{
switch ($payload['object_attributes']['state']) {
case 'opened':
return $this->handleIssueOpened($payload['object_attributes']);
case 'closed':
return $this->handleIssueClosed($payload['object_attributes']);
}
return false;
}
/**
* Handle new issues
*
* @access public
* @param array $issue Issue data
* @return boolean
*/
public function handleIssueOpened(array $issue)
{
$event = array(
'project_id' => $this->project_id,
'reference' => $issue['id'],
'title' => $issue['title'],
'description' => $issue['description']."\n\n[".t('Gitlab Issue').']('.$issue['url'].')',
);
$this->container['dispatcher']->dispatch(
self::EVENT_ISSUE_OPENED,
new GenericEvent($event)
);
return true;
}
/**
* Handle issue closing
*
* @access public
* @param array $issue Issue data
* @return boolean
*/
public function handleIssueClosed(array $issue)
{
$task = $this->taskFinder->getByReference($issue['id']);
if ($task) {
$event = array(
'project_id' => $this->project_id,
'task_id' => $task['id'],
'reference' => $issue['id'],
);
$this->container['dispatcher']->dispatch(
self::EVENT_ISSUE_CLOSED,
new GenericEvent($event)
);
return true;
}
return false;
}
}

View file

@ -182,7 +182,7 @@ return array(
'Change assignee' => 'Ændre ansvarlig', 'Change assignee' => 'Ændre ansvarlig',
'Change assignee for the task "%s"' => 'Ændre ansvarlig for opgaven: "%s"', 'Change assignee for the task "%s"' => 'Ændre ansvarlig for opgaven: "%s"',
'Timezone' => 'Tidszone', 'Timezone' => 'Tidszone',
'Sorry, I didn\'t found this information in my database!' => 'Denne information kunne ikke findes i databasen!', 'Sorry, I didn\'t find this information in my database!' => 'Denne information kunne ikke findes i databasen!',
'Page not found' => 'Siden er ikke fundet', 'Page not found' => 'Siden er ikke fundet',
'Complexity' => 'Kompleksitet', 'Complexity' => 'Kompleksitet',
'limit' => 'Begrænsning', 'limit' => 'Begrænsning',
@ -194,7 +194,7 @@ return array(
'Allow this user' => 'Tillad denne bruger', 'Allow this user' => 'Tillad denne bruger',
'Only those users have access to this project:' => 'Kunne disse brugere har adgang til dette projekt:', 'Only those users have access to this project:' => 'Kunne disse brugere har adgang til dette projekt:',
'Don\'t forget that administrators have access to everything.' => 'Glem ikke at administratorer har adgang til alt.', 'Don\'t forget that administrators have access to everything.' => 'Glem ikke at administratorer har adgang til alt.',
'revoke' => 'fjern', 'Revoke' => 'Fjern',
'List of authorized users' => 'Liste over autoriserede brugere', 'List of authorized users' => 'Liste over autoriserede brugere',
'User' => 'Bruger', 'User' => 'Bruger',
'Nobody have access to this project.' => 'Ingen har adgang til dette projekt.', 'Nobody have access to this project.' => 'Ingen har adgang til dette projekt.',
@ -213,6 +213,7 @@ return array(
'Invalid date' => 'Ugyldig dato', 'Invalid date' => 'Ugyldig dato',
'Must be done before %B %e, %Y' => 'Skal være fuldført inden %d.%m.%Y', 'Must be done before %B %e, %Y' => 'Skal være fuldført inden %d.%m.%Y',
'%B %e, %Y' => '%d.%m.%Y', '%B %e, %Y' => '%d.%m.%Y',
// '%b %e, %Y' => '',
'Automatic actions' => 'Automatiske handlinger', 'Automatic actions' => 'Automatiske handlinger',
'Your automatic action have been created successfully.' => 'Din automatiske handling er oprettet.', 'Your automatic action have been created successfully.' => 'Din automatiske handling er oprettet.',
'Unable to create your automatic action.' => 'Din automatiske handling kunne ikke oprettes.', 'Unable to create your automatic action.' => 'Din automatiske handling kunne ikke oprettes.',
@ -468,18 +469,18 @@ return array(
'Unable to change the password.' => 'Adgangskoden kunne ikke ændres.', 'Unable to change the password.' => 'Adgangskoden kunne ikke ændres.',
'Change category for the task "%s"' => 'Skift kategori for opgaven "%s"', 'Change category for the task "%s"' => 'Skift kategori for opgaven "%s"',
'Change category' => 'Skift kategori', 'Change category' => 'Skift kategori',
'%s updated the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s opdatert opgaven <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s updated the task %s' => '%s opdatert opgaven %s',
'%s open the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s åben opgaven <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s opened the task %s' => '%s åben opgaven %s',
'%s moved the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to the position #%d in the column "%s"' => '%s flyt opgaven <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> til positionen #%d i kolonnen "%s"', '%s moved the task %s to the position #%d in the column "%s"' => '%s flyt opgaven %s til positionen #%d i kolonnen "%s"',
'%s moved the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to the column "%s"' => '%s flyttede opgaven <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> til kolonnen "%s"', '%s moved the task %s to the column "%s"' => '%s flyttede opgaven %s til kolonnen "%s"',
'%s created the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s oprettede opgaven <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s created the task %s' => '%s oprettede opgaven %s',
'%s closed the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '', '%s closed the task %s' => '',
'%s created a subtask for the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s oprettede en under-opgave for opgaven <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s created a subtask for the task %s' => '%s oprettede en under-opgave for opgaven %s',
'%s updated a subtask for the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s opdaterede en under-opgave for opgaven <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s updated a subtask for the task %s' => '%s opdaterede en under-opgave for opgaven %s',
'Assigned to %s with an estimate of %s/%sh' => 'Tildelt til %s med en estimering på %s/%sh', 'Assigned to %s with an estimate of %s/%sh' => 'Tildelt til %s med en estimering på %s/%sh',
'Not assigned, estimate of %sh' => 'Ikke tildelt, estimeret til %sh', 'Not assigned, estimate of %sh' => 'Ikke tildelt, estimeret til %sh',
'%s updated a comment on the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s opdateret en kommentar på opgaven <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s updated a comment on the task %s' => '%s opdateret en kommentar på opgaven %s',
'%s commented the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s har kommenteret opgaven <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s commented the task %s' => '%s har kommenteret opgaven %s',
'%s\'s activity' => '%s\'s aktvitet', '%s\'s activity' => '%s\'s aktvitet',
'No activity.' => 'Ingen aktivitet', 'No activity.' => 'Ingen aktivitet',
'RSS feed' => 'RSS feed', 'RSS feed' => 'RSS feed',
@ -498,7 +499,7 @@ return array(
'Default columns for new projects (Comma-separated)' => 'Standard kolonne for nye projekter (kommasepareret)', 'Default columns for new projects (Comma-separated)' => 'Standard kolonne for nye projekter (kommasepareret)',
'Task assignee change' => 'Opgaven ansvarlig ændring', 'Task assignee change' => 'Opgaven ansvarlig ændring',
'%s change the assignee of the task #%d to %s' => '%s skrift ansvarlig for opgaven #%d til %s', '%s change the assignee of the task #%d to %s' => '%s skrift ansvarlig for opgaven #%d til %s',
'%s change the assignee of the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to %s' => '%s skift ansvarlig for opgaven <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> til %s', '%s changed the assignee of the task %s to %s' => '%s skift ansvarlig for opgaven %s til %s',
'[%s][Column Change] %s (#%d)' => '[%s][Kolonne Skift] %s (#%d)', '[%s][Column Change] %s (#%d)' => '[%s][Kolonne Skift] %s (#%d)',
'[%s][Position Change] %s (#%d)' => '[%s][Position Skift] %s (#%d)', '[%s][Position Change] %s (#%d)' => '[%s][Position Skift] %s (#%d)',
'[%s][Assignee Change] %s (#%d)' => '[%s][Ansvarlig Skift] %s (#%d)', '[%s][Assignee Change] %s (#%d)' => '[%s][Ansvarlig Skift] %s (#%d)',
@ -555,8 +556,8 @@ return array(
// 'Webhooks' => '', // 'Webhooks' => '',
// 'API' => '', // 'API' => '',
// 'Integration' => '', // 'Integration' => '',
// 'Github webhook' => '', // 'Github webhooks' => '',
// 'Help on Github webhook' => '', // 'Help on Github webhooks' => '',
// 'Create a comment from an external provider' => '', // 'Create a comment from an external provider' => '',
// 'Github issue comment created' => '', // 'Github issue comment created' => '',
// 'Configure' => '', // 'Configure' => '',
@ -602,4 +603,49 @@ return array(
// 'Nothing to preview...' => '', // 'Nothing to preview...' => '',
// 'Preview' => '', // 'Preview' => '',
// 'Write' => '', // 'Write' => '',
// 'Active swimlanes' => '',
// 'Add a new swimlane' => '',
// 'Change default swimlane' => '',
// 'Default swimlane' => '',
// 'Do you really want to remove this swimlane: "%s"?' => '',
// 'Inactive swimlanes' => '',
// 'Set project manager' => '',
// 'Set project member' => '',
// 'Remove a swimlane' => '',
// 'Rename' => '',
// 'Show default swimlane' => '',
// 'Swimlane modification for the project "%s"' => '',
// 'Swimlane not found.' => '',
// 'Swimlane removed successfully.' => '',
// 'Swimlanes' => '',
// 'Swimlane updated successfully.' => '',
// 'The default swimlane have been updated successfully.' => '',
// 'Unable to create your swimlane.' => '',
// 'Unable to remove this swimlane.' => '',
// 'Unable to update this swimlane.' => '',
// 'Your swimlane have been created successfully.' => '',
// 'Example: "Bug, Feature Request, Improvement"' => '',
// 'Default categories for new projects (Comma-separated)' => '',
// 'Gitlab commit received' => '',
// 'Gitlab issue opened' => '',
// 'Gitlab issue closed' => '',
// 'Gitlab webhooks' => '',
// 'Help on Gitlab webhooks' => '',
// 'Integrations' => '',
// 'Integration with third-party services' => '',
// 'Role for this project' => '',
// 'Project manager' => '',
// 'Project member' => '',
// 'A project manager can change the settings of the project and have more privileges than a standard user.' => '',
// 'Gitlab Issue' => '',
// 'Subtask Id' => '',
// 'Subtasks' => '',
// 'Subtasks Export' => '',
// 'Subtasks exportation for "%s"' => '',
// 'Task Title' => '',
// 'Untitled' => '',
// 'Application default' => '',
// 'Language:' => '',
// 'Timezone:' => '',
// 'Next' => '',
); );

View file

@ -49,7 +49,7 @@ return array(
'No project' => 'Keine Projekte', 'No project' => 'Keine Projekte',
'Project' => 'Projekt', 'Project' => 'Projekt',
'Status' => 'Status', 'Status' => 'Status',
'Tasks' => 'Aufgabe', 'Tasks' => 'Aufgaben',
'Board' => 'Pinnwand', 'Board' => 'Pinnwand',
'Actions' => 'Aktionen', 'Actions' => 'Aktionen',
'Inactive' => 'Inaktiv', 'Inactive' => 'Inaktiv',
@ -182,7 +182,7 @@ return array(
'Change assignee' => 'Zuständigkeit ändern', 'Change assignee' => 'Zuständigkeit ändern',
'Change assignee for the task "%s"' => 'Zuständigkeit für diese Aufgabe ändern: "%s"', 'Change assignee for the task "%s"' => 'Zuständigkeit für diese Aufgabe ändern: "%s"',
'Timezone' => 'Zeitzone', 'Timezone' => 'Zeitzone',
'Sorry, I didn\'t found this information in my database!' => 'Diese Information wurde in der Datenbank nicht gefunden!', 'Sorry, I didn\'t find this information in my database!' => 'Diese Information wurde in der Datenbank nicht gefunden!',
'Page not found' => 'Seite nicht gefunden', 'Page not found' => 'Seite nicht gefunden',
'Complexity' => 'Komplexität', 'Complexity' => 'Komplexität',
'limit' => 'Limit', 'limit' => 'Limit',
@ -194,7 +194,7 @@ return array(
'Allow this user' => 'Diesen Benutzer autorisieren', 'Allow this user' => 'Diesen Benutzer autorisieren',
'Only those users have access to this project:' => 'Nur diese Benutzer haben Zugriff zum Projekt:', 'Only those users have access to this project:' => 'Nur diese Benutzer haben Zugriff zum Projekt:',
'Don\'t forget that administrators have access to everything.' => 'Nicht vergessen: Administratoren haben überall Zugriff.', 'Don\'t forget that administrators have access to everything.' => 'Nicht vergessen: Administratoren haben überall Zugriff.',
'revoke' => 'entfernen', 'Revoke' => 'Entfernen',
'List of authorized users' => 'Liste der autorisierten Benutzer', 'List of authorized users' => 'Liste der autorisierten Benutzer',
'User' => 'Benutzer', 'User' => 'Benutzer',
'Nobody have access to this project.' => 'Niemand hat Zugriff auf dieses Projekt.', 'Nobody have access to this project.' => 'Niemand hat Zugriff auf dieses Projekt.',
@ -202,9 +202,9 @@ return array(
'Comments' => 'Kommentare', 'Comments' => 'Kommentare',
'Post comment' => 'Kommentieren', 'Post comment' => 'Kommentieren',
'Write your text in Markdown' => 'Schreibe deinen Text in Markdown-Syntax', 'Write your text in Markdown' => 'Schreibe deinen Text in Markdown-Syntax',
'Leave a comment' => 'Kommentar eingeben...', 'Leave a comment' => 'Kommentar eingeben',
'Comment is required' => 'Ein Kommentar wird benötigt', 'Comment is required' => 'Ein Kommentar wird benötigt',
'Leave a description' => 'Beschreibung eingeben...', 'Leave a description' => 'Beschreibung eingeben',
'Comment added successfully.' => 'Kommentar erfolgreich hinzugefügt.', 'Comment added successfully.' => 'Kommentar erfolgreich hinzugefügt.',
'Unable to create your comment.' => 'Hinzufügen eines Kommentars nicht möglich.', 'Unable to create your comment.' => 'Hinzufügen eines Kommentars nicht möglich.',
'The description is required' => 'Eine Beschreibung wird benötigt', 'The description is required' => 'Eine Beschreibung wird benötigt',
@ -213,8 +213,9 @@ return array(
'Invalid date' => 'Ungültiges Datum', 'Invalid date' => 'Ungültiges Datum',
'Must be done before %B %e, %Y' => 'Muss vor dem %d.%m.%Y erledigt werden', 'Must be done before %B %e, %Y' => 'Muss vor dem %d.%m.%Y erledigt werden',
'%B %e, %Y' => '%d.%m.%Y', '%B %e, %Y' => '%d.%m.%Y',
// '%b %e, %Y' => '',
'Automatic actions' => 'Automatische Aktionen', 'Automatic actions' => 'Automatische Aktionen',
'Your automatic action have been created successfully.' => 'Die Automatische Aktion wurde erfolgreich erstellt.', 'Your automatic action have been created successfully.' => 'Die automatische Aktion wurde erfolgreich erstellt.',
'Unable to create your automatic action.' => 'Erstellen der automatischen Aktion nicht möglich.', 'Unable to create your automatic action.' => 'Erstellen der automatischen Aktion nicht möglich.',
'Remove an action' => 'Aktion löschen', 'Remove an action' => 'Aktion löschen',
'Unable to remove this action.' => 'Löschen der Aktion nicht möglich.', 'Unable to remove this action.' => 'Löschen der Aktion nicht möglich.',
@ -222,8 +223,8 @@ return array(
'Automatic actions for the project "%s"' => 'Automatische Aktionen für das Projekt "%s"', 'Automatic actions for the project "%s"' => 'Automatische Aktionen für das Projekt "%s"',
'Defined actions' => 'Definierte Aktionen', 'Defined actions' => 'Definierte Aktionen',
'Add an action' => 'Aktion hinzufügen', 'Add an action' => 'Aktion hinzufügen',
'Event name' => 'Ereignis', 'Event name' => 'Ereignisname',
'Action name' => 'Aktion', 'Action name' => 'Aktionsname',
'Action parameters' => 'Aktionsparameter', 'Action parameters' => 'Aktionsparameter',
'Action' => 'Aktion', 'Action' => 'Aktion',
'Event' => 'Ereignis', 'Event' => 'Ereignis',
@ -331,7 +332,7 @@ return array(
'Remove a file' => 'Datei löschen', 'Remove a file' => 'Datei löschen',
'Unable to remove this file.' => 'Löschen der Datei nicht möglich.', 'Unable to remove this file.' => 'Löschen der Datei nicht möglich.',
'File removed successfully.' => 'Datei erfolgreich gelöscht.', 'File removed successfully.' => 'Datei erfolgreich gelöscht.',
'Attach a document' => 'Datei anhängen', 'Attach a document' => 'Dokument anhängen',
'Do you really want to remove this file: "%s"?' => 'Soll diese Datei wirklich gelöscht werden: "%s"?', 'Do you really want to remove this file: "%s"?' => 'Soll diese Datei wirklich gelöscht werden: "%s"?',
'open' => 'öffnen', 'open' => 'öffnen',
'Attachments' => 'Anhänge', 'Attachments' => 'Anhänge',
@ -366,7 +367,7 @@ return array(
'Sub-task added successfully.' => 'Teilaufgabe erfolgreich angelegt.', 'Sub-task added successfully.' => 'Teilaufgabe erfolgreich angelegt.',
'Maximum size: ' => 'Maximalgröße: ', 'Maximum size: ' => 'Maximalgröße: ',
'Unable to upload the file.' => 'Hochladen der Datei nicht möglich.', 'Unable to upload the file.' => 'Hochladen der Datei nicht möglich.',
'Display another project' => 'Zu Projekt wechseln...', 'Display another project' => 'Zu Projekt wechseln',
'Your GitHub account was successfully linked to your profile.' => 'GitHub Account erfolgreich mit dem Profil verbunden.', 'Your GitHub account was successfully linked to your profile.' => 'GitHub Account erfolgreich mit dem Profil verbunden.',
'Unable to link your GitHub Account.' => 'Verbindung mit diesem GitHub Account nicht möglich.', 'Unable to link your GitHub Account.' => 'Verbindung mit diesem GitHub Account nicht möglich.',
'GitHub authentication failed' => 'Zugriff mit GitHub fehlgeschlagen', 'GitHub authentication failed' => 'Zugriff mit GitHub fehlgeschlagen',
@ -420,7 +421,7 @@ return array(
'[Kanboard] Notification' => '[Kanboard] Benachrichtigung', '[Kanboard] Notification' => '[Kanboard] Benachrichtigung',
'I want to receive notifications only for those projects:' => 'Ich möchte nur für diese Projekte Benachrichtigungen erhalten:', 'I want to receive notifications only for those projects:' => 'Ich möchte nur für diese Projekte Benachrichtigungen erhalten:',
'view the task on Kanboard' => 'diese Aufgabe auf dem Kanboard zeigen', 'view the task on Kanboard' => 'diese Aufgabe auf dem Kanboard zeigen',
'Public access' => 'Öffentlich', 'Public access' => 'Öffentlicher Zugriff',
'Category management' => 'Kategorien verwalten', 'Category management' => 'Kategorien verwalten',
'User management' => 'Benutzer verwalten', 'User management' => 'Benutzer verwalten',
'Active tasks' => 'Aktive Aufgaben', 'Active tasks' => 'Aktive Aufgaben',
@ -448,12 +449,12 @@ return array(
'Username:' => 'Benutzername', 'Username:' => 'Benutzername',
'Name:' => 'Name', 'Name:' => 'Name',
'Email:' => 'E-Mail', 'Email:' => 'E-Mail',
'Default project:' => 'Standardprojekt', 'Default project:' => 'Standardprojekt:',
'Notifications:' => 'Benachrichtigungen', 'Notifications:' => 'Benachrichtigungen:',
'Notifications' => 'Benachrichtigungen', 'Notifications' => 'Benachrichtigungen',
'Group:' => 'Gruppe', 'Group:' => 'Gruppe',
'Regular user' => 'Standardbenutzer', 'Regular user' => 'Standardbenutzer',
'Account type:' => 'Accounttyp', 'Account type:' => 'Accounttyp:',
'Edit profile' => 'Profil bearbeiten', 'Edit profile' => 'Profil bearbeiten',
'Change password' => 'Passwort ändern', 'Change password' => 'Passwort ändern',
'Password modification' => 'Passwortänderung', 'Password modification' => 'Passwortänderung',
@ -468,18 +469,18 @@ return array(
'Unable to change the password.' => 'Passwort konnte nicht geändert werden.', 'Unable to change the password.' => 'Passwort konnte nicht geändert werden.',
'Change category for the task "%s"' => 'Kategorie der Aufgabe "%s" ändern', 'Change category for the task "%s"' => 'Kategorie der Aufgabe "%s" ändern',
'Change category' => 'Kategorie ändern', 'Change category' => 'Kategorie ändern',
'%s updated the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s hat die Aufgabe <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> aktualisiert', '%s updated the task %s' => '%s hat die Aufgabe %s aktualisiert',
'%s open the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s hat die Aufgabe <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> geöffnet', '%s opened the task %s' => '%s hat die Aufgabe %s geöffnet',
'%s moved the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to the position #%d in the column "%s"' => '%s hat die Aufgabe <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> auf die Position #%d in der Spalte "%s" verschoben', '%s moved the task %s to the position #%d in the column "%s"' => '%s hat die Aufgabe %s auf die Position #%d in der Spalte "%s" verschoben',
'%s moved the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to the column "%s"' => '%s hat die Aufgabe <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> in die Spalte "%s" verschoben', '%s moved the task %s to the column "%s"' => '%s hat die Aufgabe %s in die Spalte "%s" verschoben',
'%s created the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s hat die Aufgabe <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> angelegt', '%s created the task %s' => '%s hat die Aufgabe %s angelegt',
'%s closed the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s hat die Aufgabe <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> geschlossen', '%s closed the task %s' => '%s hat die Aufgabe %s geschlossen',
'%s created a subtask for the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s hat eine Teilaufgabe für die Aufgabe <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> angelegt', '%s created a subtask for the task %s' => '%s hat eine Teilaufgabe für die Aufgabe %s angelegt',
'%s updated a subtask for the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s hat eine Teilaufgabe der Aufgabe <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> verändert', '%s updated a subtask for the task %s' => '%s hat eine Teilaufgabe der Aufgabe %s verändert',
'Assigned to %s with an estimate of %s/%sh' => 'An %s zugewiesen mit einer Schätzung von %s/%s Stunden', 'Assigned to %s with an estimate of %s/%sh' => 'An %s zugewiesen mit einer Schätzung von %s/%s Stunden',
'Not assigned, estimate of %sh' => 'Nicht zugewiesen, Schätzung von %s Stunden', 'Not assigned, estimate of %sh' => 'Nicht zugewiesen, Schätzung von %s Stunden',
'%s updated a comment on the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s hat einen Kommentat der Aufgabe <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> aktualisiert', '%s updated a comment on the task %s' => '%s hat einen Kommentat der Aufgabe %s aktualisiert',
'%s commented the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s hat die Aufgabe <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> kommentiert', '%s commented the task %s' => '%s hat die Aufgabe %s kommentiert',
'%s\'s activity' => '%s\'s Aktivität', '%s\'s activity' => '%s\'s Aktivität',
'No activity.' => 'Keine Aktivität.', 'No activity.' => 'Keine Aktivität.',
'RSS feed' => 'RSS Feed', 'RSS feed' => 'RSS Feed',
@ -498,7 +499,7 @@ return array(
'Default columns for new projects (Comma-separated)' => 'Standardspalten für neue Projekte (komma-getrennt)', 'Default columns for new projects (Comma-separated)' => 'Standardspalten für neue Projekte (komma-getrennt)',
'Task assignee change' => 'Zuständigkeit geändert', 'Task assignee change' => 'Zuständigkeit geändert',
'%s change the assignee of the task #%d to %s' => '%s hat die Zusständigkeit der Aufgabe #%d geändert um %s', '%s change the assignee of the task #%d to %s' => '%s hat die Zusständigkeit der Aufgabe #%d geändert um %s',
'%s change the assignee of the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to %s' => '%s hat die Zuständigkeit der Aufgabe <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> geändert um %s', '%s changed the assignee of the task %s to %s' => '%s hat die Zuständigkeit der Aufgabe %s geändert um %s',
'[%s][Column Change] %s (#%d)' => '[%s][Spaltenänderung] %s (#%d)', '[%s][Column Change] %s (#%d)' => '[%s][Spaltenänderung] %s (#%d)',
'[%s][Position Change] %s (#%d)' => '[%s][Positionsänderung] %s (#%d)', '[%s][Position Change] %s (#%d)' => '[%s][Positionsänderung] %s (#%d)',
'[%s][Assignee Change] %s (#%d)' => '[%s][Zuständigkeitsänderung] %s (#%d)', '[%s][Assignee Change] %s (#%d)' => '[%s][Zuständigkeitsänderung] %s (#%d)',
@ -511,7 +512,7 @@ return array(
'Github issue assignee change' => 'Github Fehlerzuständigkeit geändert', 'Github issue assignee change' => 'Github Fehlerzuständigkeit geändert',
'Github issue label change' => 'Github Fehlerkennzeichnung verändert', 'Github issue label change' => 'Github Fehlerkennzeichnung verändert',
'Create a task from an external provider' => 'Eine Aufgabe durch einen externen Provider hinzufügen', 'Create a task from an external provider' => 'Eine Aufgabe durch einen externen Provider hinzufügen',
// 'Change the assignee based on an external username' => '', 'Change the assignee based on an external username' => 'Zuordnung ändern basierend auf externem Benutzernamen',
'Change the category based on an external label' => 'Kategorie basierend auf einer externen Kennzeichnung ändern', 'Change the category based on an external label' => 'Kategorie basierend auf einer externen Kennzeichnung ändern',
'Reference' => 'Referenz', 'Reference' => 'Referenz',
'Reference: %s' => 'Referenz: %s', 'Reference: %s' => 'Referenz: %s',
@ -544,8 +545,8 @@ return array(
'Time spent: %s hours' => 'Aufgewendete Zeit: %s Stunden', 'Time spent: %s hours' => 'Aufgewendete Zeit: %s Stunden',
'Started on %B %e, %Y' => 'Gestartet am %B %e %Y', 'Started on %B %e, %Y' => 'Gestartet am %B %e %Y',
'Start date' => 'Startdatum', 'Start date' => 'Startdatum',
'Time estimated' => 'Geplante Zeit', 'Time estimated' => 'Geschätzte Zeit',
'There is nothing assigned to you.' => 'Es ist nichts an Sie zugewiesen.', 'There is nothing assigned to you.' => 'Ihnen ist nichts zugewiesen.',
'My tasks' => 'Meine Aufgaben', 'My tasks' => 'Meine Aufgaben',
'Activity stream' => 'Letzte Aktivitäten', 'Activity stream' => 'Letzte Aktivitäten',
'Dashboard' => 'Dashboard', 'Dashboard' => 'Dashboard',
@ -555,11 +556,11 @@ return array(
'Webhooks' => 'Webhooks', 'Webhooks' => 'Webhooks',
'API' => 'API', 'API' => 'API',
'Integration' => 'Integration', 'Integration' => 'Integration',
'Github webhook' => 'Github Webhook', 'Github webhooks' => 'Github Webhook',
'Help on Github webhook' => 'Hilfe bei einem Github Webhook', 'Help on Github webhooks' => 'Hilfe für Github Webhooks',
'Create a comment from an external provider' => 'Kommentar eines externen Providers hinzufügen', 'Create a comment from an external provider' => 'Kommentar eines externen Providers hinzufügen',
'Github issue comment created' => 'Github Fehler Kommentar hinzugefügt', 'Github issue comment created' => 'Github Fehler Kommentar hinzugefügt',
'Configure' => 'konfigurieren', 'Configure' => 'Einstellungen',
'Project management' => 'Projektmanagement', 'Project management' => 'Projektmanagement',
'My projects' => 'Meine Projekte', 'My projects' => 'Meine Projekte',
'Columns' => 'Spalten', 'Columns' => 'Spalten',
@ -602,4 +603,49 @@ return array(
'Nothing to preview...' => 'Nichts in der Vorschau anzuzeigen ...', 'Nothing to preview...' => 'Nichts in der Vorschau anzuzeigen ...',
'Preview' => 'Vorschau', 'Preview' => 'Vorschau',
'Write' => 'Ändern', 'Write' => 'Ändern',
'Active swimlanes' => 'Aktive Swimlane',
'Add a new swimlane' => 'Eine neue Swimlane hinzufügen',
'Change default swimlane' => 'Standard Swimlane ändern',
'Default swimlane' => 'Standard Swimlane',
'Do you really want to remove this swimlane: "%s"?' => 'Diese Swimlane wirklich ändern: "%s"?',
'Inactive swimlanes' => 'Inaktive Swimlane',
'Set project manager' => 'zum Projektmanager machen',
'Set project member' => 'zum Projektmitglied machen',
'Remove a swimlane' => 'Swimlane entfernen',
'Rename' => 'umbenennen',
'Show default swimlane' => 'Standard Swimlane anzeigen',
'Swimlane modification for the project "%s"' => 'Swimlane Änderung für das Projekt "% s"',
'Swimlane not found.' => 'Swimlane nicht gefunden',
'Swimlane removed successfully.' => 'Swimlane erfolgreich entfernt.',
'Swimlanes' => 'Swimlanes',
'Swimlane updated successfully.' => 'Swimlane erfolgreich geändert.',
'The default swimlane have been updated successfully.' => 'Die standard Swimlane wurden erfolgreich aktualisiert. Die standard Swimlane wurden erfolgreich aktualisiert.',
'Unable to create your swimlane.' => 'Es ist nicht möglich die Swimlane zu erstellen.',
'Unable to remove this swimlane.' => 'Es ist nicht möglich die Swimlane zu entfernen.',
'Unable to update this swimlane.' => 'Es ist nicht möglich die Swimöane zu ändern.',
'Your swimlane have been created successfully.' => 'Die Swimlane wurde erfolgreich angelegt.',
'Example: "Bug, Feature Request, Improvement"' => 'Beispiel: "Bug, Funktionswünsche, Verbesserung"',
'Default categories for new projects (Comma-separated)' => 'Standard Kategorien für neue Projekte (Komma-getrennt)',
'Gitlab commit received' => 'Gitlab commit erhalten',
'Gitlab issue opened' => 'Gitlab Thema eröffnet',
'Gitlab issue closed' => 'Gitlab Thema geschlossen',
'Gitlab webhooks' => 'Gitlab Webhook',
'Help on Gitlab webhooks' => 'Hilfe für Gitlab Webhooks',
'Integrations' => 'Integration',
'Integration with third-party services' => 'Integration von Fremdleistungen',
'Role for this project' => 'Rolle für dieses Projekt',
'Project manager' => 'Projektmanager',
'Project member' => 'Projektmitglied',
'A project manager can change the settings of the project and have more privileges than a standard user.' => 'Ein Projektmanager kann die Projekteinstellungen ändern und hat mehr Rechte als ein normaler Benutzer.',
'Gitlab Issue' => 'Gitlab Thema',
'Subtask Id' => 'Teilaufgaben Id',
'Subtasks' => 'Teilaufgaben',
'Subtasks Export' => 'Teilaufgaben Export',
'Subtasks exportation for "%s"' => 'Teilaufgaben Export für "%s"',
'Task Title' => 'Aufgaben Titel',
'Untitled' => 'unbetitelt',
'Application default' => 'Anwendungsstandard',
'Language:' => 'Sprache:',
'Timezone:' => 'Zeitzone:',
// 'Next' => '',
); );

View file

@ -182,7 +182,7 @@ return array(
'Change assignee' => 'Cambiar la persona asignada', 'Change assignee' => 'Cambiar la persona asignada',
'Change assignee for the task "%s"' => 'Cambiar la persona asignada por la tarea « %s »', 'Change assignee for the task "%s"' => 'Cambiar la persona asignada por la tarea « %s »',
'Timezone' => 'Zona horaria', 'Timezone' => 'Zona horaria',
'Sorry, I didn\'t found this information in my database!' => 'Lo siento no he encontrado información en la base de datos!', 'Sorry, I didn\'t find this information in my database!' => 'Lo siento no he encontrado información en la base de datos!',
'Page not found' => 'Página no encontrada', 'Page not found' => 'Página no encontrada',
'Complexity' => 'Complejidad', 'Complexity' => 'Complejidad',
'limit' => 'límite', 'limit' => 'límite',
@ -194,7 +194,7 @@ return array(
'Allow this user' => 'Autorizar este usuario', 'Allow this user' => 'Autorizar este usuario',
'Only those users have access to this project:' => 'Solo estos usuarios tienen acceso a este proyecto:', 'Only those users have access to this project:' => 'Solo estos usuarios tienen acceso a este proyecto:',
'Don\'t forget that administrators have access to everything.' => 'No olvide que los administradores tienen acceso a todo.', 'Don\'t forget that administrators have access to everything.' => 'No olvide que los administradores tienen acceso a todo.',
'revoke' => 'revocar', 'Revoke' => 'Revocar',
'List of authorized users' => 'Lista de los usuarios autorizados', 'List of authorized users' => 'Lista de los usuarios autorizados',
'User' => 'Usuario', 'User' => 'Usuario',
// 'Nobody have access to this project.' => '', // 'Nobody have access to this project.' => '',
@ -213,6 +213,7 @@ return array(
'Invalid date' => 'Fecha no válida', 'Invalid date' => 'Fecha no válida',
'Must be done before %B %e, %Y' => 'Debe de estar hecho antes del %d/%m/%Y', 'Must be done before %B %e, %Y' => 'Debe de estar hecho antes del %d/%m/%Y',
'%B %e, %Y' => '%d/%m/%Y', '%B %e, %Y' => '%d/%m/%Y',
// '%b %e, %Y' => '',
'Automatic actions' => 'Acciones automatizadas', 'Automatic actions' => 'Acciones automatizadas',
'Your automatic action have been created successfully.' => 'La acción automatizada ha sido creada correctamente.', 'Your automatic action have been created successfully.' => 'La acción automatizada ha sido creada correctamente.',
'Unable to create your automatic action.' => 'No se puede crear esta acción automatizada.', 'Unable to create your automatic action.' => 'No se puede crear esta acción automatizada.',
@ -452,7 +453,7 @@ return array(
'Notifications:' => 'Notificaciones:', 'Notifications:' => 'Notificaciones:',
// 'Notifications' => '', // 'Notifications' => '',
'Group:' => 'Grupo:', 'Group:' => 'Grupo:',
'Regular user' => 'Usuario regular:', 'Regular user' => 'Usuario regular',
'Account type:' => 'Tipo de Cuenta:', 'Account type:' => 'Tipo de Cuenta:',
'Edit profile' => 'Editar perfil', 'Edit profile' => 'Editar perfil',
'Change password' => 'Cambiar contraseña', 'Change password' => 'Cambiar contraseña',
@ -468,18 +469,18 @@ return array(
'Unable to change the password.' => 'No pude cambiar la contraseña.', 'Unable to change the password.' => 'No pude cambiar la contraseña.',
'Change category for the task "%s"' => 'Cambiar la categoría de la tarea "%s"', 'Change category for the task "%s"' => 'Cambiar la categoría de la tarea "%s"',
'Change category' => 'Cambiar categoría', 'Change category' => 'Cambiar categoría',
'%s updated the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s actualizó la tarea <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s updated the task %s' => '%s actualizó la tarea %s',
'%s open the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s abrió la tarea <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s opened the task %s' => '%s abrió la tarea %s',
'%s moved the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to the position #%d in the column "%s"' => '%s movió la tarea <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> a la posición #%d de la columna "%s"', '%s moved the task %s to the position #%d in the column "%s"' => '%s movió la tarea %s a la posición #%d de la columna "%s"',
'%s moved the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to the column "%s"' => '%s movió la tarea <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> a la columna "%s"', '%s moved the task %s to the column "%s"' => '%s movió la tarea %s a la columna "%s"',
'%s created the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s creó la tarea <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s created the task %s' => '%s creó la tarea %s',
'%s closed the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s cerró la tarea <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s closed the task %s' => '%s cerró la tarea %s',
'%s created a subtask for the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s creó una subtarea para la tarea <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s created a subtask for the task %s' => '%s creó una subtarea para la tarea %s',
'%s updated a subtask for the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s actualizó una subtarea para la tarea <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s updated a subtask for the task %s' => '%s actualizó una subtarea para la tarea %s',
'Assigned to %s with an estimate of %s/%sh' => 'Asignada a %s con una estimación de %s/%sh', 'Assigned to %s with an estimate of %s/%sh' => 'Asignada a %s con una estimación de %s/%sh',
'Not assigned, estimate of %sh' => 'No asignada, se estima en %sh', 'Not assigned, estimate of %sh' => 'No asignada, se estima en %sh',
'%s updated a comment on the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s actualizó un comentario de la tarea <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s updated a comment on the task %s' => '%s actualizó un comentario de la tarea %s',
'%s commented the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s comentó la tarea <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s commented the task %s' => '%s comentó la tarea %s',
'%s\'s activity' => 'Actividad de %s', '%s\'s activity' => 'Actividad de %s',
'No activity.' => 'Sin actividad', 'No activity.' => 'Sin actividad',
'RSS feed' => 'Fichero RSS', 'RSS feed' => 'Fichero RSS',
@ -498,7 +499,7 @@ return array(
'Default columns for new projects (Comma-separated)' => 'Columnas por defecto de los nuevos proyectos (Separadas mediante comas)', 'Default columns for new projects (Comma-separated)' => 'Columnas por defecto de los nuevos proyectos (Separadas mediante comas)',
'Task assignee change' => 'Cambiar persona asignada a la tarea', 'Task assignee change' => 'Cambiar persona asignada a la tarea',
// '%s change the assignee of the task #%d to %s' => '', // '%s change the assignee of the task #%d to %s' => '',
// '%s change the assignee of the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to %s' => '', // '%s changed the assignee of the task %s to %s' => '',
'[%s][Column Change] %s (#%d)' => '[%s][Cambia Columna] %s (#%d)', '[%s][Column Change] %s (#%d)' => '[%s][Cambia Columna] %s (#%d)',
'[%s][Position Change] %s (#%d)' => '[%s][Cambia Posición] %s (#%d)', '[%s][Position Change] %s (#%d)' => '[%s][Cambia Posición] %s (#%d)',
'[%s][Assignee Change] %s (#%d)' => '[%s][Cambia Persona Asignada] %s (#%d)', '[%s][Assignee Change] %s (#%d)' => '[%s][Cambia Persona Asignada] %s (#%d)',
@ -555,8 +556,8 @@ return array(
// 'Webhooks' => '', // 'Webhooks' => '',
// 'API' => '', // 'API' => '',
// 'Integration' => '', // 'Integration' => '',
// 'Github webhook' => '', // 'Github webhooks' => '',
// 'Help on Github webhook' => '', // 'Help on Github webhooks' => '',
// 'Create a comment from an external provider' => '', // 'Create a comment from an external provider' => '',
// 'Github issue comment created' => '', // 'Github issue comment created' => '',
// 'Configure' => '', // 'Configure' => '',
@ -602,4 +603,49 @@ return array(
// 'Nothing to preview...' => '', // 'Nothing to preview...' => '',
// 'Preview' => '', // 'Preview' => '',
// 'Write' => '', // 'Write' => '',
// 'Active swimlanes' => '',
// 'Add a new swimlane' => '',
// 'Change default swimlane' => '',
// 'Default swimlane' => '',
// 'Do you really want to remove this swimlane: "%s"?' => '',
// 'Inactive swimlanes' => '',
// 'Set project manager' => '',
// 'Set project member' => '',
// 'Remove a swimlane' => '',
// 'Rename' => '',
// 'Show default swimlane' => '',
// 'Swimlane modification for the project "%s"' => '',
// 'Swimlane not found.' => '',
// 'Swimlane removed successfully.' => '',
// 'Swimlanes' => '',
// 'Swimlane updated successfully.' => '',
// 'The default swimlane have been updated successfully.' => '',
// 'Unable to create your swimlane.' => '',
// 'Unable to remove this swimlane.' => '',
// 'Unable to update this swimlane.' => '',
// 'Your swimlane have been created successfully.' => '',
// 'Example: "Bug, Feature Request, Improvement"' => '',
// 'Default categories for new projects (Comma-separated)' => '',
// 'Gitlab commit received' => '',
// 'Gitlab issue opened' => '',
// 'Gitlab issue closed' => '',
// 'Gitlab webhooks' => '',
// 'Help on Gitlab webhooks' => '',
// 'Integrations' => '',
// 'Integration with third-party services' => '',
// 'Role for this project' => '',
// 'Project manager' => '',
// 'Project member' => '',
// 'A project manager can change the settings of the project and have more privileges than a standard user.' => '',
// 'Gitlab Issue' => '',
// 'Subtask Id' => '',
// 'Subtasks' => '',
// 'Subtasks Export' => '',
// 'Subtasks exportation for "%s"' => '',
// 'Task Title' => '',
// 'Untitled' => '',
// 'Application default' => '',
// 'Language:' => '',
// 'Timezone:' => '',
// 'Next' => '',
); );

View file

@ -182,19 +182,19 @@ return array(
'Change assignee' => 'Vaihda suorittajaa', 'Change assignee' => 'Vaihda suorittajaa',
'Change assignee for the task "%s"' => 'Vaihda suorittajaa tehtävälle %s', 'Change assignee for the task "%s"' => 'Vaihda suorittajaa tehtävälle %s',
'Timezone' => 'Aikavyöhyke', 'Timezone' => 'Aikavyöhyke',
'Sorry, I didn\'t found this information in my database!' => 'Anteeksi, en löytänyt tätä tietoa tietokannastani', 'Sorry, I didn\'t find this information in my database!' => 'Anteeksi, en löytänyt tätä tietoa tietokannastani',
'Page not found' => 'Sivua ei löydy', 'Page not found' => 'Sivua ei löydy',
'Complexity' => 'Monimutkaisuus', 'Complexity' => 'Monimutkaisuus',
'limit' => 'raja', 'limit' => 'raja',
'Task limit' => 'Tehtävien maksimimäärä', 'Task limit' => 'Tehtävien maksimimäärä',
// 'Task count' => '', 'Task count' => 'Tehtävien määrä',
'This value must be greater than %d' => 'Arvon täytyy olla suurempi kuin %d', 'This value must be greater than %d' => 'Arvon täytyy olla suurempi kuin %d',
'Edit project access list' => 'Muuta projektin käyttäjiä', 'Edit project access list' => 'Muuta projektin käyttäjiä',
'Edit users access' => 'Muuta käyttäjien pääsyä', 'Edit users access' => 'Muuta käyttäjien pääsyä',
'Allow this user' => 'Salli tämä projekti', 'Allow this user' => 'Salli tämä projekti',
'Only those users have access to this project:' => 'Vain näillä käyttäjillä on pääsy projektiin:', 'Only those users have access to this project:' => 'Vain näillä käyttäjillä on pääsy projektiin:',
'Don\'t forget that administrators have access to everything.' => 'Muista että ylläpitäjät pääsevät kaikkialle.', 'Don\'t forget that administrators have access to everything.' => 'Muista että ylläpitäjät pääsevät kaikkialle.',
'revoke' => 'poista', 'Revoke' => 'Poista',
'List of authorized users' => 'Sallittujen käyttäjien lista', 'List of authorized users' => 'Sallittujen käyttäjien lista',
'User' => 'Käyttäjät', 'User' => 'Käyttäjät',
// 'Nobody have access to this project.' => '', // 'Nobody have access to this project.' => '',
@ -213,6 +213,7 @@ return array(
'Invalid date' => 'Virheellinen päiväys', 'Invalid date' => 'Virheellinen päiväys',
'Must be done before %B %e, %Y' => 'Täytyy suorittaa ennen %d.%m.%Y', 'Must be done before %B %e, %Y' => 'Täytyy suorittaa ennen %d.%m.%Y',
'%B %e, %Y' => '%d.%m.%Y', '%B %e, %Y' => '%d.%m.%Y',
// '%b %e, %Y' => '',
'Automatic actions' => 'Automaattiset toiminnot', 'Automatic actions' => 'Automaattiset toiminnot',
'Your automatic action have been created successfully.' => 'Toiminto suoritettiin onnistuneesti.', 'Your automatic action have been created successfully.' => 'Toiminto suoritettiin onnistuneesti.',
'Unable to create your automatic action.' => 'Automaattisen toiminnon luominen epäonnistui.', 'Unable to create your automatic action.' => 'Automaattisen toiminnon luominen epäonnistui.',
@ -367,14 +368,14 @@ return array(
'Maximum size: ' => 'Maksimikoko: ', 'Maximum size: ' => 'Maksimikoko: ',
'Unable to upload the file.' => 'Tiedoston lataus epäonnistui.', 'Unable to upload the file.' => 'Tiedoston lataus epäonnistui.',
'Display another project' => 'Näytä toinen projekti', 'Display another project' => 'Näytä toinen projekti',
// 'Your GitHub account was successfully linked to your profile.' => '', 'Your GitHub account was successfully linked to your profile.' => 'Github-tilisi on onnistuneesti liitetty profiiliisi',
// 'Unable to link your GitHub Account.' => '', 'Unable to link your GitHub Account.' => 'Github-tilin liittäminen epäonnistui',
// 'GitHub authentication failed' => '', 'GitHub authentication failed' => 'Github-todennus epäonnistui',
// 'Your GitHub account is no longer linked to your profile.' => '', 'Your GitHub account is no longer linked to your profile.' => 'Github-tiliäsi ei ole enää liitetty profiiliisi.',
// 'Unable to unlink your GitHub Account.' => '', 'Unable to unlink your GitHub Account.' => 'Github-tilisi liitoksen poisto epäonnistui',
// 'Login with my GitHub Account' => '', 'Login with my GitHub Account' => 'Kirjaudu sisään Github-tililläni',
// 'Link my GitHub Account' => '', 'Link my GitHub Account' => 'Liitä Github-tilini',
// 'Unlink my GitHub Account' => '', 'Unlink my GitHub Account' => 'Poista liitos Github-tiliini',
'Created by %s' => 'Luonut: %s', 'Created by %s' => 'Luonut: %s',
'Last modified on %B %e, %Y at %k:%M %p' => 'Viimeksi muokattu %B %e, %Y kello %H:%M', 'Last modified on %B %e, %Y at %k:%M %p' => 'Viimeksi muokattu %B %e, %Y kello %H:%M',
'Tasks Export' => 'Tehtävien vienti', 'Tasks Export' => 'Tehtävien vienti',
@ -388,24 +389,24 @@ return array(
'Completion date' => 'Valmistumispäivä', 'Completion date' => 'Valmistumispäivä',
'Webhook URL for task creation' => 'Webhook URL tehtävän luomiselle', 'Webhook URL for task creation' => 'Webhook URL tehtävän luomiselle',
'Webhook URL for task modification' => 'Webhook URL tehtävän muokkaamiselle', 'Webhook URL for task modification' => 'Webhook URL tehtävän muokkaamiselle',
// 'Clone' => '', 'Clone' => 'Kahdenna',
// 'Clone Project' => '', 'Clone Project' => 'Kahdenna projekti',
// 'Project cloned successfully.' => '', 'Project cloned successfully.' => 'Projekti kahdennettu onnistuneesti',
// 'Unable to clone this project.' => '', 'Unable to clone this project.' => 'Projektin kahdennus epäonnistui',
// 'Email notifications' => '', 'Email notifications' => 'Sähköposti-ilmoitukset',
// 'Enable email notifications' => '', 'Enable email notifications' => 'Ota käyttöön sähköposti-ilmoitukset',
// 'Task position:' => '', 'Task position:' => 'Tehtävän sijainti',
// 'The task #%d have been opened.' => '', 'The task #%d have been opened.' => 'Tehtävä #%d on avattu',
// 'The task #%d have been closed.' => '', 'The task #%d have been closed.' => 'Tehtävä #%d on suljettu',
// 'Sub-task updated' => '', 'Sub-task updated' => 'Alitehtävä päivitetty',
// 'Title:' => '', 'Title:' => 'Otsikko:',
// 'Status:' => '', 'Status:' => 'Tila:',
// 'Assignee:' => '', 'Assignee:' => 'Vastaanottaja:',
// 'Time tracking:' => '', 'Time tracking:' => 'Ajan seuranta:',
// 'New sub-task' => '', 'New sub-task' => 'Uusi alitehtävä',
// 'New attachment added "%s"' => '', 'New attachment added "%s"' => 'Uusi liite lisätty "%s"',
// 'Comment updated' => '', 'Comment updated' => 'Kommentti päivitetty',
// 'New comment posted by %s' => '', 'New comment posted by %s' => '%s lisäsi uuden kommentin',
// 'List of due tasks for the project "%s"' => '', // 'List of due tasks for the project "%s"' => '',
// '[%s][New attachment] %s (#%d)' => '', // '[%s][New attachment] %s (#%d)' => '',
// '[%s][New comment] %s (#%d)' => '', // '[%s][New comment] %s (#%d)' => '',
@ -418,188 +419,233 @@ return array(
// '[%s][Task opened] %s (#%d)' => '', // '[%s][Task opened] %s (#%d)' => '',
// '[%s][Due tasks]' => '', // '[%s][Due tasks]' => '',
// '[Kanboard] Notification' => '', // '[Kanboard] Notification' => '',
// 'I want to receive notifications only for those projects:' => '', 'I want to receive notifications only for those projects:' => 'Haluan vastaanottaa ilmoituksia ainoastaan näistä projekteista:',
// 'view the task on Kanboard' => '', 'view the task on Kanboard' => 'katso tehtävää Kanboardissa',
// 'Public access' => '', 'Public access' => 'Julkinen käyttöoikeus',
// 'Category management' => '', 'Category management' => 'Kategorioiden hallinta',
// 'User management' => '', 'User management' => 'Käyttäjähallinta',
// 'Active tasks' => '', 'Active tasks' => 'Aktiiviset tehtävät',
// 'Disable public access' => '', 'Disable public access' => 'Poista käytöstä julkinen käyttöoikeus',
// 'Enable public access' => '', 'Enable public access' => 'Ota käyttöön ',
// 'Active projects' => '', 'Active projects' => 'Aktiiviset projektit',
// 'Inactive projects' => '', 'Inactive projects' => 'Passiiviset projektit',
// 'Public access disabled' => '', 'Public access disabled' => 'Julkinen käyttöoikeus ei ole käytössä',
// 'Do you really want to disable this project: "%s"?' => '', 'Do you really want to disable this project: "%s"?' => 'Haluatko varmasti tehdä projektista "%s" passiivisen?',
// 'Do you really want to duplicate this project: "%s"?' => '', 'Do you really want to duplicate this project: "%s"?' => 'Haluatko varmasti kahdentaa projektin "%s"?',
// 'Do you really want to enable this project: "%s"?' => '', 'Do you really want to enable this project: "%s"?' => 'Haluatko varmasti aktivoida projektinen "%s"',
// 'Project activation' => '', 'Project activation' => 'Projektin aktivointi',
// 'Move the task to another project' => '', 'Move the task to another project' => 'Siirrä tehtävä toiseen projektiin',
// 'Move to another project' => '', 'Move to another project' => 'Siirrä toiseen projektiin',
// 'Do you really want to duplicate this task?' => '', 'Do you really want to duplicate this task?' => 'Haluatko varmasti kahdentaa tämän tehtävän?',
// 'Duplicate a task' => '', 'Duplicate a task' => 'Kahdenna tehtävä',
// 'External accounts' => '', 'External accounts' => 'Muut tilit',
// 'Account type' => '', 'Account type' => 'Tilin tyyppi',
// 'Local' => '', 'Local' => 'Paikallinen',
// 'Remote' => '', 'Remote' => 'Etä',
// 'Enabled' => '', 'Enabled' => 'Käytössä',
// 'Disabled' => '', 'Disabled' => 'Pois käytöstä',
// 'Google account linked' => '', 'Google account linked' => 'Google-tili liitetty',
// 'Github account linked' => '', 'Github account linked' => 'Github-tili liitetty',
// 'Username:' => '', 'Username:' => 'Käyttäjänimi:',
// 'Name:' => '', 'Name:' => 'Nimi:',
// 'Email:' => '', 'Email:' => 'Sähköpostiosoite:',
// 'Default project:' => '', 'Default project:' => 'Oletusprojekti:',
// 'Notifications:' => '', 'Notifications:' => 'Ilmoitukset:',
// 'Notifications' => '', 'Notifications' => 'Ilmoitukset',
// 'Group:' => '', 'Group:' => 'Ryhmä:',
// 'Regular user' => '', 'Regular user' => 'Peruskäyttäjä',
// 'Account type:' => '', 'Account type:' => 'Tilin tyyppi:',
// 'Edit profile' => '', 'Edit profile' => 'Muokkaa profiilia',
// 'Change password' => '', 'Change password' => 'Vaihda salasana',
// 'Password modification' => '', 'Password modification' => 'Salasanan vaihto',
// 'External authentications' => '', 'External authentications' => 'Muut tunnistautumistavat',
// 'Google Account' => '', 'Google Account' => 'Google-tili',
// 'Github Account' => '', 'Github Account' => 'Github-tili',
// 'Never connected.' => '', 'Never connected.' => 'Ei koskaan liitetty.',
// 'No account linked.' => '', 'No account linked.' => 'Tiliä ei ole liitetty.',
// 'Account linked.' => '', 'Account linked.' => 'Tili on liitetty.',
// 'No external authentication enabled.' => '', 'No external authentication enabled.' => 'Muita tunnistautumistapoja ei ole otettu käyttöön.',
// 'Password modified successfully.' => '', 'Password modified successfully.' => 'Salasana vaihdettu onnistuneesti.',
// 'Unable to change the password.' => '', 'Unable to change the password.' => 'Salasanan vaihto epäonnistui.',
// 'Change category for the task "%s"' => '', 'Change category for the task "%s"' => 'Vaihda tehtävän "%s" kategoria',
// 'Change category' => '', 'Change category' => 'Vaihda kategoria',
// '%s updated the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '', '%s updated the task %s' => '%s päivitti tehtävän %s',
// '%s open the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '', '%s opened the task %s' => '%s avasi tehtävän %s',
// '%s moved the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to the position #%d in the column "%s"' => '', '%s moved the task %s to the position #%d in the column "%s"' => '%s siirsi tehtävän %s %d. sarakkeessa "%s"',
// '%s moved the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to the column "%s"' => '', '%s moved the task %s to the column "%s"' => '%s siirsi tehtävän %s sarakkeeseen "%s"',
// '%s created the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '', '%s created the task %s' => '%s loi tehtävän %s',
// '%s closed the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '', '%s closed the task %s' => '%s sulki tehtävän %s',
// '%s created a subtask for the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '', '%s created a subtask for the task %s' => '%s loi alitehtävän tehtävälle %s',
// '%s updated a subtask for the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '', '%s updated a subtask for the task %s' => '%s päivitti tehtävän %s alitehtävää',
// 'Assigned to %s with an estimate of %s/%sh' => '', 'Assigned to %s with an estimate of %s/%sh' => 'Annettu henkilölle %s arviolla %s/%sh',
// 'Not assigned, estimate of %sh' => '', 'Not assigned, estimate of %sh' => 'Ei annettu kenellekään, arvio %sh',
// '%s updated a comment on the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '', '%s updated a comment on the task %s' => '%s päivitti kommentia tehtävässä %s',
// '%s commented the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '', '%s commented the task %s' => '%s kommentoi tehtävää %s',
// '%s\'s activity' => '', '%s\'s activity' => 'Henkilön %s toiminta',
// 'No activity.' => '', 'No activity.' => 'Ei toimintaa.',
// 'RSS feed' => '', 'RSS feed' => 'RSS-syöte',
// '%s updated a comment on the task #%d' => '', '%s updated a comment on the task #%d' => '%s päivitti kommenttia tehtävässä #%d',
// '%s commented on the task #%d' => '', '%s commented on the task #%d' => '%s kommentoi tehtävää #%d',
// '%s updated a subtask for the task #%d' => '', '%s updated a subtask for the task #%d' => '%s päivitti tehtävän #%d alitehtävää',
// '%s created a subtask for the task #%d' => '', '%s created a subtask for the task #%d' => '%s loi alitehtävän tehtävälle #%d',
// '%s updated the task #%d' => '', '%s updated the task #%d' => '%s päivitti tehtävää #%d',
// '%s created the task #%d' => '', '%s created the task #%d' => '%s loi tehtävän #%d',
// '%s closed the task #%d' => '', '%s closed the task #%d' => '%s sulki tehtävän #%d',
// '%s open the task #%d' => '', '%s open the task #%d' => '%s avasi tehtävän #%d',
// '%s moved the task #%d to the column "%s"' => '', '%s moved the task #%d to the column "%s"' => '%s siirsi tehtävän #%d sarakkeeseen "%s"',
// '%s moved the task #%d to the position %d in the column "%s"' => '', '%s moved the task #%d to the position %d in the column "%s"' => '%s siirsi tehtävän #%d %d. sarakkeessa %s',
// 'Activity' => '', 'Activity' => 'Toiminta',
// 'Default values are "%s"' => '', 'Default values are "%s"' => 'Oletusarvot ovat "%s"',
// 'Default columns for new projects (Comma-separated)' => '', 'Default columns for new projects (Comma-separated)' => 'Oletussarakkeet uusille projekteille',
// 'Task assignee change' => '', 'Task assignee change' => 'Tehtävän saajan vaihto',
// '%s change the assignee of the task #%d to %s' => '', '%s change the assignee of the task #%d to %s' => '%s vaihtoi tehtävän #%d saajaksi %s',
// '%s change the assignee of the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to %s' => '', '%s changed the assignee of the task %s to %s' => '%s vaihtoi tehtävän %s saajaksi %s',
// '[%s][Column Change] %s (#%d)' => '', // '[%s][Column Change] %s (#%d)' => '',
// '[%s][Position Change] %s (#%d)' => '', // '[%s][Position Change] %s (#%d)' => '',
// '[%s][Assignee Change] %s (#%d)' => '', // '[%s][Assignee Change] %s (#%d)' => '',
// 'New password for the user "%s"' => '', 'New password for the user "%s"' => 'Uusi salasana käyttäjälle "%s"',
// 'Choose an event' => '', 'Choose an event' => 'Valitse toiminta',
// 'Github commit received' => '', 'Github commit received' => 'Github-kommitti vastaanotettu',
// 'Github issue opened' => '', 'Github issue opened' => 'Github-issue avattu',
// 'Github issue closed' => '', 'Github issue closed' => 'Github-issue suljettu',
// 'Github issue reopened' => '', 'Github issue reopened' => 'Github-issue uudelleenavattu',
// 'Github issue assignee change' => '', 'Github issue assignee change' => 'Github-issuen saajan vaihto',
// 'Github issue label change' => '', 'Github issue label change' => 'Github-issuen labelin vaihto',
// 'Create a task from an external provider' => '', 'Create a task from an external provider' => 'Luo tehtävä ulkoiselta tarjoajalta',
// 'Change the assignee based on an external username' => '', 'Change the assignee based on an external username' => 'Vaihda tehtävän saajaa perustuen ulkoiseen käyttäjänimeen',
// 'Change the category based on an external label' => '', 'Change the category based on an external label' => 'Vaihda kategoriaa perustuen ulkoiseen labeliin',
// 'Reference' => '', 'Reference' => 'Viite',
// 'Reference: %s' => '', 'Reference: %s' => 'Viite: %s',
// 'Label' => '', 'Label' => 'Label',
// 'Database' => '', 'Database' => 'Tietokanta',
// 'About' => '', 'About' => 'Tietoja',
// 'Database driver:' => '', 'Database driver:' => 'Tietokantaohjelmisto:',
// 'Board settings' => '', 'Board settings' => 'Taulun asetukset',
// 'URL and token' => '', 'URL and token' => 'URL ja token',
// 'Webhook settings' => '', 'Webhook settings' => 'Webhookin asetukset',
// 'URL for task creation:' => '', 'URL for task creation:' => 'URL tehtävän luomiseksi:',
// 'Reset token' => '', 'Reset token' => 'Vaihda token',
// 'API endpoint:' => '', 'API endpoint:' => 'API päätepiste:',
// 'Refresh interval for private board' => '', 'Refresh interval for private board' => 'Päivitystiheys yksityisille tauluille',
// 'Refresh interval for public board' => '', 'Refresh interval for public board' => 'Päivitystiheys julkisille tauluille',
// 'Task highlight period' => '', 'Task highlight period' => 'Tehtävän korostusaika',
// 'Period (in second) to consider a task was modified recently (0 to disable, 2 days by default)' => '', 'Period (in second) to consider a task was modified recently (0 to disable, 2 days by default)' => 'Aika (sekunteina) kuinka kauan tehtävä voidaan katsoa äskettäin muokatuksi (0 poistaa toiminnon käytöstä, oletuksena 2 päivää)',
// 'Frequency in second (60 seconds by default)' => '', 'Frequency in second (60 seconds by default)' => 'Päivitystiheys sekunteina (60 sekuntia oletuksena)',
// 'Frequency in second (0 to disable this feature, 10 seconds by default)' => '', 'Frequency in second (0 to disable this feature, 10 seconds by default)' => 'Päivitystiheys sekunteina (0 poistaa toiminnon käytöstä, oletuksena 10 sekuntia)',
// 'Application URL' => '', 'Application URL' => 'Sovelluksen URL',
// 'Example: http://example.kanboard.net/ (used by email notifications)' => '', 'Example: http://example.kanboard.net/ (used by email notifications)' => 'Esimerkiksi: http://example.kanboard.net/ (käytetään sähköposti-ilmoituksissa)',
// 'Token regenerated.' => '', 'Token regenerated.' => 'Token uudelleenluotu.',
// 'Date format' => '', 'Date format' => 'Päiväyksen muoto',
// 'ISO format is always accepted, example: "%s" and "%s"' => '', 'ISO format is always accepted, example: "%s" and "%s"' => 'ISO-muoto on aina hyväksytty, esimerkiksi %s ja %s',
// 'New private project' => '', 'New private project' => 'Uusi yksityinen projekti',
// 'This project is private' => '', 'This project is private' => 'Tämä projekti on yksityinen',
// 'Type here to create a new sub-task' => '', 'Type here to create a new sub-task' => 'Kirjoita tähän luodaksesi uuden alitehtävän',
// 'Add' => '', 'Add' => 'Lisää',
// 'Estimated time: %s hours' => '', 'Estimated time: %s hours' => 'Arvioitu aika: %s tuntia',
// 'Time spent: %s hours' => '', 'Time spent: %s hours' => 'Aikaa kulunut: %s tuntia',
// 'Started on %B %e, %Y' => '', 'Started on %B %e, %Y' => 'Aloitettu %B %e, %Y',
// 'Start date' => '', 'Start date' => 'Aloituspäivä',
// 'Time estimated' => '', 'Time estimated' => 'Arvioitu aika',
// 'There is nothing assigned to you.' => '', 'There is nothing assigned to you.' => 'Ei tehtäviä, joihin sinut olisi merkitty tekijäksi.',
// 'My tasks' => '', 'My tasks' => 'Minun tehtävät',
// 'Activity stream' => '', 'Activity stream' => 'Toiminta',
// 'Dashboard' => '', 'Dashboard' => 'Työpöytä',
// 'Confirmation' => '', 'Confirmation' => 'Vahvistus',
// 'Allow everybody to access to this project' => '', 'Allow everybody to access to this project' => 'Anna kaikille käyttöoikeus tähän projektiin',
// 'Everybody have access to this project.' => '', 'Everybody have access to this project.' => 'Kaikilla on käyttöoikeus projektiin.',
// 'Webhooks' => '', // 'Webhooks' => '',
// 'API' => '', // 'API' => '',
// 'Integration' => '', 'Integration' => 'Integraatio',
// 'Github webhook' => '', // 'Github webhooks' => '',
// 'Help on Github webhook' => '', // 'Help on Github webhooks' => '',
// 'Create a comment from an external provider' => '', // 'Create a comment from an external provider' => '',
// 'Github issue comment created' => '', // 'Github issue comment created' => '',
// 'Configure' => '', 'Configure' => 'Konfiguroi',
// 'Project management' => '', 'Project management' => 'Projektin hallinta',
// 'My projects' => '', 'My projects' => 'Minun projektini',
// 'Columns' => '', 'Columns' => 'Sarakkeet',
// 'Task' => '', 'Task' => 'Tehtävät',
// 'Your are not member of any project.' => '', 'Your are not member of any project.' => 'Et ole minkään projektin jäsen.',
// 'Percentage' => '', 'Percentage' => 'Prosentti',
// 'Number of tasks' => '', 'Number of tasks' => 'Tehtävien määrä',
// 'Task distribution' => '', 'Task distribution' => 'Tehtävien jakauma',
// 'Reportings' => '', 'Reportings' => 'Raportoinnit',
// 'Task repartition for "%s"' => '', // 'Task repartition for "%s"' => '',
// 'Analytics' => '', 'Analytics' => 'Analytiikka',
// 'Subtask' => '', 'Subtask' => 'Alitehtävä',
// 'My subtasks' => '', 'My subtasks' => 'Minun alitehtäväni',
// 'User repartition' => '', // 'User repartition' => '',
// 'User repartition for "%s"' => '', // 'User repartition for "%s"' => '',
// 'Clone this project' => '', 'Clone this project' => 'Kahdenna projekti',
// 'Column removed successfully.' => '', 'Column removed successfully.' => 'Sarake poistettu onnstuneesti.',
// 'Edit Project' => '', 'Edit Project' => 'Muokkaa projektia',
// 'Github Issue' => '', 'Github Issue' => 'Github-issue',
// 'Not enough data to show the graph.' => '', 'Not enough data to show the graph.' => 'Ei riittävästi dataa graafin näyttämiseksi.',
// 'Previous' => '', 'Previous' => 'Edellinen',
// 'The id must be an integer' => '', 'The id must be an integer' => 'ID:n on oltava kokonaisluku',
// 'The project id must be an integer' => '', 'The project id must be an integer' => 'Projektin ID:n on oltava kokonaisluku',
// 'The status must be an integer' => '', 'The status must be an integer' => 'Tilan on oltava kokonaisluku',
// 'The subtask id is required' => '', 'The subtask id is required' => 'Alitehtävän ID vaaditaan',
// 'The subtask id must be an integer' => '', 'The subtask id must be an integer' => 'Alitehtävän ID:ntulee olla kokonaisluku',
// 'The task id is required' => '', 'The task id is required' => 'Tehtävän ID vaaditaan',
// 'The task id must be an integer' => '', 'The task id must be an integer' => 'Tehtävän ID on oltava kokonaisluku',
// 'The user id must be an integer' => '', 'The user id must be an integer' => 'Käyttäjän ID on oltava kokonaisluku',
// 'This value is required' => '', 'This value is required' => 'Tämä arvo on pakollinen',
// 'This value must be numeric' => '', 'This value must be numeric' => 'Tämän arvon tulee olla numeerinen',
// 'Unable to create this task.' => '', 'Unable to create this task.' => 'Tehtävän luonti epäonnistui',
// 'Cumulative flow diagram' => '', 'Cumulative flow diagram' => 'Kumulatiivinen vuokaavio',
// 'Cumulative flow diagram for "%s"' => '', 'Cumulative flow diagram for "%s"' => 'Kumulatiivinen vuokaavio kohteelle "%s"',
// 'Daily project summary' => '', 'Daily project summary' => 'Päivittäinen yhteenveto',
// 'Daily project summary export' => '', 'Daily project summary export' => 'Päivittäisen yhteenvedon vienti',
// 'Daily project summary export for "%s"' => '', 'Daily project summary export for "%s"' => 'Päivittäisen yhteenvedon vienti kohteeseen "%s"',
// 'Exports' => '', 'Exports' => 'Viennit',
// 'This export contains the number of tasks per column grouped per day.' => '', 'This export contains the number of tasks per column grouped per day.' => 'Tämä tiedosto sisältää tehtäviä sarakkeisiin päiväkohtaisesti ryhmilteltyinä',
// 'Nothing to preview...' => '', 'Nothing to preview...' => 'Ei esikatselua...',
// 'Preview' => '', 'Preview' => 'Ei esikatselua',
// 'Write' => '', 'Write' => 'Kirjoita',
'Active swimlanes' => 'Aktiiviset kaistat',
'Add a new swimlane' => 'Lisää uusi kaista',
'Change default swimlane' => 'Vaihda oletuskaistaa',
'Default swimlane' => 'Oletuskaista',
'Do you really want to remove this swimlane: "%s"?' => 'Haluatko varmasti poistaa tämän kaistan: "%s"?',
'Inactive swimlanes' => 'Passiiviset kaistat',
// 'Set project manager' => '',
// 'Set project member' => '',
'Remove a swimlane' => 'Poista kaista',
'Rename' => 'Uudelleennimeä',
'Show default swimlane' => 'Näytä oletuskaista',
'Swimlane modification for the project "%s"' => 'Kaistamuutos projektille "%s"',
'Swimlane not found.' => 'Kaistaa ei löydy',
'Swimlane removed successfully.' => 'Kaista poistettu onnistuneesti.',
'Swimlanes' => 'Kaistat',
'Swimlane updated successfully.' => 'Kaista päivitetty onnistuneesti.',
'The default swimlane have been updated successfully.' => 'Oletuskaista päivitetty onnistuneesti.',
'Unable to create your swimlane.' => 'Kaistan luonti epäonnistui.',
'Unable to remove this swimlane.' => 'Kaistan poisto epäonnistui.',
'Unable to update this swimlane.' => 'Kaistan päivittäminen epäonnistui.',
'Your swimlane have been created successfully.' => 'Kaista luotu onnistuneesti.',
'Example: "Bug, Feature Request, Improvement"' => 'Esimerkiksi: "Bugit, Ominaisuuspyynnöt, Parannukset"',
'Default categories for new projects (Comma-separated)' => 'Oletuskategoriat uusille projekteille (pilkuin eroteltu)',
// 'Gitlab commit received' => '',
// 'Gitlab issue opened' => '',
// 'Gitlab issue closed' => '',
// 'Gitlab webhooks' => '',
// 'Help on Gitlab webhooks' => '',
// 'Integrations' => '',
// 'Integration with third-party services' => '',
// 'Role for this project' => '',
// 'Project manager' => '',
// 'Project member' => '',
// 'A project manager can change the settings of the project and have more privileges than a standard user.' => '',
// 'Gitlab Issue' => '',
// 'Subtask Id' => '',
// 'Subtasks' => '',
// 'Subtasks Export' => '',
// 'Subtasks exportation for "%s"' => '',
// 'Task Title' => '',
// 'Untitled' => '',
// 'Application default' => '',
// 'Language:' => '',
// 'Timezone:' => '',
// 'Next' => '',
); );

View file

@ -182,11 +182,11 @@ return array(
'Change assignee' => 'Changer la personne assignée', 'Change assignee' => 'Changer la personne assignée',
'Change assignee for the task "%s"' => 'Changer la personne assignée pour la tâche « %s »', 'Change assignee for the task "%s"' => 'Changer la personne assignée pour la tâche « %s »',
'Timezone' => 'Fuseau horaire', 'Timezone' => 'Fuseau horaire',
'Sorry, I didn\'t found this information in my database!' => 'Désolé, je n\'ai pas trouvé cette information dans ma base de données !', 'Sorry, I didn\'t find this information in my database!' => 'Désolé, je n\'ai pas trouvé cette information dans ma base de données !',
'Page not found' => 'Page introuvable', 'Page not found' => 'Page introuvable',
'Complexity' => 'Complexité', 'Complexity' => 'Complexité',
'limit' => 'limite', 'limit' => 'limite',
'Task limit' => 'Nombre maximum de tâches', 'Task limit' => 'Tâches Max.',
'Task count' => 'Nombre de tâches', 'Task count' => 'Nombre de tâches',
'This value must be greater than %d' => 'Cette valeur doit être plus grande que %d', 'This value must be greater than %d' => 'Cette valeur doit être plus grande que %d',
'Edit project access list' => 'Modifier l\'accès au projet', 'Edit project access list' => 'Modifier l\'accès au projet',
@ -194,7 +194,7 @@ return array(
'Allow this user' => 'Autoriser cet utilisateur', 'Allow this user' => 'Autoriser cet utilisateur',
'Only those users have access to this project:' => 'Seulement ces utilisateurs ont accès à ce projet :', 'Only those users have access to this project:' => 'Seulement ces utilisateurs ont accès à ce projet :',
'Don\'t forget that administrators have access to everything.' => 'N\'oubliez pas que les administrateurs ont accès à tout.', 'Don\'t forget that administrators have access to everything.' => 'N\'oubliez pas que les administrateurs ont accès à tout.',
'revoke' => 'révoquer', 'Revoke' => 'Révoquer',
'List of authorized users' => 'Liste des utilisateurs autorisés', 'List of authorized users' => 'Liste des utilisateurs autorisés',
'User' => 'Utilisateur', 'User' => 'Utilisateur',
'Nobody have access to this project.' => 'Personne n\'est autorisé à accéder au projet.', 'Nobody have access to this project.' => 'Personne n\'est autorisé à accéder au projet.',
@ -213,6 +213,7 @@ return array(
'Invalid date' => 'Date invalide', 'Invalid date' => 'Date invalide',
'Must be done before %B %e, %Y' => 'Doit être fait avant le %d/%m/%Y', 'Must be done before %B %e, %Y' => 'Doit être fait avant le %d/%m/%Y',
'%B %e, %Y' => '%d %B %Y', '%B %e, %Y' => '%d %B %Y',
'%b %e, %Y' => '%d/%m/%Y',
'Automatic actions' => 'Actions automatisées', 'Automatic actions' => 'Actions automatisées',
'Your automatic action have been created successfully.' => 'Votre action automatisée a été ajouté avec succès.', 'Your automatic action have been created successfully.' => 'Votre action automatisée a été ajouté avec succès.',
'Unable to create your automatic action.' => 'Impossible de créer votre action automatisée.', 'Unable to create your automatic action.' => 'Impossible de créer votre action automatisée.',
@ -468,18 +469,18 @@ return array(
'Unable to change the password.' => 'Impossible de changer le mot de passe.', 'Unable to change the password.' => 'Impossible de changer le mot de passe.',
'Change category for the task "%s"' => 'Changer la catégorie pour la tâche « %s »', 'Change category for the task "%s"' => 'Changer la catégorie pour la tâche « %s »',
'Change category' => 'Changer de catégorie', 'Change category' => 'Changer de catégorie',
'%s updated the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s a mis à jour la tâche <a href="?controller=task&amp;action=show&amp;task_id=%d">n°%d</a>', '%s updated the task %s' => '%s a mis à jour la tâche %s',
'%s open the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s a ouvert la tâche <a href="?controller=task&amp;action=show&amp;task_id=%d">n°%d</a>', '%s opened the task %s' => '%s a ouvert la tâche %s',
'%s moved the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to the position #%d in the column "%s"' => '%s a déplacé la tâche <a href="?controller=task&amp;action=show&amp;task_id=%d">n°%d</a> à la position n°%d dans la colonne « %s »', '%s moved the task %s to the position #%d in the column "%s"' => '%s a déplacé la tâche %s à la position n°%d dans la colonne « %s »',
'%s moved the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to the column "%s"' => '%s a déplacé la tâche <a href="?controller=task&amp;action=show&amp;task_id=%d">n°%d</a> dans la colonne « %s »', '%s moved the task %s to the column "%s"' => '%s a déplacé la tâche %s dans la colonne « %s »',
'%s created the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s a créé la tâche <a href="?controller=task&amp;action=show&amp;task_id=%d">n°%d</a>', '%s created the task %s' => '%s a créé la tâche %s',
'%s closed the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s a fermé la tâche <a href="?controller=task&amp;action=show&amp;task_id=%d">n°%d</a>', '%s closed the task %s' => '%s a fermé la tâche %s',
'%s created a subtask for the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s a créé une sous-tâche pour la tâche <a href="?controller=task&amp;action=show&amp;task_id=%d">n°%d</a>', '%s created a subtask for the task %s' => '%s a créé une sous-tâche pour la tâche %s',
'%s updated a subtask for the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s a mis à jour une sous-tâche appartenant à la tâche <a href="?controller=task&amp;action=show&amp;task_id=%d">n°%d</a>', '%s updated a subtask for the task %s' => '%s a mis à jour une sous-tâche appartenant à la tâche %s',
'Assigned to %s with an estimate of %s/%sh' => 'Assigné à %s avec un estimé de %s/%sh', 'Assigned to %s with an estimate of %s/%sh' => 'Assigné à %s avec un estimé de %s/%sh',
'Not assigned, estimate of %sh' => 'Personne assigné, estimé de %sh', 'Not assigned, estimate of %sh' => 'Personne assigné, estimé de %sh',
'%s updated a comment on the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s a mis à jour un commentaire appartenant à la tâche <a href="?controller=task&amp;action=show&amp;task_id=%d">n°%d</a>', '%s updated a comment on the task %s' => '%s a mis à jour un commentaire appartenant à la tâche %s',
'%s commented the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s a ajouté un commentaire sur la tâche <a href="?controller=task&amp;action=show&amp;task_id=%d">n°%d</a>', '%s commented the task %s' => '%s a ajouté un commentaire sur la tâche %s',
'%s\'s activity' => 'Activité du projet %s', '%s\'s activity' => 'Activité du projet %s',
'No activity.' => 'Aucune activité.', 'No activity.' => 'Aucune activité.',
'RSS feed' => 'Flux RSS', 'RSS feed' => 'Flux RSS',
@ -497,11 +498,11 @@ return array(
'Default values are "%s"' => 'Les valeurs par défaut sont « %s »', 'Default values are "%s"' => 'Les valeurs par défaut sont « %s »',
'Default columns for new projects (Comma-separated)' => 'Colonnes par défaut pour les nouveaux projets (séparé par des virgules)', 'Default columns for new projects (Comma-separated)' => 'Colonnes par défaut pour les nouveaux projets (séparé par des virgules)',
'Task assignee change' => 'Modification de la personne assignée sur une tâche', 'Task assignee change' => 'Modification de la personne assignée sur une tâche',
'%s change the assignee of the task #%d to %s' => '%s a changé la personne assignée sur la tâche #%d pour %s', '%s change the assignee of the task #%d to %s' => '%s a changé la personne assignée sur la tâche %d pour %s',
'%s change the assignee of the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to %s' => '%s a changé la personne assignée sur la tâche <a href="?controller=task&amp;action=show&amp;task_id=%d">n°%d</a> pour %s', '%s changed the assignee of the task %s to %s' => '%s a changé la personne assignée sur la tâche %s pour %s',
'[%s][Column Change] %s (#%d)' => '[%s][Changement de colonne] %s (#%d)', '[%s][Column Change] %s (#%d)' => '[%s][Changement de colonne] %s (%d)',
'[%s][Position Change] %s (#%d)' => '[%s][Changement de position] %s (#%d)', '[%s][Position Change] %s (#%d)' => '[%s][Changement de position] %s (%d)',
'[%s][Assignee Change] %s (#%d)' => '[%s][Changement d\'assigné] %s (#%d)', '[%s][Assignee Change] %s (#%d)' => '[%s][Changement d\'assigné] %s (%d)',
'New password for the user "%s"' => 'Nouveau mot de passe pour l\'utilisateur « %s »', 'New password for the user "%s"' => 'Nouveau mot de passe pour l\'utilisateur « %s »',
'Choose an event' => 'Choisir un événement', 'Choose an event' => 'Choisir un événement',
'Github commit received' => '« Commit » reçu via Github', 'Github commit received' => '« Commit » reçu via Github',
@ -555,8 +556,8 @@ return array(
'Webhooks' => 'Webhooks', 'Webhooks' => 'Webhooks',
'API' => 'API', 'API' => 'API',
'Integration' => 'Intégration', 'Integration' => 'Intégration',
'Github webhook' => 'Webhook Github', 'Github webhooks' => 'Webhook Github',
'Help on Github webhook' => 'Aide sur les webhooks Github', 'Help on Github webhooks' => 'Aide sur les webhooks Github',
'Create a comment from an external provider' => 'Créer un commentaire depuis un fournisseur externe', 'Create a comment from an external provider' => 'Créer un commentaire depuis un fournisseur externe',
'Github issue comment created' => 'Commentaire créé sur un ticket Github', 'Github issue comment created' => 'Commentaire créé sur un ticket Github',
'Configure' => 'Configurer', 'Configure' => 'Configurer',
@ -602,4 +603,50 @@ return array(
'Nothing to preview...' => 'Rien à prévisualiser...', 'Nothing to preview...' => 'Rien à prévisualiser...',
'Preview' => 'Prévisualiser', 'Preview' => 'Prévisualiser',
'Write' => 'Écrire', 'Write' => 'Écrire',
'Active swimlanes' => 'Swimlanes actives',
'Add a new swimlane' => 'Ajouter une nouvelle swimlane',
'Change default swimlane' => 'Modifier la swimlane par défaut',
'Default swimlane' => 'Swimlane par défaut',
'Do you really want to remove this swimlane: "%s"?' => 'Voulez-vous vraiment supprimer cette swimlane : « %s » ?',
'Inactive swimlanes' => 'Swimlanes inactives',
'Set project manager' => 'Mettre chef de projet',
'Set project member' => 'Mettre membre du projet',
'Remove a swimlane' => 'Supprimer une swimlane',
'Rename' => 'Renommer',
'Show default swimlane' => 'Afficher la swimlane par défaut',
'Swimlane modification for the project "%s"' => 'Modification d\'une swimlane pour le projet « %s »',
'Swimlane not found.' => 'Cette swimlane est introuvable.',
'Swimlane removed successfully.' => 'Swimlane supprimée avec succès.',
'Swimlanes' => 'Swimlanes',
'Swimlane updated successfully.' => 'Swimlane mise à jour avec succès.',
'The default swimlane have been updated successfully.' => 'La swimlane par défaut a été mise à jour avec succès.',
'Unable to create your swimlane.' => 'Impossible de créer votre swimlane.',
'Unable to remove this swimlane.' => 'Impossible de supprimer cette swimlane.',
'Unable to update this swimlane.' => 'Impossible de mettre à jour cette swimlane.',
'Your swimlane have been created successfully.' => 'Votre swimlane a été créée avec succès.',
'Example: "Bug, Feature Request, Improvement"' => 'Exemple: « Incident, Demande de fonctionnalité, Amélioration »',
'Default categories for new projects (Comma-separated)' => 'Catégories par défaut pour les nouveaux projets (séparé par des virgules)',
'Gitlab commit received' => '« Commit » reçu via Gitlab',
'Gitlab issue opened' => 'Ouverture d\'un ticket sur Gitlab',
'Gitlab issue closed' => 'Fermeture d\'un ticket sur Gitlab',
'Gitlab webhooks' => 'Webhook Gitlab',
'Help on Gitlab webhooks' => 'Aide sur les webhooks Gitlab',
'Integrations' => 'Intégrations',
'Integration with third-party services' => 'Intégration avec des services externes',
'Role for this project' => 'Rôle pour ce projet',
'Project manager' => 'Chef de projet',
'Project member' => 'Membre du projet',
'A project manager can change the settings of the project and have more privileges than a standard user.' => 'Un chef de projet peut changer les paramètres du projet et possède plus de privilèges qu\'un utilisateur standard.',
'Gitlab Issue' => 'Ticket Gitlab',
'Subtask Id' => 'Identifiant de la sous-tâche',
'Subtasks' => 'Sous-tâches',
'Subtasks Export' => 'Exportation des sous-tâches',
'Subtasks exportation for "%s"' => 'Exportation des sous-tâches pour le projet « %s »',
'Task Title' => 'Titre de la tâche',
'Untitled' => 'Sans nom',
'Application default' => 'Valeur par défaut de l\'application',
'Language:' => 'Langue :',
'Timezone:' => 'Fuseau horaire :',
'Next' => 'Suivant',
'#%d' => 'n˚%d',
); );

View file

@ -0,0 +1,651 @@
<?php
return array(
'None' => 'Semelyik',
'edit' => 'szerkesztés',
'Edit' => 'Szerkesztés',
'remove' => 'eltávolít',
'Remove' => 'Eltávolít',
'Update' => 'Frissítés',
'Yes' => 'Igen',
'No' => 'Nincs',
'cancel' => 'mégsem',
'or' => 'vagy',
'Yellow' => 'sárga',
'Blue' => 'kék',
'Green' => 'zöld',
'Purple' => 'ibolya',
'Red' => 'piros',
'Orange' => 'narancs',
'Grey' => 'szürke',
'Save' => 'Mentés',
'Login' => 'Bejelentkezés',
'Official website:' => 'Hivatalos honlap:',
'Unassigned' => 'Nincs felelős',
'View this task' => 'Feladat megtekintése',
'Remove user' => 'Felhasználó törlése',
'Do you really want to remove this user: "%s"?' => 'Tényleg törli ezt a felhasználót: "%s"?',
'New user' => 'új felhasználó',
'All users' => 'Minden felhasználó',
'Username' => 'Felhasználónév',
'Password' => 'Jelszó',
'Default project' => 'Alapértelmezett projekt',
'Administrator' => 'Rendszergazda',
'Sign in' => 'Jelentkezzen be',
'Users' => 'Felhasználók',
'No user' => 'Nincs felhasználó',
'Forbidden' => 'tiltott',
'Access Forbidden' => 'Hozzáférés megtagadva',
'Only administrators can access to this page.' => 'Csak a rendszergazdák férhetnek hozzá az oldalhoz.',
'Edit user' => 'Felhasználó módosítása',
'Logout' => 'Kilépés',
'Bad username or password' => 'Rossz felhasználónév vagy jelszó',
'users' => 'felhasználók',
'projects' => 'projektek',
'Edit project' => 'Projekt szerkesztése',
'Name' => 'Név',
'Activated' => 'Aktiválva',
'Projects' => 'Projektek',
'No project' => 'Nincs projekt',
'Project' => 'Projekt',
'Status' => 'Állapot',
'Tasks' => 'Feladat',
'Board' => 'Tábla',
'Actions' => 'Műveletek',
'Inactive' => 'Inaktív',
'Active' => 'Aktív',
'Column %d' => 'Oszlop %d',
'Add this column' => 'Oszlop hozzáadása',
'%d tasks on the board' => 'A táblán %d feladat',
'%d tasks in total' => 'Összesen %d feladat',
'Unable to update this board.' => 'Nem lehet frissíteni a táblát.',
'Edit board' => 'Tábla szerkesztése',
'Disable' => 'Letilt',
'Enable' => 'Engedélyez',
'New project' => 'Új projekt',
'Do you really want to remove this project: "%s"?' => 'Valóban törölni akarja ezt a projektet: "%s"?',
'Remove project' => 'Projekt törlése',
'Boards' => 'Táblák',
'Edit the board for "%s"' => 'Tábla szerkesztése "%s"',
'All projects' => 'Minden projekt',
'Change columns' => 'Oszlop módosítása',
'Add a new column' => 'Új oszlop',
'Title' => 'Cím',
'Add Column' => 'Oszlopot hozzáad',
'Project "%s"' => 'Projekt "%s"',
'Nobody assigned' => 'Nincs felelős',
'Assigned to %s' => 'Felelős: %s',
'Remove a column' => 'Oszlop törlése',
'Remove a column from a board' => 'Oszlop törlése a tábláról',
'Unable to remove this column.' => 'Az oszlop törlése nem lehetséges.',
'Do you really want to remove this column: "%s"?' => 'Valóban törölni akarja ezt az oszlopot: "%s"?',
'This action will REMOVE ALL TASKS associated to this column!' => 'Az oszlophoz rendelt ÖSSZES FELADAT TÖRLŐDNI FOG!',
'Settings' => 'Beállítások',
'Application settings' => 'Alkalmazás beállítások',
'Language' => 'Nyelv',
'Webhook token:' => 'Webhook token:',
'API token:' => 'API token:',
'More information' => 'További információ',
'Database size:' => 'Adatbázis méret:',
'Download the database' => 'Adatbázis letöltése',
'Optimize the database' => 'Adatbázis optimalizálása',
'(VACUUM command)' => '(VACUUM parancs)',
'(Gzip compressed Sqlite file)' => '(Gzip tömörített SQLite fájl)',
'User settings' => 'Felhasználói beállítások',
'My default project:' => 'Alapértelmezett project:',
'Close a task' => 'Feladat lezárása',
'Do you really want to close this task: "%s"?' => 'Tényleg le akarja zárni ezt a feladatot: "%s"?',
'Edit a task' => 'Feladat módosítása',
'Column' => 'Oszlop',
'Color' => 'Szín',
'Assignee' => 'Felelős',
'Create another task' => 'Új feladat létrehozása',
'New task' => 'új feladat',
'Open a task' => 'Feladat megnyitása',
'Do you really want to open this task: "%s"?' => 'Tényleg meg akarja nyitni ezt a feladatot: "%s"?',
'Back to the board' => 'Vissza a táblához',
'Created on %B %e, %Y at %k:%M %p' => 'Létrehozva: %Y.%m.%d %k:%M %p',
'There is nobody assigned' => 'Nincs felelős',
'Column on the board:' => 'Tábla oszlopa:',
'Status is open' => 'Állapot nyitva',
'Status is closed' => 'Állapot zárva',
'Close this task' => 'Feladat bezárása',
'Open this task' => 'Feladat megnyitása',
'There is no description.' => 'Nincs elérhető leírás.',
'Add a new task' => 'Új feladat hozzáadása',
'The username is required' => 'Felhasználói név szükséges',
'The maximum length is %d characters' => 'A maximális hossz %d karakter',
'The minimum length is %d characters' => 'A minimális hossza %d karakter',
'The password is required' => 'Jelszó szükséges',
'This value must be an integer' => 'Ez az érték csak egész szám lehet',
'The username must be unique' => 'A felhasználó nevének egyedinek kell lennie',
'The username must be alphanumeric' => 'A felhasználói név csak alfanumerikus lehet (betűk és számok)',
'The user id is required' => 'A felhasználói azonosítót meg kell adni',
'Passwords don\'t match' => 'A jelszavak nem egyeznek',
'The confirmation is required' => 'Megerősítés szükséges',
'The column is required' => 'Az oszlopot meg kell adni',
'The project is required' => 'A projektet meg kell adni',
'The color is required' => 'A színt meg kell adni',
'The id is required' => 'Az ID-t (azonosítót) meg kell adni',
'The project id is required' => 'A projekt ID-t (azonosítót) meg kell adni',
'The project name is required' => 'A projekt nevét meg kell adni',
'This project must be unique' => 'A projekt nevének egyedinek kell lennie',
'The title is required' => 'A címet meg kell adni',
'The language is required' => 'A nyelvet meg kell adni',
'There is no active project, the first step is to create a new project.' => 'Nincs aktív projekt. Először létre kell hozni egy projektet.',
'Settings saved successfully.' => 'A beállítások sikeresen mentve.',
'Unable to save your settings.' => 'Beállítások mentése nem sikerült.',
'Database optimization done.' => 'Adatbázis optimalizálás kész.',
'Your project have been created successfully.' => 'A projekt sikeresen elkészült.',
'Unable to create your project.' => 'Projekt létrehozása nem sikerült.',
'Project updated successfully.' => 'Projekt sikeres frissítve.',
'Unable to update this project.' => 'Projekt frissítése nem sikerült.',
'Unable to remove this project.' => 'Projekt törlése nem sikerült.',
'Project removed successfully.' => 'Projekt sikeresen törölve.',
'Project activated successfully.' => 'Projekt sikeresen aktiválta.',
'Unable to activate this project.' => 'Projekt aktiválása nem sikerült.',
'Project disabled successfully.' => 'Projekt sikeresen letiltva.',
'Unable to disable this project.' => 'Projekt letiltása nem sikerült.',
'Unable to open this task.' => 'A feladat megnyitása nem sikerült.',
'Task opened successfully.' => 'Feladat sikeresen megnyitva .',
'Unable to close this task.' => 'A feladat lezárása nem sikerült.',
'Task closed successfully.' => 'Feladat sikeresen lezárva.',
'Unable to update your task.' => 'A feladat frissítése nem sikerült.',
'Task updated successfully.' => 'Feladat sikeresen frissítve.',
'Unable to create your task.' => 'A feladat létrehozása nem sikerült.',
'Task created successfully.' => 'Feladat sikeresen létrehozva.',
'User created successfully.' => 'Felhasználó létrehozva .',
'Unable to create your user.' => 'Felhasználó létrehozása nem sikerült.',
'User updated successfully.' => 'Felhasználó sikeresen frissítve.',
'Unable to update your user.' => 'Felhasználó frissítése nem sikerült.',
'User removed successfully.' => 'Felhasználó sikeresen törölve.',
'Unable to remove this user.' => 'Felhasználó törlése nem sikerült.',
'Board updated successfully.' => 'Tábla sikeresen frissítve.',
'Ready' => 'Kész',
'Backlog' => 'Napló',
'Work in progress' => 'Dolgozom',
'Done' => 'Kész',
'Application version:' => 'Alkalmazás verzió:',
'Completed on %B %e, %Y at %k:%M %p' => 'Elkészült %Y.%m.%d %H:%M ..',
'%B %e, %Y at %k:%M %p' => '%Y.%m.%d %H:%M',
'Date created' => 'Létrehozás időpontja',
'Date completed' => 'Befejezés időpontja',
'Id' => 'ID',
'No task' => 'Nincs feladat',
'Completed tasks' => 'Elvégzett feladatok',
'List of projects' => 'Projektek listája',
'Completed tasks for "%s"' => 'Elvégzett feladatok "%s"',
'%d closed tasks' => '%d lezárt feladat',
'No task for this project' => 'Nincs feladat ebben a projektben',
'Public link' => 'Nyilvános link',
'There is no column in your project!' => 'Nincs oszlop a projektben!',
'Change assignee' => 'Felelős módosítása',
'Change assignee for the task "%s"' => 'Feladat felelősének módosítása: "%s"',
'Timezone' => 'Időzóna',
'Sorry, I didn\'t find this information in my database!' => 'Ez az információ nem található az adatbázisban!',
'Page not found' => 'Az oldal nem található',
'Complexity' => 'Bonyolultság',
'limit' => 'határ',
'Task limit' => 'Maximális számú feladat',
'Task count' => 'Feladatok száma',
'This value must be greater than %d' => 'Az értéknek nagyobbnak kell lennie, mint %d',
'Edit project access list' => 'Projekt hozzáférés módosítása',
'Edit users access' => 'Felhasználók hozzáférésének módosítása',
'Allow this user' => 'Engedélyezi ezt a felhasználót',
'Only those users have access to this project:' => 'Csak ezek a felhasználók férhetnek hozzá a projekthez:',
'Don\'t forget that administrators have access to everything.' => 'Ne felejtsük el: a rendszergazdák mindenhez hozzáférnek.',
'Revoke' => 'Visszavon',
'List of authorized users' => 'Az engedélyezett felhasználók',
'User' => 'Felhasználó',
'Nobody have access to this project.' => 'Senkinek sincs hozzáférése a projekthez.',
'You are not allowed to access to this project.' => 'Nincs hozzáférési joga a projekthez.',
'Comments' => 'Hozzászólások',
'Post comment' => 'Hozzászólás elküldése',
'Write your text in Markdown' => 'Írja be a szöveget Markdown szintaxissal',
'Leave a comment' => 'Írjon hozzászólást ...',
'Comment is required' => 'A hozzászólás mező kötelező',
'Leave a description' => 'Írjon leírást ...',
'Comment added successfully.' => 'Hozzászólás sikeresen elküldve.',
'Unable to create your comment.' => 'Hozzászólás létrehozása nem lehetséges.',
'The description is required' => 'A leírás szükséges',
'Edit this task' => 'Feladat módosítása',
'Due Date' => 'Határidő',
'Invalid date' => 'Érvénytelen dátum',
'Must be done before %B %e, %Y' => 'Kész kell lennie %Y.%m.%d előtt',
'%B %e, %Y' => '%Y.%m.%d',
// '%b %e, %Y' => '',
'Automatic actions' => 'Automatikus intézkedések',
'Your automatic action have been created successfully.' => 'Az automatikus intézkedés sikeresen elkészült.',
'Unable to create your automatic action.' => 'Automatikus intézkedés létrehozása nem lehetséges.',
'Remove an action' => 'Intézkedés törlése',
'Unable to remove this action.' => 'Intézkedés törlése nem lehetséges.',
'Action removed successfully.' => 'Intézkedés sikeresen törölve.',
'Automatic actions for the project "%s"' => 'Automatikus intézkedések a projektben "%s"',
'Defined actions' => 'Intézkedések',
'Add an action' => 'Intézkedés létrehozása',
'Event name' => 'Esemény neve',
'Action name' => 'Intézkedés neve',
'Action parameters' => 'Intézkedés paraméterei',
'Action' => 'Intézkedés',
'Event' => 'Esemény',
'When the selected event occurs execute the corresponding action.' => 'Ha a kiválasztott esemény bekövetkezik, hajtsa végre a megfelelő intézkedéseket.',
'Next step' => 'Következő lépés',
'Define action parameters' => 'Határozza meg az intézkedés paramétereit',
'Save this action' => 'Intézkedés mentése',
'Do you really want to remove this action: "%s"?' => 'Valóban törölni akarja ezt az intézkedést: "%s"?',
'Remove an automatic action' => 'Automatikus intézkedés törlése',
'Close the task' => 'Feladat lezárása',
'Assign the task to a specific user' => 'Feladat kiosztása megadott felhasználónak',
'Assign the task to the person who does the action' => 'Feladat kiosztása az intézkedő személynek',
'Duplicate the task to another project' => 'Feladat másolása másik projektbe',
'Move a task to another column' => 'Feladat mozgatása másik oszlopba',
'Move a task to another position in the same column' => 'Feladat mozgatása oszlopon belül',
'Task modification' => 'Feladat módosítása',
'Task creation' => 'Feladat létrehozása',
'Open a closed task' => 'Lezárt feladat megnyitása',
'Closing a task' => 'Feladat lezárása',
'Assign a color to a specific user' => 'Szín hozzárendelése a felhasználóhoz',
'Column title' => 'Oszlopfejléc',
'Position' => 'Pozíció',
'Move Up' => 'Fel',
'Move Down' => 'Le',
'Duplicate to another project' => 'Másold egy másik projektbe',
'Duplicate' => 'Másolat',
'link' => 'link',
'Update this comment' => 'Hozzászólás frissítése',
'Comment updated successfully.' => 'Megjegyzés sikeresen frissítve.',
'Unable to update your comment.' => 'Megjegyzés frissítése nem sikerült.',
'Remove a comment' => 'Megjegyzés törlése',
'Comment removed successfully.' => 'Megjegyzés sikeresen törölve.',
'Unable to remove this comment.' => 'Megjegyzés törölése nem lehetséges.',
'Do you really want to remove this comment?' => 'Valóban törölni szeretné ezt a megjegyzést?',
'Only administrators or the creator of the comment can access to this page.' => 'Csak a rendszergazdák és a megjegyzés létrehozója férhet hozzá az oldalhoz.',
'Details' => 'Részletek',
'Current password for the user "%s"' => 'Felhasználó jelenlegi jelszava "%s"',
'The current password is required' => 'A jelenlegi jelszót meg kell adni',
'Wrong password' => 'Hibás jelszó',
'Reset all tokens' => 'Reseteld az összes tokent',
'All tokens have been regenerated.' => 'Minden token újra lett generálva.',
'Unknown' => 'Ismeretlen',
'Last logins' => 'Legutóbbi bejelentkezések',
'Login date' => 'Bejelentkezés dátuma',
'Authentication method' => 'Azonosítási módszer',
'IP address' => 'IP-cím',
'User agent' => 'User Agent',
'Persistent connections' => 'Tartós (perzisztens) kapcsolatok',
'No session.' => 'Nincs session.',
'Expiration date' => 'Lejárati dátum',
'Remember Me' => 'Emlékezz rám',
'Creation date' => 'Létrehozás dátuma',
'Filter by user' => 'Szűrés felhasználó szerint',
'Filter by due date' => 'Szűrés határidő szerint',
'Everybody' => 'Mindenki',
'Open' => 'Nyitott',
'Closed' => 'Lezárt',
'Search' => 'Keres',
'Nothing found.' => 'Semmit sem találtam.',
'Search in the project "%s"' => 'Keresés a projektben "%s"',
'Due date' => 'Határidő',
'Others formats accepted: %s and %s' => 'Egyéb érvényes formátumok: %s és %s',
'Description' => 'Leírás',
'%d comments' => '%d megjegyzés',
'%d comment' => '%d megjegyzés',
'Email address invalid' => 'Érvénytelen e-mail cím',
'Your Google Account is not linked anymore to your profile.' => 'Google Fiók már nincs a profilhoz kapcsolva.',
'Unable to unlink your Google Account.' => 'Leválasztás a Google fiókról nem lehetséges.',
'Google authentication failed' => 'Google azonosítás sikertelen',
'Unable to link your Google Account.' => 'Google profilhoz kapcsolás nem sikerült.',
'Your Google Account is linked to your profile successfully.' => 'Sikeresen összekapcsolva a Google fiókkal.',
'Email' => 'E-mail',
'Link my Google Account' => 'Kapcsold össze a Google fiókkal',
'Unlink my Google Account' => 'Válaszd le a Google fiókomat',
'Login with my Google Account' => 'Jelentkezzen be Google fiókkal',
'Project not found.' => 'A projekt nem található.',
'Task #%d' => 'Feladat #%d.',
'Task removed successfully.' => 'Feladat törlése sikerült.',
'Unable to remove this task.' => 'A feladatot nem lehet törölni.',
'Remove a task' => 'Feladat törlése',
'Do you really want to remove this task: "%s"?' => 'Valóban törölni akarja ezt a feladatot: "%s"?',
'Assign automatically a color based on a category' => 'Szín hozzárendelése automatikusan kategória alapján',
'Assign automatically a category based on a color' => 'Kategória hozzárendelése automatikusan szín alapján',
'Task creation or modification' => 'Feladat létrehozása vagy módosítása',
'Category' => 'Kategória',
'Category:' => 'Kategória:',
'Categories' => 'Kategóriák',
'Category not found.' => 'Kategória nem található.',
'Your category have been created successfully.' => 'Kategória sikeresen létrejött.',
'Unable to create your category.' => 'A kategória létrehozása nem lehetséges.',
'Your category have been updated successfully.' => 'Kategória sikeresen frissítve.',
'Unable to update your category.' => 'Kategória frissítése nem lehetséges.',
'Remove a category' => 'Kategória törlése',
'Category removed successfully.' => 'Kategória törlése megtörtént.',
'Unable to remove this category.' => 'A kategória törlése nem lehetséges.',
'Category modification for the project "%s"' => 'Kategória módosítása a projektben "%s"',
'Category Name' => 'Kategória neve',
'Categories for the project "%s"' => 'Projekt kategóriák "%s"',
'Add a new category' => 'Új kategória',
'Do you really want to remove this category: "%s"?' => 'Valóban törölni akarja ezt a kategóriát "%s"?',
'Filter by category' => 'Szűrés kategóriára',
'All categories' => 'Minden kategória',
'No category' => 'Nincs kategória',
'The name is required' => 'A név megadása kötelező',
'Remove a file' => 'Fájl törlése',
'Unable to remove this file.' => 'Fájl törlése nem lehetséges.',
'File removed successfully.' => 'A fájl törlése sikerült.',
'Attach a document' => 'Fájl csatolása',
'Do you really want to remove this file: "%s"?' => 'Valóban törölni akarja a fájlt: "%s"?',
'open' => 'nyitott',
'Attachments' => 'Mellékletek',
'Edit the task' => 'Feladat módosítása',
'Edit the description' => 'Leírás szerkesztése',
'Add a comment' => 'Új megjegyzés',
'Edit a comment' => 'Megjegyzés szerkesztése',
'Summary' => 'Összegzés',
'Time tracking' => 'Idő követés',
'Estimate:' => 'Becsült:',
'Spent:' => 'Eltöltött:',
'Do you really want to remove this sub-task?' => 'Valóban törölni akarja ezt a részfeladatot "%s"?',
'Remaining:' => 'Hátralévő:',
'hours' => 'óra',
'spent' => 'eltöltött',
'estimated' => 'becsült',
'Sub-Tasks' => 'részfeladatok',
'Add a sub-task' => 'Részfeladat létrehozása',
'Original estimate' => 'Eredeti időbecslés',
'Create another sub-task' => 'További részfeladat létrehozása',
'Time spent' => 'Eltöltött idő',
'Edit a sub-task' => 'Részfeladat szerkesztése',
'Remove a sub-task' => 'Részfeladat törlése',
'The time must be a numeric value' => 'Idő csak számérték lehet',
'Todo' => 'Teendő',
'In progress' => 'Folyamatban',
'Sub-task removed successfully.' => 'Részfeladat sikeresen törölve.',
'Unable to remove this sub-task.' => 'Részfeladat törlése nem lehetséges.',
'Sub-task updated successfully.' => 'Részfeladat sikeresen frissítve.',
'Unable to update your sub-task.' => 'Részfeladat frissítése nem lehetséges.',
'Unable to create your sub-task.' => 'Részfeladat létrehozása nem lehetséges.',
'Sub-task added successfully.' => 'Részfeladat sikeresen létrejött.',
'Maximum size: ' => 'Maximális méret:',
'Unable to upload the file.' => 'Fájl feltöltése nem lehetséges.',
'Display another project' => 'Másik projekt megjelenítése',
'Your GitHub account was successfully linked to your profile.' => 'GitHub fiók sikeresen csatolva a profilhoz.',
'Unable to link your GitHub Account.' => 'Nem lehet csatolni a GitHub fiókot.',
'GitHub authentication failed' => 'GitHub azonosítás sikertelen',
'Your GitHub account is no longer linked to your profile.' => 'GitHub fiók már nincs profilhoz kapcsolva.',
'Unable to unlink your GitHub Account.' => 'GitHub fiók leválasztása nem lehetséges.',
'Login with my GitHub Account' => 'Jelentkezzen be GitHub fiókkal',
'Link my GitHub Account' => 'GitHub fiók csatolása',
'Unlink my GitHub Account' => 'GitHub fiók leválasztása',
'Created by %s' => 'Készítette: %s',
'Last modified on %B %e, %Y at %k:%M %p' => 'Utolsó módosítás %Y.%m.%d %H:%M',
'Tasks Export' => 'Feladatok exportálása',
'Tasks exportation for "%s"' => 'Feladatok exportálása "%s" részére',
'Start Date' => 'Kezdés dátuma',
'End Date' => 'Befejezés dátuma',
'Execute' => 'Végrehajt',
'Task Id' => 'Feladat ID',
'Creator' => 'Készítette',
'Modification date' => 'Módosítás dátuma',
'Completion date' => 'Befejezés határideje',
'Webhook URL for task creation' => 'Webhook URL a feladat létrehozásakor',
'Webhook URL for task modification' => 'Webhook URL a feladatot módosításakor',
'Clone' => 'Másolat',
'Clone Project' => 'Projekt megkettőzése',
'Project cloned successfully.' => 'A projekt sikeresen megkettőzve.',
'Unable to clone this project.' => 'Projekt megkettőzése nem sikerült.',
'Email notifications' => 'E-mail értesítések',
'Enable email notifications' => 'Engedélyezze az e-mail értesítéseket',
'Task position:' => 'Feladat helye:',
'The task #%d have been opened.' => 'Feladat #%d megnyitva.',
'The task #%d have been closed.' => 'Feladat #%d lezárva.',
'Sub-task updated' => 'Részfeladat frissítve',
'Title:' => 'Cím',
'Status:' => 'Állapot',
'Assignee:' => 'Felelős:',
'Time tracking:' => 'Idő követés:',
'New sub-task' => 'Új részfeladat',
'New attachment added "%s"' => 'Új melléklet "%s" hozzáadva.',
'Comment updated' => 'Megjegyzés frissítve',
'New comment posted by %s' => 'Új megjegyzés %s',
'List of due tasks for the project "%s"' => 'Projekt esedékes feladatai "%s"',
'[%s][New attachment] %s (#%d)' => '[%s] [Új csatolmány] %s (#%d)',
'[%s][New comment] %s (#%d)' => '[%s] [Új hozzászólás] %s (#%d)',
'[%s][Comment updated] %s (#%d)' => '[%s] [Megjegyzés frissítve] %s (#%d)',
'[%s][New subtask] %s (#%d)' => '[%s] [Új részfeladat] %s (#%d)',
'[%s][Subtask updated] %s (#%d)' => '[%s] [Részfeladat frissítve] %s (#%d)',
'[%s][New task] %s (#%d)' => '[%s] [Új feladat] %s (#%d)',
'[%s][Task updated] %s (#%d)' => '[%s] [Feladat frissítve] %s (#%d)',
'[%s][Task closed] %s (#%d)' => '[%s] [Feladat lezárva]%s (#%d)',
'[%s][Task opened] %s (#%d)' => '[%s] [Feladat megnyitva] %s (#%d)',
'[%s][Due tasks]' => '[%s] [Esedékes feladatok]',
'[Kanboard] Notification' => '[Kanboard] értesítés',
'I want to receive notifications only for those projects:' => 'Csak ezekről a projektekről kérek értesítést:',
'view the task on Kanboard' => 'feladat megtekintése a Kanboardon',
'Public access' => 'Nyilvános hozzáférés',
'Category management' => 'Kategóriák kezelése',
'User management' => 'Felhasználók kezelése',
'Active tasks' => 'Aktív feladatok',
'Disable public access' => 'Nyilvános hozzáférés letiltása',
'Enable public access' => 'Nyilvános hozzáférés engedélyezése',
'Active projects' => 'Aktív projektek',
'Inactive projects' => 'Inaktív projektek',
'Public access disabled' => 'Nyilvános hozzáférés letiltva',
'Do you really want to disable this project: "%s"?' => 'Tényleg szeretné letiltani ezt a projektet: "%s"',
'Do you really want to duplicate this project: "%s"?' => 'Tényleg szeretné megkettőzni ezt a projektet: "%s"',
'Do you really want to enable this project: "%s"?' => 'Tényleg szeretné engedélyezni ezt a projektet: "%s"',
'Project activation' => 'Projekt aktiválás',
'Move the task to another project' => 'Feladatot mozgatása másik projektbe',
'Move to another project' => 'Másik projektbe',
'Do you really want to duplicate this task?' => 'Tényleg szeretné megkettőzni ezt a feladatot?',
'Duplicate a task' => 'Feladat megkettőzése',
'External accounts' => 'Külső fiókok',
'Account type' => 'Fiók típus',
'Local' => 'Helyi',
'Remote' => 'Távoli',
'Enabled' => 'Engedélyezve',
'Disabled' => 'Letiltva',
'Google account linked' => 'Google fiók összekapcsolva',
'Github account linked' => 'GitHub fiók összekapcsolva',
'Username:' => 'Felhasználónév',
'Name:' => 'Név',
'Email:' => 'E-mail',
'Default project:' => 'Alapértelmezett projekt:',
'Notifications:' => 'Értesítések:',
'Notifications' => 'Értesítések',
'Group:' => 'Csoport:',
'Regular user' => 'Default User',
'Account type:' => 'Fiók típus:',
'Edit profile' => 'Profil szerkesztése',
'Change password' => 'Jelszó módosítása',
'Password modification' => 'Jelszó módosítása',
'External authentications' => 'Külső azonosítás',
'Google Account' => 'Google fiók',
'Github Account' => 'Github fiók',
'Never connected.' => 'Sosem csatlakozva.',
'No account linked.' => 'Nincs csatlakoztatott fiók.',
'Account linked.' => 'Fiók csatlakoztatva.',
'No external authentication enabled.' => 'Külső azonosítás nincs engedélyezve.',
'Password modified successfully.' => 'Jelszó sikeresen módosítva.',
'Unable to change the password.' => 'Jelszó módosítás sikertelen.',
'Change category for the task "%s"' => 'Feladat kategória módosítása "%s"',
'Change category' => 'Kategória módosítása',
'%s updated the task %s' => '%s frissítette a feladatot %s',
'%s opened the task %s' => '%s megnyitott a feladatot %s',
'%s moved the task %s to the position #%d in the column "%s"' => '%s átmozgatta a feladatot %s #%d pozícióba a "%s" oszlopban',
'%s moved the task %s to the column "%s"' => '%s átmozgatta a feladatot %s "%s" oszlopba',
'%s created the task %s' => '%s létrehozta a feladatot %s',
'%s closed the task %s' => '%s lezárta a feladatot %s',
'%s created a subtask for the task %s' => '%s létrehozott egy részfeladat a feladathoz %s',
'%s updated a subtask for the task %s' => '%s frissített egy részfeladatot a feladathoz %s',
'Assigned to %s with an estimate of %s/%sh' => '%s-nek kiosztva %s/%s óra becsült idő mellett',
'Not assigned, estimate of %sh' => 'Nincs kiosztva, becsült idő: %s óra',
'%s updated a comment on the task %s' => '%s frissítette a megjegyzését a feladatban %s',
'%s commented the task %s' => '%s megjegyzést fűzött a feladathoz %s',
'%s\'s activity' => '%s tevékenysége',
'No activity.' => 'Nincs tevékenység.',
'RSS feed' => 'RSS feed',
'%s updated a comment on the task #%d' => '%s frissített egy megjegyzést a feladatban #%d',
'%s commented on the task #%d' => '%s megjegyzést tett a feladathoz #%d',
'%s updated a subtask for the task #%d' => '%s frissített egy részfeladatot a feladatban #%d',
'%s created a subtask for the task #%d' => '%s létrehozott egy részfeladatot a feladatban #%d',
'%s updated the task #%d' => '%s frissítette a feladatot #%d',
'%s created the task #%d' => '%s létrehozta a feladatot #%d',
'%s closed the task #%d' => '%s lezárta a feladatot #%d',
'%s open the task #%d' => '%s megnyitotta a feladatot #%d',
'%s moved the task #%d to the column "%s"' => '%s átmozgatta a feladatot #%d a "%s" oszlopba',
'%s moved the task #%d to the position %d in the column "%s"' => '%s átmozgatta a feladatot #%d a %d pozícióba a "%s" oszlopban',
'Activity' => 'Tevékenység',
'Default values are "%s"' => 'Az alapértelmezett értékek "%s"',
'Default columns for new projects (Comma-separated)' => 'Alapértelmezett oszlopok az új projektekben (vesszővel elválasztva)',
'Task assignee change' => 'Felelős módosítása',
'%s change the assignee of the task #%d to %s' => '%s a felelőst módosította #%d %s',
'%s changed the assignee of the task %s to %s' => '%s a felelőst %s módosította: %s',
'[%s][Column Change] %s (#%d)' => '[%s] [Oszlop módosítás] %s (#%d)',
'[%s][Position Change] %s (#%d)' => '[%s] [Pozíció módosítás] %s (#%d)',
'[%s][Assignee Change] %s (#%d)' => '[%s] [Felelős módosítás] %s (#%d)',
'New password for the user "%s"' => 'Felhasználó új jelszava "%s"',
'Choose an event' => 'Válasszon eseményt',
'Github commit received' => 'GitHub commit érkezett',
'Github issue opened' => 'GitHub issue nyílt',
'Github issue closed' => 'GitHub issue zárt',
'Github issue reopened' => 'GitHub issue újranyitva',
'Github issue assignee change' => 'GitHub issue felelős változás',
'Github issue label change' => 'GitHub issue címke változás',
'Create a task from an external provider' => 'Feladat létrehozása külsős számára',
'Change the assignee based on an external username' => 'Felelős módosítása külső felhasználónév alapján',
'Change the category based on an external label' => 'Kategória módosítása külső címke alapján',
'Reference' => 'Hivatkozás',
'Reference: %s' => 'Hivatkozás: %s',
'Label' => 'Címke',
'Database' => 'Adatbázis',
'About' => 'Kanboard információ',
'Database driver:' => 'Adatbázis driver:',
'Board settings' => 'Tábla beállítások',
'URL and token' => 'URL és tokenek',
'Webhook settings' => 'Webhook beállítások',
'URL for task creation:' => 'Feladat létrehozás URL:',
'Reset token' => 'Reset token',
'API endpoint:' => 'API endpoint:',
'Refresh interval for private board' => 'Privát táblák frissítési intervalluma',
'Refresh interval for public board' => 'Nyilvános táblák frissítési intervalluma',
'Task highlight period' => 'Feladat kiemelés időtartama',
'Period (in second) to consider a task was modified recently (0 to disable, 2 days by default)' => 'Mennyi ideig tekintendő egy feladat "mostanában" módosítottnak (másodpercben) (0: funkció letiltva, alapértelmezés szerint 2 nap)',
'Frequency in second (60 seconds by default)' => 'Infó másodpercben (alapértelmezett 60 másodperc)',
'Frequency in second (0 to disable this feature, 10 seconds by default)' => 'Infó másodpercben (0 funkció letiltva, alapértelmezés szerint 10 másodperc)',
'Application URL' => 'Alkalmazás URL',
'Example: http://example.kanboard.net/ (used by email notifications)' => 'Példa: http://example.kanboard.net/ (e-mail értesítőben)',
'Token regenerated.' => 'Token újragenerálva.',
'Date format' => 'Dátum formátum',
'ISO format is always accepted, example: "%s" and "%s"' => 'ISO formátum mindig elfogadott, pl: "%s" és "%s"',
'New private project' => 'Új privát projekt',
'This project is private' => 'Ez egy privát projekt',
'Type here to create a new sub-task' => 'Ide írva létrehozhat egy új részfeladatot',
'Add' => 'Hozzáad',
'Estimated time: %s hours' => 'Becsült idő: %s óra',
'Time spent: %s hours' => 'Eltöltött idő: %s óra',
'Started on %B %e, %Y' => 'Elkezdve: %Y.%m.%d',
'Start date' => 'Kezdés dátuma',
'Time estimated' => 'Becsült időtartam',
'There is nothing assigned to you.' => 'Nincs kiosztott feladat.',
'My tasks' => 'Feladataim',
'Activity stream' => 'Legutóbbi tevékenységek',
'Dashboard' => 'Műszerfal',
'Confirmation' => 'Megerősítés',
'Allow everybody to access to this project' => 'Engedélyezze a projekt elérését mindenkinek',
'Everybody have access to this project.' => 'Mindenki elérheti a projektet',
'Webhooks' => 'Webhook',
'API' => 'API',
'Integration' => 'Integráció',
'Github webhooks' => 'Github webhooks',
'Help on Github webhooks' => 'Github Webhook súgó',
'Create a comment from an external provider' => 'Megjegyzés létrehozása külső felhasználótól',
'Github issue comment created' => 'Github issue megjegyzés létrehozva',
'Configure' => 'Konfigurál',
'Project management' => 'Projekt menedzsment',
'My projects' => 'Projektjeim',
'Columns' => 'Oszlopok',
'Task' => 'Feladat',
'Your are not member of any project.' => 'Ön nem tagja projektnek.',
'Percentage' => 'Százalék',
'Number of tasks' => 'A feladatok száma',
'Task distribution' => 'Feladatelosztás',
'Reportings' => 'Jelentések',
'Task repartition for "%s"' => 'Feladat újraosztása "%s" számára',
'Analytics' => 'Analitika',
'Subtask' => 'Részfeladat',
'My subtasks' => 'Részfeladataim',
'User repartition' => 'Felhasználó újrafelosztás',
'User repartition for "%s"' => 'Felhasználó újrafelosztás "%s" számára',
'Clone this project' => 'Projekt megkettőzése',
'Column removed successfully.' => 'Oszlop sikeresen eltávolítva.',
'Edit Project' => 'Projekt szerkesztése',
'Github Issue' => 'Github issue',
'Not enough data to show the graph.' => 'Nincs elég adat a grafikonhoz.',
'Previous' => 'Előző',
'The id must be an integer' => 'Az ID csak egész szám lehet',
'The project id must be an integer' => 'A projekt ID csak egész szám lehet',
'The status must be an integer' => 'Az állapot csak egész szám lehet',
'The subtask id is required' => 'A részfeladat ID-t meg kell adni',
'The subtask id must be an integer' => 'A részfeladat ID csak egész szám lehet',
'The task id is required' => 'A feladat ID-t meg kell adni',
'The task id must be an integer' => 'A feladat ID csak egész szám lehet',
'The user id must be an integer' => 'A felhasználói ID csak egész szám lehet',
'This value is required' => 'Ez a mező kötelező',
'This value must be numeric' => 'Ez a mező csak szám lehet',
'Unable to create this task.' => 'A feladat nem hozható létre,',
'Cumulative flow diagram' => 'Kumulatív Flow Diagram',
'Cumulative flow diagram for "%s"' => 'Kumulatív Flow Diagram "%s" számára',
'Daily project summary' => 'Napi projektösszefoglaló',
'Daily project summary export' => 'Napi projektösszefoglaló exportálása',
'Daily project summary export for "%s"' => 'Napi projektösszefoglaló exportálása "%s" számára',
'Exports' => 'Exportálások',
'This export contains the number of tasks per column grouped per day.' => 'Ez az export tartalmazza a feladatok számát oszloponként összesítve, napokra lebontva.',
'Nothing to preview...' => 'Nincs semmi az előnézetben ...',
'Preview' => 'Előnézet',
'Write' => 'Írd',
// 'Active swimlanes' => '',
// 'Add a new swimlane' => '',
// 'Change default swimlane' => '',
// 'Default swimlane' => '',
// 'Do you really want to remove this swimlane: "%s"?' => '',
// 'Inactive swimlanes' => '',
// 'Set project manager' => '',
// 'Set project member' => '',
// 'Remove a swimlane' => '',
// 'Rename' => '',
// 'Show default swimlane' => '',
// 'Swimlane modification for the project "%s"' => '',
// 'Swimlane not found.' => '',
// 'Swimlane removed successfully.' => '',
// 'Swimlanes' => '',
// 'Swimlane updated successfully.' => '',
// 'The default swimlane have been updated successfully.' => '',
// 'Unable to create your swimlane.' => '',
// 'Unable to remove this swimlane.' => '',
// 'Unable to update this swimlane.' => '',
// 'Your swimlane have been created successfully.' => '',
// 'Example: "Bug, Feature Request, Improvement"' => '',
// 'Default categories for new projects (Comma-separated)' => '',
// 'Gitlab commit received' => '',
// 'Gitlab issue opened' => '',
// 'Gitlab issue closed' => '',
// 'Gitlab webhooks' => '',
// 'Help on Gitlab webhooks' => '',
// 'Integrations' => '',
// 'Integration with third-party services' => '',
// 'Role for this project' => '',
// 'Project manager' => '',
// 'Project member' => '',
// 'A project manager can change the settings of the project and have more privileges than a standard user.' => '',
// 'Gitlab Issue' => '',
// 'Subtask Id' => '',
// 'Subtasks' => '',
// 'Subtasks Export' => '',
// 'Subtasks exportation for "%s"' => '',
// 'Task Title' => '',
// 'Untitled' => '',
// 'Application default' => '',
// 'Language:' => '',
// 'Timezone:' => '',
// 'Next' => '',
);

View file

@ -182,7 +182,7 @@ return array(
'Change assignee' => 'Cambiare la persona assegnata', 'Change assignee' => 'Cambiare la persona assegnata',
'Change assignee for the task "%s"' => 'Cambiare la persona assegnata per il compito « %s »', 'Change assignee for the task "%s"' => 'Cambiare la persona assegnata per il compito « %s »',
'Timezone' => 'Fuso orario', 'Timezone' => 'Fuso orario',
'Sorry, I didn\'t found this information in my database!' => 'Mi dispiace, non ho trovato questa informazione sulla base dati!', 'Sorry, I didn\'t find this information in my database!' => 'Mi dispiace, non ho trovato questa informazione sulla base dati!',
'Page not found' => 'Pagina non trovata', 'Page not found' => 'Pagina non trovata',
// 'Complexity' => '', // 'Complexity' => '',
'limit' => 'limite', 'limit' => 'limite',
@ -194,7 +194,7 @@ return array(
'Allow this user' => 'Permettere a questo utente', 'Allow this user' => 'Permettere a questo utente',
'Only those users have access to this project:' => 'Solo questi utenti hanno accesso a questo progetto:', 'Only those users have access to this project:' => 'Solo questi utenti hanno accesso a questo progetto:',
'Don\'t forget that administrators have access to everything.' => 'Non dimenticare che gli amministratori hanno accesso a tutto.', 'Don\'t forget that administrators have access to everything.' => 'Non dimenticare che gli amministratori hanno accesso a tutto.',
'revoke' => 'revocare', 'Revoke' => 'Revocare',
'List of authorized users' => 'Lista di utenti autorizzati', 'List of authorized users' => 'Lista di utenti autorizzati',
'User' => 'Utente', 'User' => 'Utente',
// 'Nobody have access to this project.' => '', // 'Nobody have access to this project.' => '',
@ -213,6 +213,7 @@ return array(
'Invalid date' => 'Data sbagliata', 'Invalid date' => 'Data sbagliata',
// 'Must be done before %B %e, %Y' => '', // 'Must be done before %B %e, %Y' => '',
// '%B %e, %Y' => '', // '%B %e, %Y' => '',
// '%b %e, %Y' => '',
'Automatic actions' => 'Azioni automatiche', 'Automatic actions' => 'Azioni automatiche',
'Your automatic action have been created successfully.' => 'l\'azione automatica è stata creata correttamente.', 'Your automatic action have been created successfully.' => 'l\'azione automatica è stata creata correttamente.',
'Unable to create your automatic action.' => 'Non si può creare quest\'azione automatica.', 'Unable to create your automatic action.' => 'Non si può creare quest\'azione automatica.',
@ -468,18 +469,18 @@ return array(
// 'Unable to change the password.' => '', // 'Unable to change the password.' => '',
// 'Change category for the task "%s"' => '', // 'Change category for the task "%s"' => '',
// 'Change category' => '', // 'Change category' => '',
// '%s updated the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '', // '%s updated the task %s' => '',
// '%s open the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '', // '%s opened the task %s' => '',
// '%s moved the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to the position #%d in the column "%s"' => '', // '%s moved the task %s to the position #%d in the column "%s"' => '',
// '%s moved the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to the column "%s"' => '', // '%s moved the task %s to the column "%s"' => '',
// '%s created the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '', // '%s created the task %s' => '',
// '%s closed the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '', // '%s closed the task %s' => '',
// '%s created a subtask for the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '', // '%s created a subtask for the task %s' => '',
// '%s updated a subtask for the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '', // '%s updated a subtask for the task %s' => '',
// 'Assigned to %s with an estimate of %s/%sh' => '', // 'Assigned to %s with an estimate of %s/%sh' => '',
// 'Not assigned, estimate of %sh' => '', // 'Not assigned, estimate of %sh' => '',
// '%s updated a comment on the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '', // '%s updated a comment on the task %s' => '',
// '%s commented the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '', // '%s commented the task %s' => '',
// '%s\'s activity' => '', // '%s\'s activity' => '',
// 'No activity.' => '', // 'No activity.' => '',
// 'RSS feed' => '', // 'RSS feed' => '',
@ -498,7 +499,7 @@ return array(
// 'Default columns for new projects (Comma-separated)' => '', // 'Default columns for new projects (Comma-separated)' => '',
// 'Task assignee change' => '', // 'Task assignee change' => '',
// '%s change the assignee of the task #%d to %s' => '', // '%s change the assignee of the task #%d to %s' => '',
// '%s change the assignee of the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to %s' => '', // '%s changed the assignee of the task %s to %s' => '',
// '[%s][Column Change] %s (#%d)' => '', // '[%s][Column Change] %s (#%d)' => '',
// '[%s][Position Change] %s (#%d)' => '', // '[%s][Position Change] %s (#%d)' => '',
// '[%s][Assignee Change] %s (#%d)' => '', // '[%s][Assignee Change] %s (#%d)' => '',
@ -555,8 +556,8 @@ return array(
// 'Webhooks' => '', // 'Webhooks' => '',
// 'API' => '', // 'API' => '',
// 'Integration' => '', // 'Integration' => '',
// 'Github webhook' => '', // 'Github webhooks' => '',
// 'Help on Github webhook' => '', // 'Help on Github webhooks' => '',
// 'Create a comment from an external provider' => '', // 'Create a comment from an external provider' => '',
// 'Github issue comment created' => '', // 'Github issue comment created' => '',
// 'Configure' => '', // 'Configure' => '',
@ -602,4 +603,49 @@ return array(
// 'Nothing to preview...' => '', // 'Nothing to preview...' => '',
// 'Preview' => '', // 'Preview' => '',
// 'Write' => '', // 'Write' => '',
// 'Active swimlanes' => '',
// 'Add a new swimlane' => '',
// 'Change default swimlane' => '',
// 'Default swimlane' => '',
// 'Do you really want to remove this swimlane: "%s"?' => '',
// 'Inactive swimlanes' => '',
// 'Set project manager' => '',
// 'Set project member' => '',
// 'Remove a swimlane' => '',
// 'Rename' => '',
// 'Show default swimlane' => '',
// 'Swimlane modification for the project "%s"' => '',
// 'Swimlane not found.' => '',
// 'Swimlane removed successfully.' => '',
// 'Swimlanes' => '',
// 'Swimlane updated successfully.' => '',
// 'The default swimlane have been updated successfully.' => '',
// 'Unable to create your swimlane.' => '',
// 'Unable to remove this swimlane.' => '',
// 'Unable to update this swimlane.' => '',
// 'Your swimlane have been created successfully.' => '',
// 'Example: "Bug, Feature Request, Improvement"' => '',
// 'Default categories for new projects (Comma-separated)' => '',
// 'Gitlab commit received' => '',
// 'Gitlab issue opened' => '',
// 'Gitlab issue closed' => '',
// 'Gitlab webhooks' => '',
// 'Help on Gitlab webhooks' => '',
// 'Integrations' => '',
// 'Integration with third-party services' => '',
// 'Role for this project' => '',
// 'Project manager' => '',
// 'Project member' => '',
// 'A project manager can change the settings of the project and have more privileges than a standard user.' => '',
// 'Gitlab Issue' => '',
// 'Subtask Id' => '',
// 'Subtasks' => '',
// 'Subtasks Export' => '',
// 'Subtasks exportation for "%s"' => '',
// 'Task Title' => '',
// 'Untitled' => '',
// 'Application default' => '',
// 'Language:' => '',
// 'Timezone:' => '',
// 'Next' => '',
); );

View file

@ -182,7 +182,7 @@ return array(
'Change assignee' => '担当を変更する', 'Change assignee' => '担当を変更する',
'Change assignee for the task "%s"' => 'タスク「%s」の担当を変更する', 'Change assignee for the task "%s"' => 'タスク「%s」の担当を変更する',
'Timezone' => 'タイムゾーン', 'Timezone' => 'タイムゾーン',
'Sorry, I didn\'t found this information in my database!' => 'データベース上で情報が見つかりませんでした!', 'Sorry, I didn\'t find this information in my database!' => 'データベース上で情報が見つかりませんでした!',
'Page not found' => 'ページが見つかりません', 'Page not found' => 'ページが見つかりません',
'Complexity' => '複雑さ', 'Complexity' => '複雑さ',
'limit' => '制限', 'limit' => '制限',
@ -194,7 +194,7 @@ return array(
'Allow this user' => 'このユーザを許可する', 'Allow this user' => 'このユーザを許可する',
'Only those users have access to this project:' => 'これらのユーザのみがプロジェクトにアクセスできます:', 'Only those users have access to this project:' => 'これらのユーザのみがプロジェクトにアクセスできます:',
'Don\'t forget that administrators have access to everything.' => '管理者には全ての権限が与えられます。', 'Don\'t forget that administrators have access to everything.' => '管理者には全ての権限が与えられます。',
'revoke' => '許可を取り下げる', 'Revoke' => '許可を取り下げる',
'List of authorized users' => '許可されたユーザ', 'List of authorized users' => '許可されたユーザ',
'User' => 'ユーザ', 'User' => 'ユーザ',
'Nobody have access to this project.' => 'だれもプロジェクトにアクセスできません。', 'Nobody have access to this project.' => 'だれもプロジェクトにアクセスできません。',
@ -213,6 +213,7 @@ return array(
'Invalid date' => '日付が無効です', 'Invalid date' => '日付が無効です',
'Must be done before %B %e, %Y' => '%Y/%m/%d までに完了', 'Must be done before %B %e, %Y' => '%Y/%m/%d までに完了',
'%B %e, %Y' => '%d %B %Y', '%B %e, %Y' => '%d %B %Y',
// '%b %e, %Y' => '',
'Automatic actions' => '自動アクションを管理する', 'Automatic actions' => '自動アクションを管理する',
'Your automatic action have been created successfully.' => '自動アクションを作成しました。', 'Your automatic action have been created successfully.' => '自動アクションを作成しました。',
'Unable to create your automatic action.' => '自動アクションの作成に失敗しました。', 'Unable to create your automatic action.' => '自動アクションの作成に失敗しました。',
@ -468,18 +469,18 @@ return array(
'Unable to change the password.' => 'パスワードが変更できませんでした。', 'Unable to change the password.' => 'パスワードが変更できませんでした。',
'Change category for the task "%s"' => 'タスク「%s」のカテゴリの変更', 'Change category for the task "%s"' => 'タスク「%s」のカテゴリの変更',
'Change category' => 'カテゴリの変更', 'Change category' => 'カテゴリの変更',
'%s updated the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s がタスク <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> をアップデートしました', '%s updated the task %s' => '%s がタスク %s をアップデートしました',
'%s open the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s がタスク <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> をオープンしました', '%s opened the task %s' => '%s がタスク %s をオープンしました',
'%s moved the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to the position #%d in the column "%s"' => '%s がタスク <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> をポジション #%d カラム %s に移動しました', '%s moved the task %s to the position #%d in the column "%s"' => '%s がタスク %s をポジション #%d カラム %s に移動しました',
'%s moved the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to the column "%s"' => '%s がタスク <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> をカラム「%s」に移動しました', '%s moved the task %s to the column "%s"' => '%s がタスク %s をカラム「%s」に移動しました',
'%s created the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s がタスク <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> を作成しました', '%s created the task %s' => '%s がタスク %s を作成しました',
'%s closed the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s がタスク <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> をクローズしました', '%s closed the task %s' => '%s がタスク %s をクローズしました',
'%s created a subtask for the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s がタスク <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> のサブタスクを追加しました', '%s created a subtask for the task %s' => '%s がタスク %s のサブタスクを追加しました',
'%s updated a subtask for the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s がタスク <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> のサブタスクを更新しました', '%s updated a subtask for the task %s' => '%s がタスク %s のサブタスクを更新しました',
'Assigned to %s with an estimate of %s/%sh' => '担当者 %s に予想 %s/%sh に変更されました', 'Assigned to %s with an estimate of %s/%sh' => '担当者 %s に予想 %s/%sh に変更されました',
'Not assigned, estimate of %sh' => '担当者無しで予想 %sh に変更されました', 'Not assigned, estimate of %sh' => '担当者無しで予想 %sh に変更されました',
'%s updated a comment on the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s がタスク <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> のコメントを更新しました', '%s updated a comment on the task %s' => '%s がタスク %s のコメントを更新しました',
'%s commented the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s がタスク <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> にコメントしました', '%s commented the task %s' => '%s がタスク %s にコメントしました',
'%s\'s activity' => '%s のアクティビティ', '%s\'s activity' => '%s のアクティビティ',
'No activity.' => 'アクティビティなし。', 'No activity.' => 'アクティビティなし。',
'RSS feed' => 'RSS フィード', 'RSS feed' => 'RSS フィード',
@ -498,7 +499,7 @@ return array(
'Default columns for new projects (Comma-separated)' => '新規プロジェクトのデフォルトカラム (コンマで区切って入力)', 'Default columns for new projects (Comma-separated)' => '新規プロジェクトのデフォルトカラム (コンマで区切って入力)',
'Task assignee change' => '担当者の変更', 'Task assignee change' => '担当者の変更',
'%s change the assignee of the task #%d to %s' => '%s がタスク #%d の担当を %s に変更しました', '%s change the assignee of the task #%d to %s' => '%s がタスク #%d の担当を %s に変更しました',
'%s change the assignee of the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to %s' => '%s がタスク <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> の担当を %s に変更しました', '%s changed the assignee of the task %s to %s' => '%s がタスク %s の担当を %s に変更しました',
'[%s][Column Change] %s (#%d)' => '[%s][カラムの変更] %s (#%d)', '[%s][Column Change] %s (#%d)' => '[%s][カラムの変更] %s (#%d)',
'[%s][Position Change] %s (#%d)' => '[%s][位置の変更] %s (#%d)', '[%s][Position Change] %s (#%d)' => '[%s][位置の変更] %s (#%d)',
'[%s][Assignee Change] %s (#%d)' => '[%s][担当者変更] %s (#%d)', '[%s][Assignee Change] %s (#%d)' => '[%s][担当者変更] %s (#%d)',
@ -555,8 +556,8 @@ return array(
// 'Webhooks' => '', // 'Webhooks' => '',
// 'API' => '', // 'API' => '',
// 'Integration' => '', // 'Integration' => '',
// 'Github webhook' => '', // 'Github webhooks' => '',
// 'Help on Github webhook' => '', // 'Help on Github webhooks' => '',
// 'Create a comment from an external provider' => '', // 'Create a comment from an external provider' => '',
// 'Github issue comment created' => '', // 'Github issue comment created' => '',
// 'Configure' => '', // 'Configure' => '',
@ -602,4 +603,49 @@ return array(
// 'Nothing to preview...' => '', // 'Nothing to preview...' => '',
// 'Preview' => '', // 'Preview' => '',
// 'Write' => '', // 'Write' => '',
// 'Active swimlanes' => '',
// 'Add a new swimlane' => '',
// 'Change default swimlane' => '',
// 'Default swimlane' => '',
// 'Do you really want to remove this swimlane: "%s"?' => '',
// 'Inactive swimlanes' => '',
// 'Set project manager' => '',
// 'Set project member' => '',
// 'Remove a swimlane' => '',
// 'Rename' => '',
// 'Show default swimlane' => '',
// 'Swimlane modification for the project "%s"' => '',
// 'Swimlane not found.' => '',
// 'Swimlane removed successfully.' => '',
// 'Swimlanes' => '',
// 'Swimlane updated successfully.' => '',
// 'The default swimlane have been updated successfully.' => '',
// 'Unable to create your swimlane.' => '',
// 'Unable to remove this swimlane.' => '',
// 'Unable to update this swimlane.' => '',
// 'Your swimlane have been created successfully.' => '',
// 'Example: "Bug, Feature Request, Improvement"' => '',
// 'Default categories for new projects (Comma-separated)' => '',
// 'Gitlab commit received' => '',
// 'Gitlab issue opened' => '',
// 'Gitlab issue closed' => '',
// 'Gitlab webhooks' => '',
// 'Help on Gitlab webhooks' => '',
// 'Integrations' => '',
// 'Integration with third-party services' => '',
// 'Role for this project' => '',
// 'Project manager' => '',
// 'Project member' => '',
// 'A project manager can change the settings of the project and have more privileges than a standard user.' => '',
// 'Gitlab Issue' => '',
// 'Subtask Id' => '',
// 'Subtasks' => '',
// 'Subtasks Export' => '',
// 'Subtasks exportation for "%s"' => '',
// 'Task Title' => '',
// 'Untitled' => '',
// 'Application default' => '',
// 'Language:' => '',
// 'Timezone:' => '',
// 'Next' => '',
); );

View file

@ -182,7 +182,7 @@ return array(
'Change assignee' => 'Zmień odpowiedzialną osobę', 'Change assignee' => 'Zmień odpowiedzialną osobę',
'Change assignee for the task "%s"' => 'Zmień odpowiedzialną osobę dla zadania "%s"', 'Change assignee for the task "%s"' => 'Zmień odpowiedzialną osobę dla zadania "%s"',
'Timezone' => 'Strefa czasowa', 'Timezone' => 'Strefa czasowa',
'Sorry, I didn\'t found this information in my database!' => 'Niestety nie znaleziono tej informacji w bazie danych', 'Sorry, I didn\'t find this information in my database!' => 'Niestety nie znaleziono tej informacji w bazie danych',
'Page not found' => 'Strona nie istnieje', 'Page not found' => 'Strona nie istnieje',
'Complexity' => 'Poziom trudności', 'Complexity' => 'Poziom trudności',
'limit' => 'limit', 'limit' => 'limit',
@ -194,7 +194,7 @@ return array(
'Allow this user' => 'Dodaj użytkownika', 'Allow this user' => 'Dodaj użytkownika',
'Only those users have access to this project:' => 'Użytkownicy mający dostęp:', 'Only those users have access to this project:' => 'Użytkownicy mający dostęp:',
'Don\'t forget that administrators have access to everything.' => 'Pamiętaj: Administratorzy mają zawsze dostęp do wszystkiego!', 'Don\'t forget that administrators have access to everything.' => 'Pamiętaj: Administratorzy mają zawsze dostęp do wszystkiego!',
'revoke' => 'odbierz dostęp', 'Revoke' => 'Odbierz dostęp',
'List of authorized users' => 'Lista użytkowników mających dostęp', 'List of authorized users' => 'Lista użytkowników mających dostęp',
'User' => 'Użytkownik', 'User' => 'Użytkownik',
// 'Nobody have access to this project.' => '', // 'Nobody have access to this project.' => '',
@ -213,6 +213,7 @@ return array(
'Invalid date' => 'Błędna data', 'Invalid date' => 'Błędna data',
'Must be done before %B %e, %Y' => 'Termin do %e %B %Y', 'Must be done before %B %e, %Y' => 'Termin do %e %B %Y',
'%B %e, %Y' => '%e %B %Y', '%B %e, %Y' => '%e %B %Y',
// '%b %e, %Y' => '',
'Automatic actions' => 'Akcje automatyczne', 'Automatic actions' => 'Akcje automatyczne',
'Your automatic action have been created successfully.' => 'Twoja akcja została dodana', 'Your automatic action have been created successfully.' => 'Twoja akcja została dodana',
'Unable to create your automatic action.' => 'Nie udało się utworzyć akcji', 'Unable to create your automatic action.' => 'Nie udało się utworzyć akcji',
@ -468,18 +469,18 @@ return array(
// 'Unable to change the password.' => '', // 'Unable to change the password.' => '',
// 'Change category for the task "%s"' => '', // 'Change category for the task "%s"' => '',
// 'Change category' => '', // 'Change category' => '',
// '%s updated the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '', // '%s updated the task %s' => '',
// '%s open the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '', // '%s opened the task %s' => '',
// '%s moved the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to the position #%d in the column "%s"' => '', // '%s moved the task %s to the position #%d in the column "%s"' => '',
// '%s moved the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to the column "%s"' => '', // '%s moved the task %s to the column "%s"' => '',
// '%s created the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '', // '%s created the task %s' => '',
// '%s closed the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '', // '%s closed the task %s' => '',
// '%s created a subtask for the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '', // '%s created a subtask for the task %s' => '',
// '%s updated a subtask for the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '', // '%s updated a subtask for the task %s' => '',
// 'Assigned to %s with an estimate of %s/%sh' => '', // 'Assigned to %s with an estimate of %s/%sh' => '',
// 'Not assigned, estimate of %sh' => '', // 'Not assigned, estimate of %sh' => '',
// '%s updated a comment on the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '', // '%s updated a comment on the task %s' => '',
// '%s commented the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '', // '%s commented the task %s' => '',
// '%s\'s activity' => '', // '%s\'s activity' => '',
// 'No activity.' => '', // 'No activity.' => '',
// 'RSS feed' => '', // 'RSS feed' => '',
@ -498,7 +499,7 @@ return array(
// 'Default columns for new projects (Comma-separated)' => '', // 'Default columns for new projects (Comma-separated)' => '',
// 'Task assignee change' => '', // 'Task assignee change' => '',
// '%s change the assignee of the task #%d to %s' => '', // '%s change the assignee of the task #%d to %s' => '',
// '%s change the assignee of the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to %s' => '', // '%s changed the assignee of the task %s to %s' => '',
// '[%s][Column Change] %s (#%d)' => '', // '[%s][Column Change] %s (#%d)' => '',
// '[%s][Position Change] %s (#%d)' => '', // '[%s][Position Change] %s (#%d)' => '',
// '[%s][Assignee Change] %s (#%d)' => '', // '[%s][Assignee Change] %s (#%d)' => '',
@ -555,8 +556,8 @@ return array(
// 'Webhooks' => '', // 'Webhooks' => '',
// 'API' => '', // 'API' => '',
// 'Integration' => '', // 'Integration' => '',
// 'Github webhook' => '', // 'Github webhooks' => '',
// 'Help on Github webhook' => '', // 'Help on Github webhooks' => '',
// 'Create a comment from an external provider' => '', // 'Create a comment from an external provider' => '',
// 'Github issue comment created' => '', // 'Github issue comment created' => '',
// 'Configure' => '', // 'Configure' => '',
@ -602,4 +603,49 @@ return array(
// 'Nothing to preview...' => '', // 'Nothing to preview...' => '',
// 'Preview' => '', // 'Preview' => '',
// 'Write' => '', // 'Write' => '',
// 'Active swimlanes' => '',
// 'Add a new swimlane' => '',
// 'Change default swimlane' => '',
// 'Default swimlane' => '',
// 'Do you really want to remove this swimlane: "%s"?' => '',
// 'Inactive swimlanes' => '',
// 'Set project manager' => '',
// 'Set project member' => '',
// 'Remove a swimlane' => '',
// 'Rename' => '',
// 'Show default swimlane' => '',
// 'Swimlane modification for the project "%s"' => '',
// 'Swimlane not found.' => '',
// 'Swimlane removed successfully.' => '',
// 'Swimlanes' => '',
// 'Swimlane updated successfully.' => '',
// 'The default swimlane have been updated successfully.' => '',
// 'Unable to create your swimlane.' => '',
// 'Unable to remove this swimlane.' => '',
// 'Unable to update this swimlane.' => '',
// 'Your swimlane have been created successfully.' => '',
// 'Example: "Bug, Feature Request, Improvement"' => '',
// 'Default categories for new projects (Comma-separated)' => '',
// 'Gitlab commit received' => '',
// 'Gitlab issue opened' => '',
// 'Gitlab issue closed' => '',
// 'Gitlab webhooks' => '',
// 'Help on Gitlab webhooks' => '',
// 'Integrations' => '',
// 'Integration with third-party services' => '',
// 'Role for this project' => '',
// 'Project manager' => '',
// 'Project member' => '',
// 'A project manager can change the settings of the project and have more privileges than a standard user.' => '',
// 'Gitlab Issue' => '',
// 'Subtask Id' => '',
// 'Subtasks' => '',
// 'Subtasks Export' => '',
// 'Subtasks exportation for "%s"' => '',
// 'Task Title' => '',
// 'Untitled' => '',
// 'Application default' => '',
// 'Language:' => '',
// 'Timezone:' => '',
// 'Next' => '',
); );

View file

@ -4,8 +4,8 @@ return array(
'None' => 'Nenhum', 'None' => 'Nenhum',
'edit' => 'editar', 'edit' => 'editar',
'Edit' => 'Editar', 'Edit' => 'Editar',
'remove' => 'apagar', 'remove' => 'remover',
'Remove' => 'Apagar', 'Remove' => 'Remover',
'Update' => 'Atualizar', 'Update' => 'Atualizar',
'Yes' => 'Sim', 'Yes' => 'Sim',
'No' => 'Não', 'No' => 'Não',
@ -14,175 +14,175 @@ return array(
'Yellow' => 'Amarelo', 'Yellow' => 'Amarelo',
'Blue' => 'Azul', 'Blue' => 'Azul',
'Green' => 'Verde', 'Green' => 'Verde',
'Purple' => 'Violeta', 'Purple' => 'Roxo',
'Red' => 'Vermelho', 'Red' => 'Vermelho',
'Orange' => 'Laranja', 'Orange' => 'Laranja',
'Grey' => 'Cinza', 'Grey' => 'Cinza',
'Save' => 'Salvar', 'Save' => 'Salvar',
'Login' => 'Login', 'Login' => 'Login',
'Official website:' => 'Site web oficial :', 'Official website:' => 'Site oficial:',
'Unassigned' => 'Não Atribuída', 'Unassigned' => 'Não Atribuída',
'View this task' => 'Ver esta tarefa', 'View this task' => 'Ver esta tarefa',
'Remove user' => 'Remover usuário', 'Remove user' => 'Remover usuário',
'Do you really want to remove this user: "%s"?' => 'Quer realmente remover este usuário: "%s"?', 'Do you really want to remove this user: "%s"?' => 'Você realmente deseja remover este usuário: "%s"?',
'New user' => 'Novo usuário', 'New user' => 'Novo usuário',
'All users' => 'Todos os usuários', 'All users' => 'Todos os usuários',
'Username' => 'Nome do usuário', 'Username' => 'Nome de usuário',
'Password' => 'Senha', 'Password' => 'Senha',
'Default project' => 'Projeto default', 'Default project' => 'Projeto padrão',
'Administrator' => 'Administrador', 'Administrator' => 'Administrador',
'Sign in' => 'Logar', 'Sign in' => 'Entrar',
'Users' => 'Usuários', 'Users' => 'Usuários',
'No user' => 'Sem usuário', 'No user' => 'Sem usuário',
'Forbidden' => 'Proibido', 'Forbidden' => 'Proibido',
'Access Forbidden' => 'Acesso negado', 'Access Forbidden' => 'Acesso negado',
'Only administrators can access to this page.' => 'Somente administradores têm acesso a esta página.', 'Only administrators can access to this page.' => 'Somente administradores têm acesso a esta página.',
'Edit user' => 'Editar usuário', 'Edit user' => 'Editar usuário',
'Logout' => 'Logout', 'Logout' => 'Sair',
'Bad username or password' => 'Usuário ou senha inválidos', 'Bad username or password' => 'Usuário ou senha inválidos',
'users' => 'usuários', 'users' => 'usuários',
'projects' => 'projetos', 'projects' => 'projetos',
'Edit project' => 'Editar projeto', 'Edit project' => 'Editar projeto',
'Name' => 'Nome', 'Name' => 'Nome',
'Activated' => 'Ativo', 'Activated' => 'Ativado',
'Projects' => 'Projetos', 'Projects' => 'Projetos',
'No project' => 'Nenhum projeto', 'No project' => 'Nenhum projeto',
'Project' => 'Projeto', 'Project' => 'Projeto',
'Status' => 'Status', 'Status' => 'Status',
'Tasks' => 'Tarefas', 'Tasks' => 'Tarefas',
'Board' => 'Quadro', 'Board' => 'Board',
'Actions' => 'Ações', 'Actions' => 'Ações',
'Inactive' => 'Inativo', 'Inactive' => 'Inativo',
'Active' => 'Ativo', 'Active' => 'Ativo',
'Column %d' => 'Coluna %d', 'Column %d' => 'Coluna %d',
'Add this column' => 'Adicionar esta coluna', 'Add this column' => 'Adicionar esta coluna',
'%d tasks on the board' => '%d tarefas no quadro', '%d tasks on the board' => '%d tarefas no board',
'%d tasks in total' => '%d tarefas no total', '%d tasks in total' => '%d tarefas no total',
'Unable to update this board.' => 'Impossível atualizar este quadro.', 'Unable to update this board.' => 'Não foi possível atualizar este board.',
'Edit board' => 'Modificar quadro', 'Edit board' => 'Editar board',
'Disable' => 'Desativar', 'Disable' => 'Desativar',
'Enable' => 'Ativar', 'Enable' => 'Ativar',
'New project' => 'Novo projeto', 'New project' => 'Novo projeto',
'Do you really want to remove this project: "%s"?' => 'Quer realmente remover este projeto: "%s" ?', 'Do you really want to remove this project: "%s"?' => 'Você realmente deseja remover este projeto: "%s" ?',
'Remove project' => 'Remover projeto', 'Remove project' => 'Remover projeto',
'Boards' => 'Quadros', 'Boards' => 'Boards',
'Edit the board for "%s"' => 'Editar o quadro para "%s"', 'Edit the board for "%s"' => 'Editar o board para "%s"',
'All projects' => 'Todos os projetos', 'All projects' => 'Todos os projetos',
'Change columns' => 'Modificar colunas', 'Change columns' => 'Modificar colunas',
'Add a new column' => 'Adicionar uma nova coluna', 'Add a new column' => 'Adicionar uma nova coluna',
'Title' => 'Título', 'Title' => 'Título',
'Add Column' => 'Adicionar coluna', 'Add Column' => 'Adicionar Coluna',
'Project "%s"' => 'Projeto "%s"', 'Project "%s"' => 'Projeto "%s"',
'Nobody assigned' => 'Ninguém designado', 'Nobody assigned' => 'Ninguém designado',
'Assigned to %s' => 'Designado para %s', 'Assigned to %s' => 'Designado para %s',
'Remove a column' => 'Remover uma coluna', 'Remove a column' => 'Remover uma coluna',
'Remove a column from a board' => 'Remover uma coluna do quadro', 'Remove a column from a board' => 'Remover uma coluna do board',
'Unable to remove this column.' => 'Impossível remover esta coluna.', 'Unable to remove this column.' => 'Não foi possível remover esta coluna.',
'Do you really want to remove this column: "%s"?' => 'Quer realmente remover esta coluna: "%s"?', 'Do you really want to remove this column: "%s"?' => 'Você realmente deseja remover esta coluna: "%s"?',
'This action will REMOVE ALL TASKS associated to this column!' => 'Esta ação vai REMOVER TODAS AS TAREFAS associadas a esta coluna!', 'This action will REMOVE ALL TASKS associated to this column!' => 'Esta ação irá REMOVER TODAS AS TAREFAS associadas a esta coluna!',
'Settings' => 'Preferências', 'Settings' => 'Configurações',
'Application settings' => 'Preferências da aplicação', 'Application settings' => 'Configurações da aplicação',
'Language' => 'Idioma', 'Language' => 'Idioma',
'Webhook token:' => 'Token de webhooks:', 'Webhook token:' => 'Token de webhooks:',
'API token:' => 'API Token:', 'API token:' => 'API Token:',
'More information' => 'Mais informação', 'More information' => 'Mais informações',
'Database size:' => 'Tamanho do banco de dados:', 'Database size:' => 'Tamanho do banco de dados:',
'Download the database' => 'Download do banco de dados', 'Download the database' => 'Download do banco de dados',
'Optimize the database' => 'Otimizar o banco de dados', 'Optimize the database' => 'Otimizar o banco de dados',
'(VACUUM command)' => '(Comando VACUUM)', '(VACUUM command)' => '(Comando VACUUM)',
'(Gzip compressed Sqlite file)' => '(Arquivo Sqlite comprimido com Gzip)', '(Gzip compressed Sqlite file)' => '(Arquivo Sqlite comprimido com Gzip)',
'User settings' => 'Configurações do usuário', 'User settings' => 'Configurações do usuário',
'My default project:' => 'Meu projeto default:', 'My default project:' => 'Meu projeto padrão:',
'Close a task' => 'Encerrar uma tarefa', 'Close a task' => 'Finalizar uma tarefa',
'Do you really want to close this task: "%s"?' => 'Quer realmente encerrar esta tarefa: "%s"?', 'Do you really want to close this task: "%s"?' => 'Você realmente deseja finalizar esta tarefa: "%s"?',
'Edit a task' => 'Editar uma tarefa', 'Edit a task' => 'Editar uma tarefa',
'Column' => 'Coluna', 'Column' => 'Coluna',
'Color' => 'Cor', 'Color' => 'Cor',
'Assignee' => 'Designação', 'Assignee' => 'Designação',
'Create another task' => 'Criar uma outra tarefa (aproveitando os dados preenchidos)', 'Create another task' => 'Criar outra tarefa',
'New task' => 'Nova tarefa', 'New task' => 'Nova tarefa',
'Open a task' => 'Abrir uma tarefa', 'Open a task' => 'Abrir uma tarefa',
'Do you really want to open this task: "%s"?' => 'Quer realmente abrir esta tarefa: "%s"?', 'Do you really want to open this task: "%s"?' => 'Você realmente deseja abrir esta tarefa: "%s"?',
'Back to the board' => 'Voltar ao quadro', 'Back to the board' => 'Voltar ao board',
'Created on %B %e, %Y at %k:%M %p' => 'Criado em %d %B %Y às %H:%M', 'Created on %B %e, %Y at %k:%M %p' => 'Criado em %d %B %Y às %H:%M',
'There is nobody assigned' => 'Não há ninguém designado', 'There is nobody assigned' => 'Não há ninguém designado',
'Column on the board:' => 'Coluna no quadro:', 'Column on the board:' => 'Coluna no board:',
'Status is open' => 'Status está aberto', 'Status is open' => 'Status está aberto',
'Status is closed' => 'Status está encerrado', 'Status is closed' => 'Status está finalizado',
'Close this task' => 'Encerrar esta tarefa', 'Close this task' => 'Finalizar esta tarefa',
'Open this task' => 'Abrir esta tarefa', 'Open this task' => 'Abrir esta tarefa',
'There is no description.' => 'Não há descrição.', 'There is no description.' => 'Não há descrição.',
'Add a new task' => 'Adicionar uma nova tarefa', 'Add a new task' => 'Adicionar uma nova tarefa',
'The username is required' => 'O nome de usuário é obrigatório', 'The username is required' => 'O nome de usuário é obrigatório',
'The maximum length is %d characters' => 'O tamanho máximo são %d caracteres', 'The maximum length is %d characters' => 'O tamanho máximo é %d caracteres',
'The minimum length is %d characters' => 'O tamanho mínimo são %d caracteres', 'The minimum length is %d characters' => 'O tamanho mínimo é %d caracteres',
'The password is required' => 'A senha é obrigatória', 'The password is required' => 'A senha é obrigatória',
'This value must be an integer' => 'O valor deve ser um inteiro', 'This value must be an integer' => 'O valor deve ser um número inteiro',
'The username must be unique' => 'O nome de usuário deve ser único', 'The username must be unique' => 'O nome de usuário deve ser único',
'The username must be alphanumeric' => 'O nome de usuário deve ser alfanumérico, sem espaços ou _', 'The username must be alphanumeric' => 'O nome de usuário deve ser alfanumérico',
'The user id is required' => 'O id de usuário é obrigatório', 'The user id is required' => 'O ID de usuário é obrigatório',
'Passwords don\'t match' => 'As senhas não conferem', 'Passwords don\'t match' => 'As senhas não coincidem',
'The confirmation is required' => 'A confirmação é obrigatória', 'The confirmation is required' => 'A confirmação é obrigatória',
'The column is required' => 'A coluna é obrigatória', 'The column is required' => 'A coluna é obrigatória',
'The project is required' => 'O projeto é obrigatório', 'The project is required' => 'O projeto é obrigatório',
'The color is required' => 'A cor é obrigatória', 'The color is required' => 'A cor é obrigatória',
'The id is required' => 'O id é obrigatório', 'The id is required' => 'O ID é obrigatório',
'The project id is required' => 'O id do projeto é obrigatório', 'The project id is required' => 'O ID do projeto é obrigatório',
'The project name is required' => 'O nome do projeto é obrigatório', 'The project name is required' => 'O nome do projeto é obrigatório',
'This project must be unique' => 'Este projeto deve ser único', 'This project must be unique' => 'Este projeto deve ser único',
'The title is required' => 'O título é obrigatório', 'The title is required' => 'O título é obrigatório',
'The language is required' => 'O idioma é obrigatório', 'The language is required' => 'O idioma é obrigatório',
'There is no active project, the first step is to create a new project.' => 'Não há projeto ativo. O primeiro passo é criar um novo projeto.', 'There is no active project, the first step is to create a new project.' => 'Não há projeto ativo. O primeiro passo é criar um novo projeto.',
'Settings saved successfully.' => 'Configurações salvas com sucesso.', 'Settings saved successfully.' => 'Configurações salvas com sucesso.',
'Unable to save your settings.' => 'Impossível salvar suas configurações.', 'Unable to save your settings.' => 'Não é possível salvar suas configurações.',
'Database optimization done.' => 'Otimização do banco de dados terminada.', 'Database optimization done.' => 'Otimização do banco de dados finalizada.',
'Your project have been created successfully.' => 'Seu projeto foi criado com sucesso.', 'Your project have been created successfully.' => 'Seu projeto foi criado com sucesso.',
'Unable to create your project.' => 'Impossível criar seu projeto.', 'Unable to create your project.' => 'Não é possível criar o seu projeto.',
'Project updated successfully.' => 'Projeto atualizado com sucesso.', 'Project updated successfully.' => 'Projeto atualizado com sucesso.',
'Unable to update this project.' => 'Impossível atualizar este projeto.', 'Unable to update this project.' => 'Não é possível atualizar este projeto.',
'Unable to remove this project.' => 'Impossível remover este projeto.', 'Unable to remove this project.' => 'Não é possível remover este projeto.',
'Project removed successfully.' => 'Projeto removido com sucesso.', 'Project removed successfully.' => 'Projeto removido com sucesso.',
'Project activated successfully.' => 'Projeto ativado com sucesso.', 'Project activated successfully.' => 'Projeto ativado com sucesso.',
'Unable to activate this project.' => 'Impossível ativar este projeto.', 'Unable to activate this project.' => 'Não é possível ativar este projeto.',
'Project disabled successfully.' => 'Projeto desabilitado com sucesso.', 'Project disabled successfully.' => 'Projeto desativado com sucesso.',
'Unable to disable this project.' => 'Impossível desabilitar este projeto.', 'Unable to disable this project.' => 'Não é possível desativar este projeto.',
'Unable to open this task.' => 'Impossível abrir esta tarefa.', 'Unable to open this task.' => 'Não é possível abrir esta tarefa.',
'Task opened successfully.' => 'Tarefa aberta com sucesso.', 'Task opened successfully.' => 'Tarefa aberta com sucesso.',
'Unable to close this task.' => 'Impossível encerrar esta tarefa.', 'Unable to close this task.' => 'Não é possível finalizar esta tarefa.',
'Task closed successfully.' => 'Tarefa encerrada com sucesso.', 'Task closed successfully.' => 'Tarefa finalizada com sucesso.',
'Unable to update your task.' => 'Impossível atualizar sua tarefa.', 'Unable to update your task.' => 'Não é possível atualizar a sua tarefa.',
'Task updated successfully.' => 'Tarefa atualizada com sucesso.', 'Task updated successfully.' => 'Tarefa atualizada com sucesso.',
'Unable to create your task.' => 'Impossível criar sua tarefa.', 'Unable to create your task.' => 'Não é possível criar a sua tarefa.',
'Task created successfully.' => 'Tarefa criada com sucesso.', 'Task created successfully.' => 'Tarefa criada com sucesso.',
'User created successfully.' => 'Usuário criado com sucesso.', 'User created successfully.' => 'Usuário criado com sucesso.',
'Unable to create your user.' => 'Impossível criar seu usuário.', 'Unable to create your user.' => 'Não é possível criar o seu usuário.',
'User updated successfully.' => 'Usuário atualizado com sucesso.', 'User updated successfully.' => 'Usuário atualizado com sucesso.',
'Unable to update your user.' => 'Impossível atualizar seu usuário.', 'Unable to update your user.' => 'Não é possível atualizar o seu usuário.',
'User removed successfully.' => 'Usuário removido com sucesso.', 'User removed successfully.' => 'Usuário removido com sucesso.',
'Unable to remove this user.' => 'Impossível remover este usuário.', 'Unable to remove this user.' => 'Não é possível remover este usuário.',
'Board updated successfully.' => 'Quadro atualizado com sucesso.', 'Board updated successfully.' => 'Board atualizado com sucesso.',
'Ready' => 'Pronto', 'Ready' => 'Pronto',
'Backlog' => 'Backlog', 'Backlog' => 'Backlog',
'Work in progress' => 'Em andamento', 'Work in progress' => 'Em andamento',
'Done' => 'Encerrado', 'Done' => 'Finalizado',
'Application version:' => 'Versão da aplicação:', 'Application version:' => 'Versão da aplicação:',
'Completed on %B %e, %Y at %k:%M %p' => 'Encerrado em %d %B %Y às %H:%M', 'Completed on %B %e, %Y at %k:%M %p' => 'Finalizado em %d %B %Y às %H:%M',
'%B %e, %Y at %k:%M %p' => '%d %B %Y às %H:%M', '%B %e, %Y at %k:%M %p' => '%d %B %Y às %H:%M',
'Date created' => 'Data de criação', 'Date created' => 'Data de criação',
'Date completed' => 'Data de encerramento', 'Date completed' => 'Data da finalização',
'Id' => 'Id', 'Id' => 'Id',
'No task' => 'Nenhuma tarefa', 'No task' => 'Nenhuma tarefa',
'Completed tasks' => 'tarefas completadas', 'Completed tasks' => 'Tarefas completadas',
'List of projects' => 'Lista de projetos', 'List of projects' => 'Lista de projetos',
'Completed tasks for "%s"' => 'Tarefas completadas por "%s"', 'Completed tasks for "%s"' => 'Tarefas completadas por "%s"',
'%d closed tasks' => '%d tarefas encerradas', '%d closed tasks' => '%d tarefas finalizadas',
'No task for this project' => 'Nenhuma tarefa para este projeto', 'No task for this project' => 'Não há tarefa para este projeto',
'Public link' => 'Link público', 'Public link' => 'Link público',
'There is no column in your project!' => 'Não há colunas no seu projeto!', 'There is no column in your project!' => 'Não há colunas no seu projeto!',
'Change assignee' => 'Mudar a designação', 'Change assignee' => 'Mudar a designação',
'Change assignee for the task "%s"' => 'Modificar designação para a tarefa "%s"', 'Change assignee for the task "%s"' => 'Modificar designação para a tarefa "%s"',
'Timezone' => 'Fuso horário', 'Timezone' => 'Fuso horário',
'Sorry, I didn\'t found this information in my database!' => 'Desculpe, não encontrei esta informação no meu banco de dados!', 'Sorry, I didn\'t find this information in my database!' => 'Desculpe, não encontrei esta informação no meu banco de dados!',
'Page not found' => 'Página não encontrada', 'Page not found' => 'Página não encontrada',
'Complexity' => 'Complexidade', 'Complexity' => 'Complexidade',
'limit' => 'limite', 'limit' => 'limite',
@ -191,10 +191,10 @@ return array(
'This value must be greater than %d' => 'Este valor deve ser maior que %d', 'This value must be greater than %d' => 'Este valor deve ser maior que %d',
'Edit project access list' => 'Editar lista de acesso ao projeto', 'Edit project access list' => 'Editar lista de acesso ao projeto',
'Edit users access' => 'Editar acesso de usuários', 'Edit users access' => 'Editar acesso de usuários',
'Allow this user' => 'Permitir esse usuário', 'Allow this user' => 'Permitir este usuário',
'Only those users have access to this project:' => 'Somente estes usuários têm acesso a este projeto:', 'Only those users have access to this project:' => 'Somente esses usuários têm acesso a este projeto:',
'Don\'t forget that administrators have access to everything.' => 'Não esqueça que administradores têm acesso a tudo.', 'Don\'t forget that administrators have access to everything.' => 'Não esqueça que administradores têm acesso a tudo.',
'revoke' => 'revogar', 'Revoke' => 'Revogar',
'List of authorized users' => 'Lista de usuários autorizados', 'List of authorized users' => 'Lista de usuários autorizados',
'User' => 'Usuário', 'User' => 'Usuário',
'Nobody have access to this project.' => 'Ninguém tem acesso a este projeto.', 'Nobody have access to this project.' => 'Ninguém tem acesso a este projeto.',
@ -205,19 +205,20 @@ return array(
'Leave a comment' => 'Deixe um comentário', 'Leave a comment' => 'Deixe um comentário',
'Comment is required' => 'Comentário é obrigatório', 'Comment is required' => 'Comentário é obrigatório',
'Leave a description' => 'Deixe uma descrição', 'Leave a description' => 'Deixe uma descrição',
'Comment added successfully.' => 'Cpmentário adicionado com sucesso.', 'Comment added successfully.' => 'Comentário adicionado com sucesso.',
'Unable to create your comment.' => 'Impossível criar seu comentário.', 'Unable to create your comment.' => 'Não é possível criar o seu comentário.',
'The description is required' => 'A descrição é obrigatória', 'The description is required' => 'A descrição é obrigatória',
'Edit this task' => 'Editar esta tarefa', 'Edit this task' => 'Editar esta tarefa',
'Due Date' => 'Data de vencimento', 'Due Date' => 'Data de vencimento',
'Invalid date' => 'Data inválida', 'Invalid date' => 'Data inválida',
'Must be done before %B %e, %Y' => 'Deve ser feito antes de %d %B %Y', 'Must be done before %B %e, %Y' => 'Deve ser finalizado antes de %d %B %Y',
'%B %e, %Y' => '%d %B %Y', '%B %e, %Y' => '%d %B %Y',
'%b %e, %Y' => '%d %B %Y',
'Automatic actions' => 'Ações automáticas', 'Automatic actions' => 'Ações automáticas',
'Your automatic action have been created successfully.' => 'Sua ação automética foi criada com sucesso.', 'Your automatic action have been created successfully.' => 'Sua ação automética foi criada com sucesso.',
'Unable to create your automatic action.' => 'Impossível criar sua ação automática.', 'Unable to create your automatic action.' => 'Não é possível criar sua ação automática.',
'Remove an action' => 'Remover uma ação', 'Remove an action' => 'Remover uma ação',
'Unable to remove this action.' => 'Impossível remover esta ação.', 'Unable to remove this action.' => 'Não é possível remover esta ação.',
'Action removed successfully.' => 'Ação removida com sucesso.', 'Action removed successfully.' => 'Ação removida com sucesso.',
'Automatic actions for the project "%s"' => 'Ações automáticas para o projeto "%s"', 'Automatic actions for the project "%s"' => 'Ações automáticas para o projeto "%s"',
'Defined actions' => 'Ações definidas', 'Defined actions' => 'Ações definidas',
@ -227,22 +228,22 @@ return array(
'Action parameters' => 'Parâmetros da ação', 'Action parameters' => 'Parâmetros da ação',
'Action' => 'Ação', 'Action' => 'Ação',
'Event' => 'Evento', 'Event' => 'Evento',
'When the selected event occurs execute the corresponding action.' => 'Quando o evento selecionado ocorrer, execute a ação correspondente.', 'When the selected event occurs execute the corresponding action.' => 'Quando o evento selecionado ocorrer execute a ação correspondente.',
'Next step' => 'Próximo passo', 'Next step' => 'Próximo passo',
'Define action parameters' => 'Definir parêmetros da ação', 'Define action parameters' => 'Definir parêmetros da ação',
'Save this action' => 'Salvar esta ação', 'Save this action' => 'Salvar esta ação',
'Do you really want to remove this action: "%s"?' => 'Você quer realmente remover esta ação: "%s"?', 'Do you really want to remove this action: "%s"?' => 'Você realmente deseja remover esta ação: "%s"?',
'Remove an automatic action' => 'Remove uma ação automática', 'Remove an automatic action' => 'Remover uma ação automática',
'Close the task' => 'Encerrar tarefa', 'Close the task' => 'Finalizar tarefa',
'Assign the task to a specific user' => 'Designar a tarefa para um usuário específico', 'Assign the task to a specific user' => 'Designar a tarefa para um usuário específico',
'Assign the task to the person who does the action' => 'Designar a tarefa para a pessoa que executa a ação', 'Assign the task to the person who does the action' => 'Designar a tarefa para a pessoa que executa a ação',
'Duplicate the task to another project' => 'Duplicar a tarefa para um outro projeto', 'Duplicate the task to another project' => 'Duplicar a tarefa para um outro projeto',
'Move a task to another column' => 'Mover a tarefa para outra coluna', 'Move a task to another column' => 'Mover a tarefa para outra coluna',
'Move a task to another position in the same column' => 'Mover a tarefa para outra posição, na mesma coluna', 'Move a task to another position in the same column' => 'Mover a tarefa para outra posição na mesma coluna',
'Task modification' => 'Modificação de tarefa', 'Task modification' => 'Modificação de tarefa',
'Task creation' => 'Criação de tarefa', 'Task creation' => 'Criação de tarefa',
'Open a closed task' => 'Reabrir uma tarefa encerrada', 'Open a closed task' => 'Reabrir uma tarefa finalizada',
'Closing a task' => 'Encerrando uma tarefa', 'Closing a task' => 'Finalizando uma tarefa',
'Assign a color to a specific user' => 'Designar uma cor para um usuário específico', 'Assign a color to a specific user' => 'Designar uma cor para um usuário específico',
'Column title' => 'Título da coluna', 'Column title' => 'Título da coluna',
'Position' => 'Posição', 'Position' => 'Posição',
@ -253,26 +254,26 @@ return array(
'link' => 'link', 'link' => 'link',
'Update this comment' => 'Atualizar este comentário', 'Update this comment' => 'Atualizar este comentário',
'Comment updated successfully.' => 'Comentário atualizado com sucesso.', 'Comment updated successfully.' => 'Comentário atualizado com sucesso.',
'Unable to update your comment.' => 'Impossível atualizar seu comentário.', 'Unable to update your comment.' => 'Não é possível atualizar o seu comentário.',
'Remove a comment' => 'Remover um comentário', 'Remove a comment' => 'Remover um comentário',
'Comment removed successfully.' => 'Comentário removido com sucesso.', 'Comment removed successfully.' => 'Comentário removido com sucesso.',
'Unable to remove this comment.' => 'Impossível remover este comentário.', 'Unable to remove this comment.' => 'Não é possível remover este comentário.',
'Do you really want to remove this comment?' => 'Você tem certeza de que quer remover este comentário?', 'Do you really want to remove this comment?' => 'Você realmente deseja remover este comentário?',
'Only administrators or the creator of the comment can access to this page.' => 'Somente administradores ou o criator deste comentário tem acesso a esta página.', 'Only administrators or the creator of the comment can access to this page.' => 'Somente os administradores ou o criator deste comentário possuem acesso a esta página.',
'Details' => 'Detalhes', 'Details' => 'Detalhes',
'Current password for the user "%s"' => 'Senha atual para o usuário "%s"', 'Current password for the user "%s"' => 'Senha atual para o usuário "%s"',
'The current password is required' => 'A senha atual é obrigatória', 'The current password is required' => 'A senha atual é obrigatória',
'Wrong password' => 'Senha errada', 'Wrong password' => 'Senha incorreta',
'Reset all tokens' => 'Reiniciar todos os tokens', 'Reset all tokens' => 'Resetar todos os tokens',
'All tokens have been regenerated.' => 'Todos os tokens foram gerados novamente.', 'All tokens have been regenerated.' => 'Todos os tokens foram gerados novamente.',
'Unknown' => 'Desconhecido', 'Unknown' => 'Desconhecido',
'Last logins' => 'Últimos logins', 'Last logins' => 'Últimos logins',
'Login date' => 'Data de login', 'Login date' => 'Data de login',
'Authentication method' => 'Método de autenticação', 'Authentication method' => 'Método de autenticação',
'IP address' => 'Endereço IP', 'IP address' => 'Endereço IP',
'User agent' => 'Agente usuário', 'User agent' => 'User Agent',
'Persistent connections' => 'Conexões persistentes', 'Persistent connections' => 'Conexões persistentes',
'No session.' => 'Sem sessão.', 'No session.' => 'Nenhuma sessão.',
'Expiration date' => 'Data de expiração', 'Expiration date' => 'Data de expiração',
'Remember Me' => 'Lembre-se de mim', 'Remember Me' => 'Lembre-se de mim',
'Creation date' => 'Data de criação', 'Creation date' => 'Data de criação',
@ -280,25 +281,25 @@ return array(
'Filter by due date' => 'Filtrar por data de vencimento', 'Filter by due date' => 'Filtrar por data de vencimento',
'Everybody' => 'Todos', 'Everybody' => 'Todos',
'Open' => 'Abrir', 'Open' => 'Abrir',
'Closed' => 'Encerrado', 'Closed' => 'Finalizado',
'Search' => 'Pesquisar', 'Search' => 'Pesquisar',
'Nothing found.' => 'Não encontrado.', 'Nothing found.' => 'Nada foi encontrado.',
'Search in the project "%s"' => 'Procure no projeto "%s"', 'Search in the project "%s"' => 'Pesquisar no projeto "%s"',
'Due date' => 'Data de vencimento', 'Due date' => 'Data de vencimento',
'Others formats accepted: %s and %s' => 'Outros formatos permitidos: %s e %s', 'Others formats accepted: %s and %s' => 'Outros formatos permitidos: %s e %s',
'Description' => 'Descrição', 'Description' => 'Descrição',
'%d comments' => '%d comentários', '%d comments' => '%d comentários',
'%d comment' => '%d comentário', '%d comment' => '%d comentário',
'Email address invalid' => 'Endereço de e-mail inválido', 'Email address invalid' => 'Endereço de e-mail inválido',
'Your Google Account is not linked anymore to your profile.' => 'Sua conta Google não está mais associada ao seu perfil.', 'Your Google Account is not linked anymore to your profile.' => 'Sua conta do Google não está mais associada ao seu perfil.',
'Unable to unlink your Google Account.' => 'Impossível desassociar sua conta Google.', 'Unable to unlink your Google Account.' => 'Não foi possível desassociar a sua Conta do Google.',
'Google authentication failed' => 'Autenticação do Google falhou.', 'Google authentication failed' => 'Autenticação do Google falhou.',
'Unable to link your Google Account.' => 'Impossível associar a sua conta do Google.', 'Unable to link your Google Account.' => 'Não foi possível associar a sua Conta do Google.',
'Your Google Account is linked to your profile successfully.' => 'Sua Conta do Google está ligada ao seu perfil com sucesso.', 'Your Google Account is linked to your profile successfully.' => 'Sua Conta do Google foi associada ao seu perfil com sucesso.',
'Email' => 'E-mail', 'Email' => 'E-mail',
'Link my Google Account' => 'Vincular minha conta Google', 'Link my Google Account' => 'Vincular minha Conta do Google',
'Unlink my Google Account' => 'Desvincular minha conta do Google', 'Unlink my Google Account' => 'Desvincular minha Conta do Google',
'Login with my Google Account' => 'Entrar com minha conta do Google', 'Login with my Google Account' => 'Entrar com minha Conta do Google',
'Project not found.' => 'Projeto não encontrado.', 'Project not found.' => 'Projeto não encontrado.',
'Task #%d' => 'Tarefa #%d', 'Task #%d' => 'Tarefa #%d',
'Task removed successfully.' => 'Tarefa removida com sucesso.', 'Task removed successfully.' => 'Tarefa removida com sucesso.',
@ -312,8 +313,8 @@ return array(
'Category:' => 'Categoria:', 'Category:' => 'Categoria:',
'Categories' => 'Categorias', 'Categories' => 'Categorias',
'Category not found.' => 'Categoria não encontrada.', 'Category not found.' => 'Categoria não encontrada.',
'Your category have been created successfully.' => 'Seu categoria foi criada com sucesso.', 'Your category have been created successfully.' => 'Sua categoria foi criada com sucesso.',
'Unable to create your category.' => 'Não é possível criar sua categoria.', 'Unable to create your category.' => 'Não foi possível criar a sua categoria.',
'Your category have been updated successfully.' => 'A sua categoria foi atualizada com sucesso.', 'Your category have been updated successfully.' => 'A sua categoria foi atualizada com sucesso.',
'Unable to update your category.' => 'Não foi possível atualizar a sua categoria.', 'Unable to update your category.' => 'Não foi possível atualizar a sua categoria.',
'Remove a category' => 'Remover uma categoria', 'Remove a category' => 'Remover uma categoria',
@ -326,7 +327,7 @@ return array(
'Do you really want to remove this category: "%s"?' => 'Você realmente deseja remover esta categoria: "%s"', 'Do you really want to remove this category: "%s"?' => 'Você realmente deseja remover esta categoria: "%s"',
'Filter by category' => 'Filtrar por categoria', 'Filter by category' => 'Filtrar por categoria',
'All categories' => 'Todas as categorias', 'All categories' => 'Todas as categorias',
'No category' => 'Sem categoria', 'No category' => 'Nenhum categoria',
'The name is required' => 'O nome é obrigatório', 'The name is required' => 'O nome é obrigatório',
'Remove a file' => 'Remover um arquivo', 'Remove a file' => 'Remover um arquivo',
'Unable to remove this file.' => 'Não foi possível remover este arquivo.', 'Unable to remove this file.' => 'Não foi possível remover este arquivo.',
@ -343,60 +344,60 @@ return array(
'Time tracking' => 'Rastreamento de tempo', 'Time tracking' => 'Rastreamento de tempo',
'Estimate:' => 'Estimado:', 'Estimate:' => 'Estimado:',
'Spent:' => 'Gasto:', 'Spent:' => 'Gasto:',
'Do you really want to remove this sub-task?' => 'Você realmente deseja remover esta sub-tarefa?', 'Do you really want to remove this sub-task?' => 'Você realmente deseja remover esta subtarefa?',
'Remaining:' => 'Restante:', 'Remaining:' => 'Restante:',
'hours' => 'horas', 'hours' => 'horas',
'spent' => 'gasto', 'spent' => 'gasto',
'estimated' => 'estimada', 'estimated' => 'estimado',
'Sub-Tasks' => 'Sub-tarefas', 'Sub-Tasks' => 'Subtarefas',
'Add a sub-task' => 'Adicionar uma sub-tarefa', 'Add a sub-task' => 'Adicionar uma subtarefa',
'Original estimate' => 'Estimativa original', 'Original estimate' => 'Estimativa original',
'Create another sub-task' => 'Criar uma outra sub-tarefa', 'Create another sub-task' => 'Criar uma outra subtarefa',
'Time spent' => 'Tempo gasto', 'Time spent' => 'Tempo gasto',
'Edit a sub-task' => 'Editar uma sub-tarefa', 'Edit a sub-task' => 'Editar uma subtarefa',
'Remove a sub-task' => 'Remover uma sub-tarefa', 'Remove a sub-task' => 'Remover uma subtarefa',
'The time must be a numeric value' => 'O tempo deve ser um valor numérico', 'The time must be a numeric value' => 'O tempo deve ser um valor numérico',
'Todo' => 'A fazer', 'Todo' => 'À fazer',
'In progress' => 'Em andamento', 'In progress' => 'Em andamento',
'Sub-task removed successfully.' => 'Sub-tarefa removido com sucesso.', 'Sub-task removed successfully.' => 'Subtarefa removida com sucesso.',
'Unable to remove this sub-task.' => 'Não foi possível remover esta sub-tarefa.', 'Unable to remove this sub-task.' => 'Não foi possível remover esta subtarefa.',
'Sub-task updated successfully.' => 'Sub-tarefa atualizada com sucesso.', 'Sub-task updated successfully.' => 'Subtarefa atualizada com sucesso.',
'Unable to update your sub-task.' => 'Não foi possível atualizar sua sub-tarefa.', 'Unable to update your sub-task.' => 'Não foi possível atualizar a sua subtarefa.',
'Unable to create your sub-task.' => 'Não é possível criar sua sub-tarefa.', 'Unable to create your sub-task.' => 'Não é possível criar a sua subtarefa.',
'Sub-task added successfully.' => 'Sub-tarefa adicionada com sucesso.', 'Sub-task added successfully.' => 'Subtarefa adicionada com sucesso.',
'Maximum size: ' => 'O tamanho máximo:', 'Maximum size: ' => 'Tamanho máximo:',
'Unable to upload the file.' => 'Não foi possível carregar o arquivo.', 'Unable to upload the file.' => 'Não foi possível carregar o arquivo.',
'Display another project' => 'Mostrar um outro projeto', 'Display another project' => 'Exibir outro projeto',
'Your GitHub account was successfully linked to your profile.' => 'A sua conta GitHub foi ligada com sucesso ao seu perfil.', 'Your GitHub account was successfully linked to your profile.' => 'A sua Conta do GitHub foi associada com sucesso ao seu perfil.',
'Unable to link your GitHub Account.' => 'Não foi possível vincular sua conta GitHub.', 'Unable to link your GitHub Account.' => 'Não foi possível associar sua Conta do GitHub.',
'GitHub authentication failed' => 'Falhou autenticação GitHub', 'GitHub authentication failed' => 'Autenticação do GitHub falhou',
'Your GitHub account is no longer linked to your profile.' => 'A sua conta GitHub já não está ligada ao seu perfil.', 'Your GitHub account is no longer linked to your profile.' => 'A sua Conta do GitHub não está mais associada ao seu perfil.',
'Unable to unlink your GitHub Account.' => 'Não foi possível desvincular sua conta GitHub.', 'Unable to unlink your GitHub Account.' => 'Não foi possível desassociar a sua Conta do GitHub.',
'Login with my GitHub Account' => 'Entrar com minha conta do GitHub', 'Login with my GitHub Account' => 'Entrar com minha Conta do GitHub',
'Link my GitHub Account' => 'Vincular minha conta GitHub', 'Link my GitHub Account' => 'Associar à minha Conta do GitHub',
'Unlink my GitHub Account' => 'Desvincular minha conta do GitHub', 'Unlink my GitHub Account' => 'Desassociar a minha Conta do GitHub',
'Created by %s' => 'Criado por %s', 'Created by %s' => 'Criado por %s',
'Last modified on %B %e, %Y at %k:%M %p' => 'Última modificação em %B %e, %Y às %k: %M %p', 'Last modified on %B %e, %Y at %k:%M %p' => 'Última modificação em %B %e, %Y às %k: %M %p',
'Tasks Export' => 'Tarefas Export', 'Tasks Export' => 'Exportar Tarefas',
'Tasks exportation for "%s"' => 'Tarefas exportação para "%s"', 'Tasks exportation for "%s"' => 'As tarefas foram exportadas para "%s"',
'Start Date' => 'Data inicial', 'Start Date' => 'Data inicial',
'End Date' => 'Data final', 'End Date' => 'Data final',
'Execute' => 'Executar', 'Execute' => 'Executar',
'Task Id' => 'Id da Tarefa', 'Task Id' => 'ID da Tarefa',
'Creator' => 'Criador', 'Creator' => 'Criado por',
'Modification date' => 'Data de modificação', 'Modification date' => 'Data da modificação',
'Completion date' => 'Data de conclusão', 'Completion date' => 'Data da finalização',
'Webhook URL for task creation' => 'Webhook URL para criação de tarefas', 'Webhook URL for task creation' => 'Webhook URL para criação de tarefas',
'Webhook URL for task modification' => 'Webhook URL para modificação tarefa', 'Webhook URL for task modification' => 'Webhook URL para modificação de tarefa',
'Clone' => 'Clone', 'Clone' => 'Clonar',
'Clone Project' => 'Clonar Projeto', 'Clone Project' => 'Clonar Projeto',
'Project cloned successfully.' => 'Projeto clonado com sucesso.', 'Project cloned successfully.' => 'Projeto clonado com sucesso.',
'Unable to clone this project.' => 'Impossível clonar este projeto.', 'Unable to clone this project.' => 'Não foi possível clonar este projeto.',
'Email notifications' => 'Notificações por email', 'Email notifications' => 'Notificações por email',
'Enable email notifications' => 'Habilitar notificações por email', 'Enable email notifications' => 'Habilitar notificações por email',
'Task position:' => 'Posição da tarefa:', 'Task position:' => 'Posição da tarefa:',
'The task #%d have been opened.' => 'A tarefa #%d foi aberta.', 'The task #%d have been opened.' => 'A tarefa #%d foi aberta.',
'The task #%d have been closed.' => 'A tarefa #%d foi encerrada.', 'The task #%d have been closed.' => 'A tarefa #%d foi finalizada.',
'Sub-task updated' => 'Subtarefa atualizada', 'Sub-task updated' => 'Subtarefa atualizada',
'Title:' => 'Título:', 'Title:' => 'Título:',
'Status:' => 'Status:', 'Status:' => 'Status:',
@ -407,18 +408,18 @@ return array(
'Comment updated' => 'Comentário atualizado', 'Comment updated' => 'Comentário atualizado',
'New comment posted by %s' => 'Novo comentário postado por %s', 'New comment posted by %s' => 'Novo comentário postado por %s',
'List of due tasks for the project "%s"' => 'Lista de tarefas pendentes para o projeto "%s"', 'List of due tasks for the project "%s"' => 'Lista de tarefas pendentes para o projeto "%s"',
// '[%s][New attachment] %s (#%d)' => '', '[%s][New attachment] %s (#%d)' => '[%s][Novo anexo] %s (#%d)',
// '[%s][New comment] %s (#%d)' => '', '[%s][New comment] %s (#%d)' => '[%s][Novo comentário] %s (#%d)',
// '[%s][Comment updated] %s (#%d)' => '', '[%s][Comment updated] %s (#%d)' => '[%s][Comentário atualizado] %s (#%d)',
// '[%s][New subtask] %s (#%d)' => '', '[%s][New subtask] %s (#%d)' => '[%s][Nova subtarefa] %s (#%d)',
// '[%s][Subtask updated] %s (#%d)' => '', '[%s][Subtask updated] %s (#%d)' => '[%s][Subtarefa atualizada] %s (#%d)',
// '[%s][New task] %s (#%d)' => '', '[%s][New task] %s (#%d)' => '[%s][Nova tarefa] %s (#%d)',
// '[%s][Task updated] %s (#%d)' => '', '[%s][Task updated] %s (#%d)' => '[%s][Tarefa atualizada] %s (#%d)',
// '[%s][Task closed] %s (#%d)' => '', '[%s][Task closed] %s (#%d)' => '[%s][Tarefa finalizada] %s (#%d)',
// '[%s][Task opened] %s (#%d)' => '', '[%s][Task opened] %s (#%d)' => '[%s][Tarefa aberta] %s (#%d)',
// '[%s][Due tasks]' => '', '[%s][Due tasks]' => '[%s][Tarefas pendentes]',
'[Kanboard] Notification' => '[Kanboard] Notificação', '[Kanboard] Notification' => '[Kanboard] Notificação',
'I want to receive notifications only for those projects:' => 'Quero receber notificações somente para estes projetos:', 'I want to receive notifications only for those projects:' => 'Quero receber notificações apenas destes projetos:',
'view the task on Kanboard' => 'ver a tarefa no Kanboard', 'view the task on Kanboard' => 'ver a tarefa no Kanboard',
'Public access' => 'Acesso público', 'Public access' => 'Acesso público',
'Category management' => 'Gerenciamento de categorias', 'Category management' => 'Gerenciamento de categorias',
@ -429,17 +430,17 @@ return array(
'Active projects' => 'Projetos ativos', 'Active projects' => 'Projetos ativos',
'Inactive projects' => 'Projetos inativos', 'Inactive projects' => 'Projetos inativos',
'Public access disabled' => 'Acesso público desabilitado', 'Public access disabled' => 'Acesso público desabilitado',
'Do you really want to disable this project: "%s"?' => 'Deseja ralmente desabilitar este projeto: "%s"?', 'Do you really want to disable this project: "%s"?' => 'Você realmente deseja desabilitar este projeto: "%s"?',
'Do you really want to duplicate this project: "%s"?' => 'Deseja realmente duplicar este projeto: "%s"?', 'Do you really want to duplicate this project: "%s"?' => 'Você realmente deseja duplicar este projeto: "%s"?',
'Do you really want to enable this project: "%s"?' => 'Deseja realmente habilitar este projeto: "%s"?', 'Do you really want to enable this project: "%s"?' => 'Você realmente deseja habilitar este projeto: "%s"?',
'Project activation' => 'Avaliação do projeto', 'Project activation' => 'Ativação do projeto',
'Move the task to another project' => 'Mover a tarefa para outro projeto', 'Move the task to another project' => 'Mover a tarefa para outro projeto',
'Move to another project' => 'Mover para outro projeto', 'Move to another project' => 'Mover para outro projeto',
'Do you really want to duplicate this task?' => 'Deseja realmente duplicar esta tarefa?', 'Do you really want to duplicate this task?' => 'Você realmente deseja duplicar esta tarefa?',
'Duplicate a task' => 'Duplicar tarefa', 'Duplicate a task' => 'Duplicar uma tarefa',
'External accounts' => 'Contas externas', 'External accounts' => 'Contas externas',
'Account type' => 'Tipo de conta', 'Account type' => 'Tipo de conta',
// 'Local' => '', 'Local' => 'Local',
'Remote' => 'Remoto', 'Remote' => 'Remoto',
'Enabled' => 'Habilitado', 'Enabled' => 'Habilitado',
'Disabled' => 'Desabilitado', 'Disabled' => 'Desabilitado',
@ -447,12 +448,12 @@ return array(
'Github account linked' => 'Conta do Github associada', 'Github account linked' => 'Conta do Github associada',
'Username:' => 'Usuário:', 'Username:' => 'Usuário:',
'Name:' => 'Nome:', 'Name:' => 'Nome:',
// 'Email:' => '', 'Email:' => 'E-mail:',
'Default project:' => 'Projeto padrão:', 'Default project:' => 'Projeto padrão:',
'Notifications:' => 'Notificações:', 'Notifications:' => 'Notificações:',
'Notifications' => 'Notificações', 'Notifications' => 'Notificações',
'Group:' => 'Groupo:', 'Group:' => 'Grupo:',
'Regular user' => 'Usuário habitual', 'Regular user' => 'Usuário comum',
'Account type:' => 'Tipo de conta:', 'Account type:' => 'Tipo de conta:',
'Edit profile' => 'Editar perfil', 'Edit profile' => 'Editar perfil',
'Change password' => 'Alterar senha', 'Change password' => 'Alterar senha',
@ -463,33 +464,33 @@ return array(
'Never connected.' => 'Nunca conectado.', 'Never connected.' => 'Nunca conectado.',
'No account linked.' => 'Nenhuma conta associada.', 'No account linked.' => 'Nenhuma conta associada.',
'Account linked.' => 'Conta associada.', 'Account linked.' => 'Conta associada.',
'No external authentication enabled.' => 'Nenhuma autenticação externa permitida.', 'No external authentication enabled.' => 'Nenhuma autenticação externa habilitada.',
'Password modified successfully.' => 'Senha alterada com sucesso.', 'Password modified successfully.' => 'Senha alterada com sucesso.',
'Unable to change the password.' => 'Não foi possível alterar a senha.', 'Unable to change the password.' => 'Não foi possível alterar a senha.',
'Change category for the task "%s"' => 'Mudar categoria para a tarefa "%s"', 'Change category for the task "%s"' => 'Mudar categoria da tarefa "%s"',
'Change category' => 'Mudar categoria', 'Change category' => 'Mudar categoria',
// '%s updated the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '', '%s updated the task %s' => '%s atualizou a tarefa %s',
// '%s open the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '', '%s opened the task %s' => '%s abriu a tarefa %s',
// '%s moved the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to the position #%d in the column "%s"' => '', '%s moved the task %s to the position #%d in the column "%s"' => '%s moveu a tarefa %s para a posição #%d na coluna "%s"',
// '%s moved the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to the column "%s"' => '', '%s moved the task %s to the column "%s"' => '%s moveu a tarefa %s para a coluna "%s"',
// '%s created the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '', '%s created the task %s' => '%s criou a tarefa %s',
// '%s closed the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '', '%s closed the task %s' => '%s finalizou a tarefa %s',
'%s created a subtask for the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s criou uma sub-tarefa para a tarefa <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s created a subtask for the task %s' => '%s criou uma subtarefa para a tarefa %s',
'%s updated a subtask for the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s atualizou uma sub-tarefa da tarefa <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s updated a subtask for the task %s' => '%s atualizou uma subtarefa da tarefa %s',
'Assigned to %s with an estimate of %s/%sh' => 'Designado para %s com tempo estimado de %s/%sh', 'Assigned to %s with an estimate of %s/%sh' => 'Designado para %s com tempo estimado de %s/%sh',
'Not assigned, estimate of %sh' => 'Não designado, estimado em %sh', 'Not assigned, estimate of %sh' => 'Não designado, estimado em %sh',
'%s updated a comment on the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s atualizou o comentário na tarefa <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s updated a comment on the task %s' => '%s atualizou o comentário na tarefa %s',
'%s commented the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s comentou a tarefa <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s commented the task %s' => '%s comentou a tarefa %s',
'%s\'s activity' => 'Atividades de%s', '%s\'s activity' => 'Atividades de%s',
'No activity.' => 'Sem atividade.', 'No activity.' => 'Sem atividade.',
// 'RSS feed' => '', 'RSS feed' => 'Feed RSS',
'%s updated a comment on the task #%d' => '%s atualizou um comentário na tarefa #%d', '%s updated a comment on the task #%d' => '%s atualizou um comentário sobre a tarefa #%d',
'%s commented on the task #%d' => '%s comentou na tarefa #%d', '%s commented on the task #%d' => '%s comentou sobre a tarefa #%d',
'%s updated a subtask for the task #%d' => '%s atualizou uma sub-tarefa para a tarefa #%d', '%s updated a subtask for the task #%d' => '%s atualizou uma subtarefa para a tarefa #%d',
'%s created a subtask for the task #%d' => '%s criou uma sub-tarefa para a tarefa #%d', '%s created a subtask for the task #%d' => '%s criou uma subtarefa para a tarefa #%d',
'%s updated the task #%d' => '%s atualizou a tarefa #%d', '%s updated the task #%d' => '%s atualizou a tarefa #%d',
'%s created the task #%d' => '%s criou a tarefa #%d', '%s created the task #%d' => '%s criou a tarefa #%d',
'%s closed the task #%d' => '%s encerrou a tarefa #%d', '%s closed the task #%d' => '%s finalizou a tarefa #%d',
'%s open the task #%d' => '%s abriu a tarefa #%d', '%s open the task #%d' => '%s abriu a tarefa #%d',
'%s moved the task #%d to the column "%s"' => '%s moveu a tarefa #%d para a coluna "%s"', '%s moved the task #%d to the column "%s"' => '%s moveu a tarefa #%d para a coluna "%s"',
'%s moved the task #%d to the position %d in the column "%s"' => '%s moveu a tarefa #%d para a posição %d na coluna "%s"', '%s moved the task #%d to the position %d in the column "%s"' => '%s moveu a tarefa #%d para a posição %d na coluna "%s"',
@ -498,108 +499,153 @@ return array(
'Default columns for new projects (Comma-separated)' => 'Colunas padrão para novos projetos (Separado por vírgula)', 'Default columns for new projects (Comma-separated)' => 'Colunas padrão para novos projetos (Separado por vírgula)',
'Task assignee change' => 'Mudar designação da tarefa', 'Task assignee change' => 'Mudar designação da tarefa',
'%s change the assignee of the task #%d to %s' => '%s mudou a designação da tarefa #%d para %s', '%s change the assignee of the task #%d to %s' => '%s mudou a designação da tarefa #%d para %s',
'%s change the assignee of the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to %s' => '%s mudou a designação da tarefa <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> para %s', '%s changed the assignee of the task %s to %s' => '%s mudou a designação da tarefa %s para %s',
// '[%s][Column Change] %s (#%d)' => '', '[%s][Column Change] %s (#%d)' => '[%s][Modificou Coluna] %s (#%d)',
// '[%s][Position Change] %s (#%d)' => '', '[%s][Position Change] %s (#%d)' => '[%s][Modificou Posição] %s (#%d)',
// '[%s][Assignee Change] %s (#%d)' => '', '[%s][Assignee Change] %s (#%d)' => '[%s][Modificou Designação] %s (#%d)',
'New password for the user "%s"' => 'Novo password para o usuário "%s"', 'New password for the user "%s"' => 'Nova senha para o usuário "%s"',
'Choose an event' => 'Escolher um evento', 'Choose an event' => 'Escolher um evento',
// 'Github commit received' => '', 'Github commit received' => 'Github commit received',
// 'Github issue opened' => '', 'Github issue opened' => 'Github issue opened',
// 'Github issue closed' => '', 'Github issue closed' => 'Github issue closed',
// 'Github issue reopened' => '', 'Github issue reopened' => 'Github issue reopened',
// 'Github issue assignee change' => '', 'Github issue assignee change' => 'Github issue assignee change',
// 'Github issue label change' => '', 'Github issue label change' => 'Github issue label change',
'Create a task from an external provider' => 'Criar uma tarefa a partir de um provedor externo', 'Create a task from an external provider' => 'Criar uma tarefa por meio de um serviço externo',
'Change the assignee based on an external username' => 'Alterar designação com vase em um usuário externo!', 'Change the assignee based on an external username' => 'Alterar designação com base em um usuário externo',
'Change the category based on an external label' => 'Alterar categoria com base em um rótulo externo', 'Change the category based on an external label' => 'Alterar categoria com base em um rótulo externo',
'Reference' => 'Referencia', 'Reference' => 'Referência',
'Reference: %s' => 'Referencia: %s', 'Reference: %s' => 'Referência: %s',
'Label' => 'Rótulo', 'Label' => 'Rótulo',
'Database' => 'Banco de dados', 'Database' => 'Banco de dados',
'About' => 'Sobre', 'About' => 'Sobre',
// 'Database driver:' => '', 'Database driver:' => 'Driver do banco de dados:',
// 'Board settings' => '', 'Board settings' => 'Configurações do Board',
// 'URL and token' => '', 'URL and token' => 'URL e token',
// 'Webhook settings' => '', 'Webhook settings' => 'Configurações do Webhook',
// 'URL for task creation:' => '', 'URL for task creation:' => 'URL para a criação da tarefa:',
// 'Reset token' => '', 'Reset token' => 'Resetar token',
// 'API endpoint:' => '', 'API endpoint:' => 'API endpoint:',
// 'Refresh interval for private board' => '', 'Refresh interval for private board' => 'Intervalo de atualização para um board privado',
// 'Refresh interval for public board' => '', 'Refresh interval for public board' => 'Intervalo de atualização para um board público',
// 'Task highlight period' => '', 'Task highlight period' => 'Período de Tarefa em destaque',
// 'Period (in second) to consider a task was modified recently (0 to disable, 2 days by default)' => '', 'Period (in second) to consider a task was modified recently (0 to disable, 2 days by default)' => 'Período (em segundos) para considerar que uma tarefa foi modificada recentemente (0 para desativar, 2 dias por padrão)',
// 'Frequency in second (60 seconds by default)' => '', 'Frequency in second (60 seconds by default)' => 'Frequência em segundos (60 segundos por padrão)',
// 'Frequency in second (0 to disable this feature, 10 seconds by default)' => '', 'Frequency in second (0 to disable this feature, 10 seconds by default)' => 'Frequência em segundos (0 para desativar este recurso, 10 segundos por padrão)',
'Application URL' => 'URL da Aplicação', 'Application URL' => 'URL da Aplicação',
// 'Example: http://example.kanboard.net/ (used by email notifications)' => '', 'Example: http://example.kanboard.net/ (used by email notifications)' => 'Exemplo: http://example.kanboard.net/ (utilizado nas notificações por e-mail)',
// 'Token regenerated.' => '', 'Token regenerated.' => 'Token ',
'Date format' => 'Formato de data', 'Date format' => 'Formato de data',
'ISO format is always accepted, example: "%s" and "%s"' => 'O formato ISO é sempre aceito, exemplo: "%s" e "%s"', 'ISO format is always accepted, example: "%s" and "%s"' => 'O formato ISO é sempre aceito, exemplo: "%s" e "%s"',
'New private project' => 'Novo projeto privado', 'New private project' => 'Novo projeto privado',
'This project is private' => 'Este projeto é privado', 'This project is private' => 'Este projeto é privado',
'Type here to create a new sub-task' => 'Digite aqui para criar uma nova sub-tarefa', 'Type here to create a new sub-task' => 'Digite aqui para criar uma nova subtarefa',
'Add' => 'Adicionar', 'Add' => 'Adicionar',
'Estimated time: %s hours' => 'Tempo estimado: %s horas', 'Estimated time: %s hours' => 'Tempo estimado: %s horas',
'Time spent: %s hours' => 'Tempo gasto: %s horas', 'Time spent: %s hours' => 'Tempo gasto: %s horas',
'Started on %B %e, %Y' => 'Iniciado em %B %e, %Y', 'Started on %B %e, %Y' => 'Iniciado em %B %e, %Y',
'Start date' => 'Data de início', 'Start date' => 'Data de início',
'Time estimated' => 'Tempo estimado', 'Time estimated' => 'Tempo estimado',
'There is nothing assigned to you.' => 'Não há nada designado para você.', 'There is nothing assigned to you.' => 'Não há nada designado à você.',
'My tasks' => 'Minhas tarefas', 'My tasks' => 'Minhas tarefas',
// 'Activity stream' => '', 'Activity stream' => 'Atividades Recentes',
// 'Dashboard' => '', 'Dashboard' => 'Painel de Controle',
'Confirmation' => 'Confirmação', 'Confirmation' => 'Confirmação',
'Allow everybody to access to this project' => 'Permitir que todos acessem este projeto', 'Allow everybody to access to this project' => 'Permitir que todos acessem este projeto',
'Everybody have access to this project.' => 'Todos possuem acesso a este projeto.', 'Everybody have access to this project.' => 'Todos possuem acesso a este projeto.',
// 'Webhooks' => '', 'Webhooks' => 'Webhooks',
// 'API' => '', 'API' => 'API',
'Integration' => 'Integração', 'Integration' => 'Integração',
// 'Github webhook' => '', 'Github webhooks' => 'Github webhooks',
'Help on Github webhook' => 'Ajuda para o Github webhook', 'Help on Github webhooks' => 'Ajuda para o Github webhooks',
'Create a comment from an external provider' => 'Criar um comentário de um provedor externo', 'Create a comment from an external provider' => 'Criar um comentário por meio de um serviço externo',
// 'Github issue comment created' => '', 'Github issue comment created' => 'Github issue comment created',
'Configure' => 'Configurar', 'Configure' => 'Configurar',
'Project management' => 'Gerenciamento de projetos', 'Project management' => 'Gerenciamento de projetos',
'My projects' => 'Meus projetos', 'My projects' => 'Meus projetos',
'Columns' => 'Colunas', 'Columns' => 'Colunas',
'Task' => 'Tarefas', 'Task' => 'Tarefas',
'Your are not member of any project.' => 'Você não é menmbro de nenhum projeto.', 'Your are not member of any project.' => 'Você não é membro de nenhum projeto.',
'Percentage' => 'Porcentagem', 'Percentage' => 'Porcentagem',
'Number of tasks' => 'Número de tarefas', 'Number of tasks' => 'Número de tarefas',
'Task distribution' => 'Distribuição de tarefas', 'Task distribution' => 'Distribuição de tarefas',
'Reportings' => 'Relatórios', 'Reportings' => 'Relatórios',
// 'Task repartition for "%s"' => '', 'Task repartition for "%s"' => 'Redistribuição da tarefa para "%s"',
'Analytics' => 'Estatísticas', 'Analytics' => 'Estatísticas',
'Subtask' => 'Sub-tarefa', 'Subtask' => 'Subtarefa',
'My subtasks' => 'Minhas sub-tarefas', 'My subtasks' => 'Minhas subtarefas',
'User repartition' => 'Repartição de usuário', 'User repartition' => 'Redistribuição de usuário',
'User repartition for "%s"' => 'Repartição de usuário para "%s"', 'User repartition for "%s"' => 'Redistribuição de usuário para "%s"',
'Clone this project' => 'Clonar o projeto', 'Clone this project' => 'Clonar este projeto',
'Column removed successfully.' => 'Coluna removida com sucesso.', 'Column removed successfully.' => 'Coluna removida com sucesso.',
'Edit Project' => 'Editar projeto', 'Edit Project' => 'Editar projeto',
// 'Github Issue' => '', 'Github Issue' => 'Github Issue',
'Not enough data to show the graph.' => 'Dados insuficientes para exibir o gráfico.', 'Not enough data to show the graph.' => 'Não há dados suficientes para mostrar o gráfico.',
'Previous' => 'Anterior', 'Previous' => 'Anterior',
'The id must be an integer' => 'A ID deve ser um inteiro', 'The id must be an integer' => 'O ID deve ser um número inteiro',
'The project id must be an integer' => 'A ID do projeto deve ser um inteiro', 'The project id must be an integer' => 'O ID do projeto deve ser um inteiro',
'The status must be an integer' => 'O status deve ser um inteiro', 'The status must be an integer' => 'O status deve ser um número inteiro',
'The subtask id is required' => 'A ID da sub-tarefa é requerida', 'The subtask id is required' => 'O ID da subtarefa é obrigatório',
'The subtask id must be an integer' => 'A ID da sub-tarefa deve ser um inteiro', 'The subtask id must be an integer' => 'O ID da subtarefa deve ser um número inteiro',
'The task id is required' => 'A ID da tarefa é requerida', 'The task id is required' => 'O ID da tarefa é obrigatório',
'The task id must be an integer' => 'A ID da tarefa deve ser um inteiro', 'The task id must be an integer' => 'O ID da tarefa deve ser um número inteiro',
'The user id must be an integer' => 'A ID de usuário deve ser um inteiro', 'The user id must be an integer' => 'O ID do usuário deve ser um número inteiro',
'This value is required' => 'Este valor é requerido', 'This value is required' => 'Este valor é obrigatório',
'This value must be numeric' => 'Este valor deve ser numérico', 'This value must be numeric' => 'Este valor deve ser numérico',
'Unable to create this task.' => 'Não foi possível criar esta tarefa.', 'Unable to create this task.' => 'Não foi possível criar esta tarefa.',
// 'Cumulative flow diagram' => '', 'Cumulative flow diagram' => 'Fluxograma cumulativo',
// 'Cumulative flow diagram for "%s"' => '', 'Cumulative flow diagram for "%s"' => 'Fluxograma cumulativo para "%s"',
// 'Daily project summary' => '', 'Daily project summary' => 'Resumo diário do projeto',
// 'Daily project summary export' => '', 'Daily project summary export' => 'Exportação diária do resumo do projeto',
// 'Daily project summary export for "%s"' => '', 'Daily project summary export for "%s"' => 'Exportação diária do resumo do projeto para "%s"',
// 'Exports' => '', 'Exports' => 'Exportar',
// 'This export contains the number of tasks per column grouped per day.' => '', 'This export contains the number of tasks per column grouped per day.' => '',
'Nothing to preview...' => 'Nada para pré-visualizar...', 'Nothing to preview...' => 'Nada para pré-visualizar...',
'Preview' => 'Pré-visualizar', 'Preview' => 'Pré-visualizar',
// 'Write' => '', 'Write' => 'Escrever',
'Active swimlanes' => 'Ativar swimlanes',
'Add a new swimlane' => 'Adicionar novo swimlane',
'Change default swimlane' => 'Alterar swimlane padrão',
'Default swimlane' => 'Swimlane padrão',
'Do you really want to remove this swimlane: "%s"?' => 'Você realmente deseja remover este swimlane: "%s"?',
'Inactive swimlanes' => 'Desativar swimlanes',
'Set project manager' => 'Definir gerente do projeto',
'Set project member' => 'Definir membro do projeto',
'Remove a swimlane' => 'Remover um swimlane',
'Rename' => 'Renomear',
'Show default swimlane' => 'Exibir swimlane padrão',
'Swimlane modification for the project "%s"' => 'Modificação de swimlane para o projeto "%s"',
'Swimlane not found.' => 'Swimlane não encontrado.',
'Swimlane removed successfully.' => 'Swimlane removido com sucesso.',
'Swimlanes' => 'Swimlanes',
'Swimlane updated successfully.' => 'Swimlane atualizado com sucesso.',
'The default swimlane have been updated successfully.' => 'O swimlane padrão foi atualizado com sucesso.',
'Unable to create your swimlane.' => 'Não foi possível criar o seu swimlane.',
'Unable to remove this swimlane.' => 'Não foi possível remover este swimlane.',
'Unable to update this swimlane.' => 'Não foi possível atualizar este swimlane.',
'Your swimlane have been created successfully.' => 'Seu swimlane foi criado com sucesso.',
'Example: "Bug, Feature Request, Improvement"' => 'Exemplo: "Bug, Feature Request, Improvement"',
'Default categories for new projects (Comma-separated)' => 'Categorias padrão para novos projetos (Separadas por vírgula)',
'Gitlab commit received' => 'Gitlab commit received',
'Gitlab issue opened' => 'Gitlab issue opened',
'Gitlab issue closed' => 'Gitlab issue closed',
'Gitlab webhooks' => 'Gitlab webhooks',
'Help on Gitlab webhooks' => 'Ajuda sobre Gitlab webhooks',
'Integrations' => 'Integrações',
'Integration with third-party services' => 'Integração com serviços de terceiros',
'Role for this project' => 'Função para este projeto',
'Project manager' => 'Gerente do projeto',
'Project member' => 'Membro do projeto',
'A project manager can change the settings of the project and have more privileges than a standard user.' => 'Um gerente do projeto pode alterar as configurações do projeto e ter mais privilégios que um usuário padrão.',
'Gitlab Issue' => 'Gitlab Issue',
'Subtask Id' => 'ID da subtarefa',
'Subtasks' => 'Subtarefas',
'Subtasks Export' => 'Exportar subtarefas',
'Subtasks exportation for "%s"' => 'Subtarefas exportadas para "%s"',
'Task Title' => 'Título da Tarefa',
'Untitled' => 'Sem título',
'Application default' => 'Aplicação padrão',
'Language:' => 'Idioma',
'Timezone:' => 'Fuso horário',
'Next' => 'Próximo',
); );

View file

@ -182,7 +182,7 @@ return array(
'Change assignee' => 'Сменить назначенного', 'Change assignee' => 'Сменить назначенного',
'Change assignee for the task "%s"' => 'Сменить назначенного для задачи « %s »', 'Change assignee for the task "%s"' => 'Сменить назначенного для задачи « %s »',
'Timezone' => 'Часовой пояс', 'Timezone' => 'Часовой пояс',
'Sorry, I didn\'t found this information in my database!' => 'К сожалению, информация в базе данных не найдена !', 'Sorry, I didn\'t find this information in my database!' => 'К сожалению, информация в базе данных не найдена !',
'Page not found' => 'Страница не найдена', 'Page not found' => 'Страница не найдена',
'Complexity' => 'Сложность', 'Complexity' => 'Сложность',
'limit' => 'лимит', 'limit' => 'лимит',
@ -194,7 +194,7 @@ return array(
'Allow this user' => 'Разрешить этого пользователя', 'Allow this user' => 'Разрешить этого пользователя',
'Only those users have access to this project:' => 'Только эти пользователи имеют доступ к проекту :', 'Only those users have access to this project:' => 'Только эти пользователи имеют доступ к проекту :',
'Don\'t forget that administrators have access to everything.' => 'Помните, администратор имеет доступ ко всему.', 'Don\'t forget that administrators have access to everything.' => 'Помните, администратор имеет доступ ко всему.',
'revoke' => 'отозвать', 'Revoke' => 'отозвать',
'List of authorized users' => 'Список авторизованных пользователей', 'List of authorized users' => 'Список авторизованных пользователей',
'User' => 'Пользователь', 'User' => 'Пользователь',
'Nobody have access to this project.' => 'Ни у кого нет доступа к этому проекту', 'Nobody have access to this project.' => 'Ни у кого нет доступа к этому проекту',
@ -213,6 +213,7 @@ return array(
'Invalid date' => 'Неверная дата', 'Invalid date' => 'Неверная дата',
'Must be done before %B %e, %Y' => 'Должно быть сделано до %d/%m/%Y', 'Must be done before %B %e, %Y' => 'Должно быть сделано до %d/%m/%Y',
'%B %e, %Y' => '%d/%m/%Y', '%B %e, %Y' => '%d/%m/%Y',
// '%b %e, %Y' => '',
'Automatic actions' => 'Автоматические действия', 'Automatic actions' => 'Автоматические действия',
'Your automatic action have been created successfully.' => 'Автоматика настроена.', 'Your automatic action have been created successfully.' => 'Автоматика настроена.',
'Unable to create your automatic action.' => 'Не удалось создать автоматизированное действие.', 'Unable to create your automatic action.' => 'Не удалось создать автоматизированное действие.',
@ -468,18 +469,18 @@ return array(
'Unable to change the password.' => 'Не удалось сменить пароль.', 'Unable to change the password.' => 'Не удалось сменить пароль.',
'Change category for the task "%s"' => 'Сменить категорию для задачи "%s"', 'Change category for the task "%s"' => 'Сменить категорию для задачи "%s"',
'Change category' => 'Смена категории', 'Change category' => 'Смена категории',
'%s updated the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s обновил задачу <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s updated the task %s' => '%s обновил задачу %s',
'%s open the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s открыл задачу <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s opened the task %s' => '%s открыл задачу %s',
'%s moved the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to the position #%d in the column "%s"' => '%s перместил задачу <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> на позицию #%d в колонке "%s"', '%s moved the task %s to the position #%d in the column "%s"' => '%s перместил задачу %s на позицию #%d в колонке "%s"',
'%s moved the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to the column "%s"' => '%s переместил задачу <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> в колонку "%s"', '%s moved the task %s to the column "%s"' => '%s переместил задачу %s в колонку "%s"',
'%s created the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s создал задачу <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s created the task %s' => '%s создал задачу %s',
'%s closed the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s закрыл задачу <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s closed the task %s' => '%s закрыл задачу %s',
'%s created a subtask for the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s создал подзадачу для задачи <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s created a subtask for the task %s' => '%s создал подзадачу для задачи %s',
'%s updated a subtask for the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s обновил подзадачу для задачи <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s updated a subtask for the task %s' => '%s обновил подзадачу для задачи %s',
'Assigned to %s with an estimate of %s/%sh' => 'Назначено %s с окончанием %s/%sh', 'Assigned to %s with an estimate of %s/%sh' => 'Назначено %s с окончанием %s/%sh',
'Not assigned, estimate of %sh' => 'Не назначено, окончание %sh', 'Not assigned, estimate of %sh' => 'Не назначено, окончание %sh',
'%s updated a comment on the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s обновил комментарий к задаче <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s updated a comment on the task %s' => '%s обновил комментарий к задаче %s',
'%s commented the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s прокомментировал задачу <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s commented the task %s' => '%s прокомментировал задачу %s',
'%s\'s activity' => '%s активность', '%s\'s activity' => '%s активность',
'No activity.' => 'Нет активности', 'No activity.' => 'Нет активности',
'RSS feed' => 'RSS лента', 'RSS feed' => 'RSS лента',
@ -498,7 +499,7 @@ return array(
'Default columns for new projects (Comma-separated)' => 'Колонки по умолчанию для новых проектов (разделять запятой)', 'Default columns for new projects (Comma-separated)' => 'Колонки по умолчанию для новых проектов (разделять запятой)',
'Task assignee change' => 'Изменен назначенный', 'Task assignee change' => 'Изменен назначенный',
'%s change the assignee of the task #%d to %s' => '%s сменил назначенного для задачи #%d на %s', '%s change the assignee of the task #%d to %s' => '%s сменил назначенного для задачи #%d на %s',
'%s change the assignee of the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to %s' => '%s сменил назначенного для задачи <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> на %s', '%s changed the assignee of the task %s to %s' => '%s сменил назначенного для задачи %s на %s',
'[%s][Column Change] %s (#%d)' => '[%s][Изменение колонки] %s (#%d)', '[%s][Column Change] %s (#%d)' => '[%s][Изменение колонки] %s (#%d)',
'[%s][Position Change] %s (#%d)' => '[%s][Изменение позиции] %s (#%d)', '[%s][Position Change] %s (#%d)' => '[%s][Изменение позиции] %s (#%d)',
'[%s][Assignee Change] %s (#%d)' => '[%s][Изменение назначеного] %s (#%d)', '[%s][Assignee Change] %s (#%d)' => '[%s][Изменение назначеного] %s (#%d)',
@ -555,8 +556,8 @@ return array(
// 'Webhooks' => '', // 'Webhooks' => '',
// 'API' => '', // 'API' => '',
// 'Integration' => '', // 'Integration' => '',
// 'Github webhook' => '', // 'Github webhooks' => '',
// 'Help on Github webhook' => '', // 'Help on Github webhooks' => '',
// 'Create a comment from an external provider' => '', // 'Create a comment from an external provider' => '',
// 'Github issue comment created' => '', // 'Github issue comment created' => '',
// 'Configure' => '', // 'Configure' => '',
@ -602,4 +603,49 @@ return array(
// 'Nothing to preview...' => '', // 'Nothing to preview...' => '',
// 'Preview' => '', // 'Preview' => '',
// 'Write' => '', // 'Write' => '',
// 'Active swimlanes' => '',
// 'Add a new swimlane' => '',
// 'Change default swimlane' => '',
// 'Default swimlane' => '',
// 'Do you really want to remove this swimlane: "%s"?' => '',
// 'Inactive swimlanes' => '',
// 'Set project manager' => '',
// 'Set project member' => '',
// 'Remove a swimlane' => '',
// 'Rename' => '',
// 'Show default swimlane' => '',
// 'Swimlane modification for the project "%s"' => '',
// 'Swimlane not found.' => '',
// 'Swimlane removed successfully.' => '',
// 'Swimlanes' => '',
// 'Swimlane updated successfully.' => '',
// 'The default swimlane have been updated successfully.' => '',
// 'Unable to create your swimlane.' => '',
// 'Unable to remove this swimlane.' => '',
// 'Unable to update this swimlane.' => '',
// 'Your swimlane have been created successfully.' => '',
// 'Example: "Bug, Feature Request, Improvement"' => '',
// 'Default categories for new projects (Comma-separated)' => '',
// 'Gitlab commit received' => '',
// 'Gitlab issue opened' => '',
// 'Gitlab issue closed' => '',
// 'Gitlab webhooks' => '',
// 'Help on Gitlab webhooks' => '',
// 'Integrations' => '',
// 'Integration with third-party services' => '',
// 'Role for this project' => '',
// 'Project manager' => '',
// 'Project member' => '',
// 'A project manager can change the settings of the project and have more privileges than a standard user.' => '',
// 'Gitlab Issue' => '',
// 'Subtask Id' => '',
// 'Subtasks' => '',
// 'Subtasks Export' => '',
// 'Subtasks exportation for "%s"' => '',
// 'Task Title' => '',
// 'Untitled' => '',
// 'Application default' => '',
// 'Language:' => '',
// 'Timezone:' => '',
// 'Next' => '',
); );

View file

@ -104,7 +104,7 @@ return array(
'Open a task' => 'Öppna en uppgift', 'Open a task' => 'Öppna en uppgift',
'Do you really want to open this task: "%s"?' => 'Vill du verkligen öppna denna uppgift: "%s"?', 'Do you really want to open this task: "%s"?' => 'Vill du verkligen öppna denna uppgift: "%s"?',
'Back to the board' => 'Tillbaka till tavlan', 'Back to the board' => 'Tillbaka till tavlan',
'Created on %B %e, %Y at %k:%M %p' => 'Skapad %d %B %Y kl %H:%M', 'Created on %B %e, %Y at %k:%M %p' => 'Skapad %Y-%m-%d kl %H:%M',
'There is nobody assigned' => 'Det finns ingen tilldelad', 'There is nobody assigned' => 'Det finns ingen tilldelad',
'Column on the board:' => 'Kolumn på tavlan:', 'Column on the board:' => 'Kolumn på tavlan:',
'Status is open' => 'Statusen är öppen', 'Status is open' => 'Statusen är öppen',
@ -166,8 +166,8 @@ return array(
'Work in progress' => 'Pågående', 'Work in progress' => 'Pågående',
'Done' => 'Slutfört', 'Done' => 'Slutfört',
'Application version:' => 'Version:', 'Application version:' => 'Version:',
'Completed on %B %e, %Y at %k:%M %p' => 'Slutfört %d %B %Y kl %H:%M', 'Completed on %B %e, %Y at %k:%M %p' => 'Slutfört %Y-%m-%d kl %H:%M',
'%B %e, %Y at %k:%M %p' => '%d %B %Y kl %H:%M', '%B %e, %Y at %k:%M %p' => '%Y-%m-%d kl %H:%M',
'Date created' => 'Skapat datum', 'Date created' => 'Skapat datum',
'Date completed' => 'Slutfört datum', 'Date completed' => 'Slutfört datum',
'Id' => 'ID', 'Id' => 'ID',
@ -182,19 +182,19 @@ return array(
'Change assignee' => 'Ändra uppdragsinnehavare', 'Change assignee' => 'Ändra uppdragsinnehavare',
'Change assignee for the task "%s"' => 'Ändra uppdragsinnehavare för uppgiften "%s"', 'Change assignee for the task "%s"' => 'Ändra uppdragsinnehavare för uppgiften "%s"',
'Timezone' => 'Tidszon', 'Timezone' => 'Tidszon',
'Sorry, I didn\'t found this information in my database!' => 'Informationen kunde inte hittas i databasen.', 'Sorry, I didn\'t find this information in my database!' => 'Informationen kunde inte hittas i databasen.',
'Page not found' => 'Sidan hittas inte', 'Page not found' => 'Sidan hittas inte',
'Complexity' => 'Ungefärligt antal timmar', 'Complexity' => 'Komplexitet',
'limit' => 'max', 'limit' => 'max',
'Task limit' => 'Uppgiftsbegränsning', 'Task limit' => 'Uppgiftsbegränsning',
// 'Task count' => '', 'Task count' => 'Antal uppgifter',
'This value must be greater than %d' => 'Värdet måste vara större än %d', 'This value must be greater than %d' => 'Värdet måste vara större än %d',
'Edit project access list' => 'Ändra projektåtkomst lista', 'Edit project access list' => 'Ändra projektåtkomst lista',
'Edit users access' => 'Användaråtkomst', 'Edit users access' => 'Användaråtkomst',
'Allow this user' => 'Tillåt användare', 'Allow this user' => 'Tillåt användare',
'Only those users have access to this project:' => 'Bara de användarna har tillgång till detta projekt.', 'Only those users have access to this project:' => 'Bara de användarna har tillgång till detta projekt.',
'Don\'t forget that administrators have access to everything.' => 'Glöm inte att administratörerna har rätt att göra allt.', 'Don\'t forget that administrators have access to everything.' => 'Glöm inte att administratörerna har rätt att göra allt.',
'revoke' => 'Dra tillbaka behörighet', 'Revoke' => 'Dra tillbaka behörighet',
'List of authorized users' => 'Lista med behöriga användare', 'List of authorized users' => 'Lista med behöriga användare',
'User' => 'Användare', 'User' => 'Användare',
'Nobody have access to this project.' => 'Ingen har tillgång till detta projekt.', 'Nobody have access to this project.' => 'Ingen har tillgång till detta projekt.',
@ -211,8 +211,9 @@ return array(
'Edit this task' => 'Ändra denna uppgift', 'Edit this task' => 'Ändra denna uppgift',
'Due Date' => 'Måldatum', 'Due Date' => 'Måldatum',
'Invalid date' => 'Ej tillåtet datum', 'Invalid date' => 'Ej tillåtet datum',
'Must be done before %B %e, %Y' => 'Måste vara klart innan %B %e, %Y', 'Must be done before %B %e, %Y' => 'Måste vara klart innan %Y-%m-%d',
'%B %e, %Y' => '%d %B %Y', '%B %e, %Y' => '%Y-%m-%d',
'%b %e, %Y' => '%Y-%m-%d',
'Automatic actions' => 'Automatiska åtgärder', 'Automatic actions' => 'Automatiska åtgärder',
'Your automatic action have been created successfully.' => 'Din automatiska åtgärd har skapats.', 'Your automatic action have been created successfully.' => 'Din automatiska åtgärd har skapats.',
'Unable to create your automatic action.' => 'Kunde inte skapa din automatiska åtgärd.', 'Unable to create your automatic action.' => 'Kunde inte skapa din automatiska åtgärd.',
@ -376,7 +377,7 @@ return array(
'Link my GitHub Account' => 'Anslut mitt GitHub-konto', 'Link my GitHub Account' => 'Anslut mitt GitHub-konto',
'Unlink my GitHub Account' => 'Koppla ifrån mitt GitHub-konto', 'Unlink my GitHub Account' => 'Koppla ifrån mitt GitHub-konto',
'Created by %s' => 'Skapad av %s', 'Created by %s' => 'Skapad av %s',
'Last modified on %B %e, %Y at %k:%M %p' => 'Senaste ändring %B %e, %Y kl %k:%M %p', 'Last modified on %B %e, %Y at %k:%M %p' => 'Senaste ändring %Y-%m-%d kl %H:%M',
'Tasks Export' => 'Exportera uppgifter', 'Tasks Export' => 'Exportera uppgifter',
'Tasks exportation for "%s"' => 'Exportera uppgifter för "%s"', 'Tasks exportation for "%s"' => 'Exportera uppgifter för "%s"',
'Start Date' => 'Startdatum', 'Start Date' => 'Startdatum',
@ -468,18 +469,18 @@ return array(
'Unable to change the password.' => 'Kunde inte byta lösenord.', 'Unable to change the password.' => 'Kunde inte byta lösenord.',
'Change category for the task "%s"' => 'Byt kategori för uppgiften "%s"', 'Change category for the task "%s"' => 'Byt kategori för uppgiften "%s"',
'Change category' => 'Byt kategori', 'Change category' => 'Byt kategori',
'%s updated the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s uppdaterade uppgiften <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s updated the task %s' => '%s uppdaterade uppgiften %s',
'%s open the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s öppna uppgiften <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s opened the task %s' => '%s öppna uppgiften %s',
'%s moved the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to the position #%d in the column "%s"' => '%s flyttade uppgiften <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> till positionen #%d i kolumnen "%s"', '%s moved the task %s to the position #%d in the column "%s"' => '%s flyttade uppgiften %s till positionen #%d i kolumnen "%s"',
'%s moved the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to the column "%s"' => '%s flyttade uppgiften <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> till kolumnen "%s"', '%s moved the task %s to the column "%s"' => '%s flyttade uppgiften %s till kolumnen "%s"',
'%s created the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s skapade uppgiften <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s created the task %s' => '%s skapade uppgiften %s',
'%s closed the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s stängde uppgiften <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s closed the task %s' => '%s stängde uppgiften %s',
'%s created a subtask for the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s skapade en deluppgift för uppgiften <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s created a subtask for the task %s' => '%s skapade en deluppgift för uppgiften %s',
'%s updated a subtask for the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s uppdaterade en deluppgift för uppgiften <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s updated a subtask for the task %s' => '%s uppdaterade en deluppgift för uppgiften %s',
'Assigned to %s with an estimate of %s/%sh' => 'Tilldelades %s med en uppskattning på %s/%sh', 'Assigned to %s with an estimate of %s/%sh' => 'Tilldelades %s med en uppskattning på %s/%sh',
'Not assigned, estimate of %sh' => 'Inte tilldelade, uppskattat %sh', 'Not assigned, estimate of %sh' => 'Inte tilldelade, uppskattat %sh',
'%s updated a comment on the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s uppdaterade en kommentar till uppgiften <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s updated a comment on the task %s' => '%s uppdaterade en kommentar till uppgiften %s',
'%s commented the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s kommenterade uppgiften <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s commented the task %s' => '%s kommenterade uppgiften %s',
'%s\'s activity' => '%s\'s aktivitet', '%s\'s activity' => '%s\'s aktivitet',
'No activity.' => 'Ingen aktivitet.', 'No activity.' => 'Ingen aktivitet.',
'RSS feed' => 'RSS flöde', 'RSS feed' => 'RSS flöde',
@ -498,7 +499,7 @@ return array(
'Default columns for new projects (Comma-separated)' => 'Standardkolumner för nya projekt (kommaseparerade)', 'Default columns for new projects (Comma-separated)' => 'Standardkolumner för nya projekt (kommaseparerade)',
'Task assignee change' => 'Ändra tilldelning av uppgiften', 'Task assignee change' => 'Ändra tilldelning av uppgiften',
'%s change the assignee of the task #%d to %s' => '%s byt tilldelning av uppgiften #%d till %s', '%s change the assignee of the task #%d to %s' => '%s byt tilldelning av uppgiften #%d till %s',
'%s change the assignee of the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to %s' => '%s byt tilldelning av uppgiften <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> till %s', '%s changed the assignee of the task %s to %s' => '%s byt tilldelning av uppgiften %s till %s',
'[%s][Column Change] %s (#%d)' => '[%s][Byt kolumn] %s (#%d)', '[%s][Column Change] %s (#%d)' => '[%s][Byt kolumn] %s (#%d)',
'[%s][Position Change] %s (#%d)' => '[%s][Byt position] %s (#%d)', '[%s][Position Change] %s (#%d)' => '[%s][Byt position] %s (#%d)',
'[%s][Assignee Change] %s (#%d)' => '[%s][Byt tilldelning] %s (#%d)', '[%s][Assignee Change] %s (#%d)' => '[%s][Byt tilldelning] %s (#%d)',
@ -542,64 +543,109 @@ return array(
'Add' => 'Lägg till', 'Add' => 'Lägg till',
'Estimated time: %s hours' => 'Uppskattad tid: %s timmar', 'Estimated time: %s hours' => 'Uppskattad tid: %s timmar',
'Time spent: %s hours' => 'Nedlaggd tid: %s timmar', 'Time spent: %s hours' => 'Nedlaggd tid: %s timmar',
'Started on %B %e, %Y' => 'Startad den %B %e, %Y', 'Started on %B %e, %Y' => 'Startad %Y-%m-%d',
'Start date' => 'Startdatum', 'Start date' => 'Startdatum',
'Time estimated' => 'Uppskattad tid', 'Time estimated' => 'Uppskattad tid',
'There is nothing assigned to you.' => 'Du har inget tilldelat till dig.', 'There is nothing assigned to you.' => 'Du har inget tilldelat till dig.',
'My tasks' => 'Mina uppgifte', 'My tasks' => 'Mina uppgifter',
'Activity stream' => 'Aktivitetsström', 'Activity stream' => 'Aktivitetsström',
'Dashboard' => 'Instrumentpanel', 'Dashboard' => 'Instrumentpanel',
'Confirmation' => 'Bekräftelse', 'Confirmation' => 'Bekräftelse',
// 'Allow everybody to access to this project' => '', 'Allow everybody to access to this project' => 'Ge alla tillgång till projektet',
// 'Everybody have access to this project.' => '', 'Everybody have access to this project.' => 'Alla har tillgång till projektet',
// 'Webhooks' => '', 'Webhooks' => 'Webhooks',
// 'API' => '', 'API' => 'API',
// 'Integration' => '', 'Integration' => 'Integration',
// 'Github webhook' => '', 'Github webhooks' => 'Github webhooks',
// 'Help on Github webhook' => '', 'Help on Github webhooks' => 'Hjälp för Github webhooks',
// 'Create a comment from an external provider' => '', 'Create a comment from an external provider' => 'Skapa en kommentar från en extern leverantör',
// 'Github issue comment created' => '', 'Github issue comment created' => 'Github frågekommentar skapad',
// 'Configure' => '', 'Configure' => 'Konfigurera',
// 'Project management' => '', 'Project management' => 'Projekthantering',
// 'My projects' => '', 'My projects' => 'Mina projekt',
// 'Columns' => '', 'Columns' => 'Kolumner',
// 'Task' => '', 'Task' => 'Uppgift',
// 'Your are not member of any project.' => '', 'Your are not member of any project.' => 'Du är inte medlem i något projekt',
// 'Percentage' => '', 'Percentage' => 'Procent',
// 'Number of tasks' => '', 'Number of tasks' => 'Antal uppgifter',
// 'Task distribution' => '', 'Task distribution' => 'Uppgiftsfördelning',
// 'Reportings' => '', 'Reportings' => 'Rapportering',
// 'Task repartition for "%s"' => '', 'Task repartition for "%s"' => 'Uppgiftsdeltagande för "%s"',
// 'Analytics' => '', 'Analytics' => 'Analyser',
// 'Subtask' => '', 'Subtask' => 'Deluppgift',
// 'My subtasks' => '', 'My subtasks' => 'Mina deluppgifter',
// 'User repartition' => '', 'User repartition' => 'Användardeltagande',
// 'User repartition for "%s"' => '', 'User repartition for "%s"' => 'Användardeltagande för "%s"',
// 'Clone this project' => '', 'Clone this project' => 'Klona projektet',
// 'Column removed successfully.' => '', 'Column removed successfully.' => 'Kolumnen togs bort',
// 'Edit Project' => '', 'Edit Project' => 'Ändra Projekt',
// 'Github Issue' => '', 'Github Issue' => 'Github fråga',
// 'Not enough data to show the graph.' => '', 'Not enough data to show the graph.' => 'Inte tillräckligt med data för att visa graf',
// 'Previous' => '', 'Previous' => 'Föregående',
// 'The id must be an integer' => '', 'The id must be an integer' => 'ID måste vara ett heltal',
// 'The project id must be an integer' => '', 'The project id must be an integer' => 'Projekt-ID måste vara ett heltal',
// 'The status must be an integer' => '', 'The status must be an integer' => 'Status måste vara ett heltal',
// 'The subtask id is required' => '', 'The subtask id is required' => 'Deluppgifts-ID behövs',
// 'The subtask id must be an integer' => '', 'The subtask id must be an integer' => 'Deluppgifts-ID måste vara ett heltal',
// 'The task id is required' => '', 'The task id is required' => 'Uppgifts-ID behövs',
// 'The task id must be an integer' => '', 'The task id must be an integer' => 'Uppgifts-ID måste vara ett heltal',
// 'The user id must be an integer' => '', 'The user id must be an integer' => 'Användar-ID måste vara ett heltal',
// 'This value is required' => '', 'This value is required' => 'Värdet behövs',
// 'This value must be numeric' => '', 'This value must be numeric' => 'Värdet måste vara numeriskt',
// 'Unable to create this task.' => '', 'Unable to create this task.' => 'Kunde inte skapa uppgiften.',
// 'Cumulative flow diagram' => '', 'Cumulative flow diagram' => 'Diagram med kumulativt flöde',
// 'Cumulative flow diagram for "%s"' => '', 'Cumulative flow diagram for "%s"' => 'Diagram med kumulativt flöde för "%s"',
// 'Daily project summary' => '', 'Daily project summary' => 'Daglig projektsummering',
// 'Daily project summary export' => '', 'Daily project summary export' => 'Export av daglig projektsummering',
// 'Daily project summary export for "%s"' => '', 'Daily project summary export for "%s"' => 'Export av daglig projektsummering för "%s"',
// 'Exports' => '', 'Exports' => 'Exporter',
// 'This export contains the number of tasks per column grouped per day.' => '', 'This export contains the number of tasks per column grouped per day.' => 'Denna export innehåller antalet uppgifter per kolumn grupperade per dag.',
// 'Nothing to preview...' => '', 'Nothing to preview...' => 'Inget att förhandsgrandska...',
// 'Preview' => '', 'Preview' => 'Förhandsgranska',
// 'Write' => '', 'Write' => 'Skriva',
'Active swimlanes' => 'Aktiva swimlanes',
'Add a new swimlane' => 'Lägg till en nytt swimlane',
'Change default swimlane' => 'Ändra standard swimlane',
'Default swimlane' => 'Standard swimlane',
'Do you really want to remove this swimlane: "%s"?' => 'Vill du verkligen ta bort denna swimlane: "%s"?',
'Inactive swimlanes' => 'Inaktiv swimlane',
'Set project manager' => 'Sätt Projektadministratör',
'Set project member' => 'Sätt projektmedlem',
'Remove a swimlane' => 'Ta bort en swimlane',
'Rename' => 'Byt namn',
'Show default swimlane' => 'Visa standard swimlane',
'Swimlane modification for the project "%s"' => 'Ändra swimlane för projektet "%s"',
'Swimlane not found.' => 'Swimlane kunde inte hittas',
'Swimlane removed successfully.' => 'Swimlane togs bort',
'Swimlanes' => 'Swimlanes',
'Swimlane updated successfully.' => 'Swimlane uppdaterad',
'The default swimlane have been updated successfully.' => 'Standardswimlane har uppdaterats',
'Unable to create your swimlane.' => 'Kunde inte skapa din swimlane',
'Unable to remove this swimlane.' => 'Kunde inte ta bort swimlane',
'Unable to update this swimlane.' => 'Kunde inte uppdatera swimlane',
'Your swimlane have been created successfully.' => 'Din swimlane har skapats',
'Example: "Bug, Feature Request, Improvement"' => 'Exempel: "Bug, ny funktionalitet, förbättringar"',
'Default categories for new projects (Comma-separated)' => 'Standardkategorier för nya projekt (komma-separerade)',
'Gitlab commit received' => 'Gitlab bidrag mottaget',
'Gitlab issue opened' => 'Gitlab fråga öppnad',
'Gitlab issue closed' => 'Gitlab fråga stängd',
'Gitlab webhooks' => 'Gitlab webhooks',
'Help on Gitlab webhooks' => 'Hjälp för Gitlab webhooks',
'Integrations' => 'Integrationer',
'Integration with third-party services' => 'Integration med tjänst från tredjepart',
'Role for this project' => 'Roll för detta projekt',
'Project manager' => 'Projektadministratör',
'Project member' => 'Projektmedlem',
'A project manager can change the settings of the project and have more privileges than a standard user.' => 'En projektadministratör kan ändra inställningar för projektet och har mer rättigheter än en standardanvändare.',
'Gitlab Issue' => 'Gitlab fråga',
'Subtask Id' => 'Deluppgifts-ID',
'Subtasks' => 'Deluppgift',
'Subtasks Export' => 'Export av deluppgifter',
'Subtasks exportation for "%s"' => 'Export av deluppgifter för "%s"',
'Task Title' => 'Uppgiftstitel',
'Untitled' => 'Titel saknas',
'Application default' => 'Applikationsstandard',
'Language:' => 'Språk',
'Timezone:' => 'Tidszon',
'Next' => 'Nästa',
); );

View file

@ -182,7 +182,7 @@ return array(
'Change assignee' => 'เปลี่ยนการกำหนด', 'Change assignee' => 'เปลี่ยนการกำหนด',
'Change assignee for the task "%s"' => 'เปลี่ยนการกำหนดสำหรับงาน « %s »', 'Change assignee for the task "%s"' => 'เปลี่ยนการกำหนดสำหรับงาน « %s »',
'Timezone' => 'เขตเวลา', 'Timezone' => 'เขตเวลา',
'Sorry, I didn\'t found this information in my database!' => 'เสียใจด้วย ไม่สามารถหาข้อมูลในฐานข้อมูลได้', 'Sorry, I didn\'t find this information in my database!' => 'เสียใจด้วย ไม่สามารถหาข้อมูลในฐานข้อมูลได้',
'Page not found' => 'ไม่พบหน้า', 'Page not found' => 'ไม่พบหน้า',
'Complexity' => 'ความซับซ้อน', 'Complexity' => 'ความซับซ้อน',
'limit' => 'จำกัด', 'limit' => 'จำกัด',
@ -194,7 +194,7 @@ return array(
'Allow this user' => 'อนุญาตผู้ใช้นี้', 'Allow this user' => 'อนุญาตผู้ใช้นี้',
'Only those users have access to this project:' => 'ผู้ใช้ที่สามารถเข้าถึงโปรเจคนี้:', 'Only those users have access to this project:' => 'ผู้ใช้ที่สามารถเข้าถึงโปรเจคนี้:',
'Don\'t forget that administrators have access to everything.' => 'อย่าลืมผู้ดูแลระบบสามารถเข้าถึงได้ทุกอย่าง', 'Don\'t forget that administrators have access to everything.' => 'อย่าลืมผู้ดูแลระบบสามารถเข้าถึงได้ทุกอย่าง',
'revoke' => 'ยกเลิก', 'Revoke' => 'ยกเลิก',
'List of authorized users' => 'รายชื่อผู้ใช้ที่ได้รับการยืนยัน', 'List of authorized users' => 'รายชื่อผู้ใช้ที่ได้รับการยืนยัน',
'User' => 'ผู้ใช้', 'User' => 'ผู้ใช้',
// 'Nobody have access to this project.' => '', // 'Nobody have access to this project.' => '',
@ -213,6 +213,7 @@ return array(
'Invalid date' => 'วันที่ผิด', 'Invalid date' => 'วันที่ผิด',
'Must be done before %B %e, %Y' => 'ต้องทำให้เสร็จก่อน %d/%m/%Y', 'Must be done before %B %e, %Y' => 'ต้องทำให้เสร็จก่อน %d/%m/%Y',
'%B %e, %Y' => '%d/%m/%Y', '%B %e, %Y' => '%d/%m/%Y',
// '%b %e, %Y' => '',
'Automatic actions' => 'การกระทำอัตโนมัติ', 'Automatic actions' => 'การกระทำอัตโนมัติ',
'Your automatic action have been created successfully.' => 'การกระทำอัตโนมัติสร้างเรียบร้อยแล้ว', 'Your automatic action have been created successfully.' => 'การกระทำอัตโนมัติสร้างเรียบร้อยแล้ว',
'Unable to create your automatic action.' => 'ไม่สามารถสร้างการกระทำอัตโนมัติได้', 'Unable to create your automatic action.' => 'ไม่สามารถสร้างการกระทำอัตโนมัติได้',
@ -468,18 +469,18 @@ return array(
'Unable to change the password.' => 'ไม่สามารถเปลี่ยนรหัสผ่านได้', 'Unable to change the password.' => 'ไม่สามารถเปลี่ยนรหัสผ่านได้',
'Change category for the task "%s"' => 'เปลี่ยนกลุ่มสำหรับงาน "%s"', 'Change category for the task "%s"' => 'เปลี่ยนกลุ่มสำหรับงาน "%s"',
'Change category' => 'เปลี่ยนกลุ่ม', 'Change category' => 'เปลี่ยนกลุ่ม',
'%s updated the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s ปรับปรุงงานแล้ว <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s updated the task %s' => '%s ปรับปรุงงานแล้ว %s',
'%s open the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s เปิดงานแล้ว <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s opened the task %s' => '%s เปิดงานแล้ว %s',
'%s moved the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to the position #%d in the column "%s"' => '%s ย้ายงานแล้ว <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> ไปตำแหน่ง #%d ในคอลัมน์ "%s"', '%s moved the task %s to the position #%d in the column "%s"' => '%s ย้ายงานแล้ว %s ไปตำแหน่ง #%d ในคอลัมน์ "%s"',
'%s moved the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to the column "%s"' => '%s ย้ายงานแล้ว <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> ไปคอลัมน์ "%s"', '%s moved the task %s to the column "%s"' => '%s ย้ายงานแล้ว %s ไปคอลัมน์ "%s"',
'%s created the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s สร้างงานแล้ว <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s created the task %s' => '%s สร้างงานแล้ว %s',
'%s closed the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s ปิดงานแล้ว <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s closed the task %s' => '%s ปิดงานแล้ว %s',
'%s created a subtask for the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s สร้างงานย่อยสำหรับงานแล้ว <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s created a subtask for the task %s' => '%s สร้างงานย่อยสำหรับงานแล้ว %s',
'%s updated a subtask for the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s ปรับปรุงงานย่อยสำหรับงานแล้ว <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s updated a subtask for the task %s' => '%s ปรับปรุงงานย่อยสำหรับงานแล้ว %s',
'Assigned to %s with an estimate of %s/%sh' => 'กำหนดให้ %s โดยประมาณแล้ว %s/%sh', 'Assigned to %s with an estimate of %s/%sh' => 'กำหนดให้ %s โดยประมาณแล้ว %s/%sh',
'Not assigned, estimate of %sh' => 'ไม่กำหนดแล้ว, ประมาณเวลาที่ใช้ %s ชั่วโมง', 'Not assigned, estimate of %sh' => 'ไม่กำหนดแล้ว, ประมาณเวลาที่ใช้ %s ชั่วโมง',
'%s updated a comment on the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s ปรับปรุงความคิดเห็นในงานแล้ว <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s updated a comment on the task %s' => '%s ปรับปรุงความคิดเห็นในงานแล้ว %s',
'%s commented the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s แสดงความคิดเห็นของงานแล้ว <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s commented the task %s' => '%s แสดงความคิดเห็นของงานแล้ว %s',
'%s\'s activity' => 'กิจกรรม %s', '%s\'s activity' => 'กิจกรรม %s',
'No activity.' => 'ไม่มีกิจกรรม', 'No activity.' => 'ไม่มีกิจกรรม',
'RSS feed' => 'RSS feed', 'RSS feed' => 'RSS feed',
@ -498,7 +499,7 @@ return array(
'Default columns for new projects (Comma-separated)' => 'คอลัมน์เริ่มต้นสำหรับโปรเจคใหม่ (Comma-separated)', 'Default columns for new projects (Comma-separated)' => 'คอลัมน์เริ่มต้นสำหรับโปรเจคใหม่ (Comma-separated)',
'Task assignee change' => 'เปลี่ยนการกำหนดบุคคลของงาน', 'Task assignee change' => 'เปลี่ยนการกำหนดบุคคลของงาน',
// '%s change the assignee of the task #%d to %s' => '', // '%s change the assignee of the task #%d to %s' => '',
// '%s change the assignee of the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to %s' => '', // '%s changed the assignee of the task %s to %s' => '',
// '[%s][Column Change] %s (#%d)' => '', // '[%s][Column Change] %s (#%d)' => '',
// '[%s][Position Change] %s (#%d)' => '', // '[%s][Position Change] %s (#%d)' => '',
// '[%s][Assignee Change] %s (#%d)' => '', // '[%s][Assignee Change] %s (#%d)' => '',
@ -555,8 +556,8 @@ return array(
// 'Webhooks' => '', // 'Webhooks' => '',
// 'API' => '', // 'API' => '',
// 'Integration' => '', // 'Integration' => '',
// 'Github webhook' => '', // 'Github webhooks' => '',
// 'Help on Github webhook' => '', // 'Help on Github webhooks' => '',
// 'Create a comment from an external provider' => '', // 'Create a comment from an external provider' => '',
// 'Github issue comment created' => '', // 'Github issue comment created' => '',
// 'Configure' => '', // 'Configure' => '',
@ -602,4 +603,49 @@ return array(
// 'Nothing to preview...' => '', // 'Nothing to preview...' => '',
// 'Preview' => '', // 'Preview' => '',
// 'Write' => '', // 'Write' => '',
// 'Active swimlanes' => '',
// 'Add a new swimlane' => '',
// 'Change default swimlane' => '',
// 'Default swimlane' => '',
// 'Do you really want to remove this swimlane: "%s"?' => '',
// 'Inactive swimlanes' => '',
// 'Set project manager' => '',
// 'Set project member' => '',
// 'Remove a swimlane' => '',
// 'Rename' => '',
// 'Show default swimlane' => '',
// 'Swimlane modification for the project "%s"' => '',
// 'Swimlane not found.' => '',
// 'Swimlane removed successfully.' => '',
// 'Swimlanes' => '',
// 'Swimlane updated successfully.' => '',
// 'The default swimlane have been updated successfully.' => '',
// 'Unable to create your swimlane.' => '',
// 'Unable to remove this swimlane.' => '',
// 'Unable to update this swimlane.' => '',
// 'Your swimlane have been created successfully.' => '',
// 'Example: "Bug, Feature Request, Improvement"' => '',
// 'Default categories for new projects (Comma-separated)' => '',
// 'Gitlab commit received' => '',
// 'Gitlab issue opened' => '',
// 'Gitlab issue closed' => '',
// 'Gitlab webhooks' => '',
// 'Help on Gitlab webhooks' => '',
// 'Integrations' => '',
// 'Integration with third-party services' => '',
// 'Role for this project' => '',
// 'Project manager' => '',
// 'Project member' => '',
// 'A project manager can change the settings of the project and have more privileges than a standard user.' => '',
// 'Gitlab Issue' => '',
// 'Subtask Id' => '',
// 'Subtasks' => '',
// 'Subtasks Export' => '',
// 'Subtasks exportation for "%s"' => '',
// 'Task Title' => '',
// 'Untitled' => '',
// 'Application default' => '',
// 'Language:' => '',
// 'Timezone:' => '',
// 'Next' => '',
); );

View file

@ -24,7 +24,7 @@ return array(
'Unassigned' => '未指定', 'Unassigned' => '未指定',
'View this task' => '查看该任务', 'View this task' => '查看该任务',
'Remove user' => '移除用户', 'Remove user' => '移除用户',
'Do you really want to remove this user: "%s"?' => '你确定要移除这个用户吗:"%s"', 'Do you really want to remove this user: "%s"?' => '确定要删除用户"%s"吗',
'New user' => '新建用户', 'New user' => '新建用户',
'All users' => '所有用户', 'All users' => '所有用户',
'Username' => '用户名', 'Username' => '用户名',
@ -63,7 +63,7 @@ return array(
'Disable' => '停用', 'Disable' => '停用',
'Enable' => '启用', 'Enable' => '启用',
'New project' => '新建项目', 'New project' => '新建项目',
'Do you really want to remove this project: "%s"?' => '确定要移除项目吗:"%s"', 'Do you really want to remove this project: "%s"?' => '确定要移除项目"%s"',
'Remove project' => '移除项目', 'Remove project' => '移除项目',
'Boards' => '看板', 'Boards' => '看板',
'Edit the board for "%s"' => '为"%s"修改看板', 'Edit the board for "%s"' => '为"%s"修改看板',
@ -78,7 +78,7 @@ return array(
'Remove a column' => '移除一个栏目', 'Remove a column' => '移除一个栏目',
'Remove a column from a board' => '从看板移除一个栏目', 'Remove a column from a board' => '从看板移除一个栏目',
'Unable to remove this column.' => '无法移除该栏目。', 'Unable to remove this column.' => '无法移除该栏目。',
'Do you really want to remove this column: "%s"?' => '确定要移除栏目"%s"吗?', 'Do you really want to remove this column: "%s"?' => '确定要移除栏目"%s"吗?',
'This action will REMOVE ALL TASKS associated to this column!' => '该动作将移除与该栏目相关的所有项目!', 'This action will REMOVE ALL TASKS associated to this column!' => '该动作将移除与该栏目相关的所有项目!',
'Settings' => '设置', 'Settings' => '设置',
'Application settings' => '应用设置', 'Application settings' => '应用设置',
@ -182,19 +182,19 @@ return array(
'Change assignee' => '变更负责人', 'Change assignee' => '变更负责人',
'Change assignee for the task "%s"' => '更改任务"%s"的负责人', 'Change assignee for the task "%s"' => '更改任务"%s"的负责人',
'Timezone' => '时区', 'Timezone' => '时区',
'Sorry, I didn\'t found this information in my database!' => '抱歉,无法在数据库中找到该信息!', 'Sorry, I didn\'t find this information in my database!' => '抱歉,无法在数据库中找到该信息!',
'Page not found' => '页面未找到', 'Page not found' => '页面未找到',
'Complexity' => '复杂度', 'Complexity' => '复杂度',
'limit' => '限制', 'limit' => '限制',
'Task limit' => '任务限制', 'Task limit' => '任务限制',
// 'Task count' => '', 'Task count' => '任务数',
'This value must be greater than %d' => '该数值必须大于%d', 'This value must be greater than %d' => '该数值必须大于%d',
'Edit project access list' => '编辑项目存取列表', 'Edit project access list' => '编辑项目存取列表',
'Edit users access' => '编辑用户存取权限', 'Edit users access' => '编辑用户存取权限',
'Allow this user' => '允许该用户', 'Allow this user' => '允许该用户',
'Only those users have access to this project:' => '只有这些用户有该项目的存取权限:', 'Only those users have access to this project:' => '只有这些用户有该项目的存取权限:',
'Don\'t forget that administrators have access to everything.' => '别忘了管理员有一切的权限。', 'Don\'t forget that administrators have access to everything.' => '别忘了管理员有一切的权限。',
'revoke' => '撤销', 'Revoke' => '撤销',
'List of authorized users' => '已授权的用户列表', 'List of authorized users' => '已授权的用户列表',
'User' => '用户', 'User' => '用户',
'Nobody have access to this project.' => '无用户可以访问此项目.', 'Nobody have access to this project.' => '无用户可以访问此项目.',
@ -213,6 +213,7 @@ return array(
'Invalid date' => '无效日期', 'Invalid date' => '无效日期',
'Must be done before %B %e, %Y' => '必须在%Y/%m/%d前完成', 'Must be done before %B %e, %Y' => '必须在%Y/%m/%d前完成',
'%B %e, %Y' => '%Y/%m/%d', '%B %e, %Y' => '%Y/%m/%d',
// '%b %e, %Y' => '',
'Automatic actions' => '自动动作', 'Automatic actions' => '自动动作',
'Your automatic action have been created successfully.' => '您的自动动作已成功创建', 'Your automatic action have been created successfully.' => '您的自动动作已成功创建',
'Unable to create your automatic action.' => '无法为您创建自动动作。', 'Unable to create your automatic action.' => '无法为您创建自动动作。',
@ -231,7 +232,7 @@ return array(
'Next step' => '下一步', 'Next step' => '下一步',
'Define action parameters' => '定义动作参数', 'Define action parameters' => '定义动作参数',
'Save this action' => '保存该动作', 'Save this action' => '保存该动作',
'Do you really want to remove this action: "%s"?' => '确定要移除动作"%s"吗?', 'Do you really want to remove this action: "%s"?' => '确定要移除动作"%s"吗?',
'Remove an automatic action' => '移除一个自动动作', 'Remove an automatic action' => '移除一个自动动作',
'Close the task' => '关闭任务', 'Close the task' => '关闭任务',
'Assign the task to a specific user' => '将该任务指派给一个用户', 'Assign the task to a specific user' => '将该任务指派给一个用户',
@ -285,7 +286,7 @@ return array(
'Nothing found.' => '没找到。', 'Nothing found.' => '没找到。',
'Search in the project "%s"' => '在项目"%s"中查找', 'Search in the project "%s"' => '在项目"%s"中查找',
'Due date' => '到期时间', 'Due date' => '到期时间',
'Others formats accepted: %s and %s' => '允许其他格式:%s 和 %s', 'Others formats accepted: %s and %s' => '可以使用的其它格式:%s 和 %s',
'Description' => '描述', 'Description' => '描述',
'%d comments' => '%d个评论', '%d comments' => '%d个评论',
'%d comment' => '%d个评论', '%d comment' => '%d个评论',
@ -323,7 +324,7 @@ return array(
'Category Name' => '分类名称', 'Category Name' => '分类名称',
'Categories for the project "%s"' => '项目"%s"的分类', 'Categories for the project "%s"' => '项目"%s"的分类',
'Add a new category' => '加入新分类', 'Add a new category' => '加入新分类',
'Do you really want to remove this category: "%s"?' => '确定要移除分类"%s"吗?', 'Do you really want to remove this category: "%s"?' => '确定要移除分类"%s"吗?',
'Filter by category' => '按分类过滤', 'Filter by category' => '按分类过滤',
'All categories' => '所有分类', 'All categories' => '所有分类',
'No category' => '无分类', 'No category' => '无分类',
@ -332,7 +333,7 @@ return array(
'Unable to remove this file.' => '无法移除该文件。', 'Unable to remove this file.' => '无法移除该文件。',
'File removed successfully.' => '文件成功移除。', 'File removed successfully.' => '文件成功移除。',
'Attach a document' => '附加文档', 'Attach a document' => '附加文档',
'Do you really want to remove this file: "%s"?' => '确定要移除文件"%s"吗?', 'Do you really want to remove this file: "%s"?' => '确定要移除文件"%s"吗?',
'open' => '打开', 'open' => '打开',
'Attachments' => '附件', 'Attachments' => '附件',
'Edit the task' => '修改任务', 'Edit the task' => '修改任务',
@ -375,7 +376,7 @@ return array(
'Login with my GitHub Account' => '用Github账号登录', 'Login with my GitHub Account' => '用Github账号登录',
'Link my GitHub Account' => '链接GitHub账号', 'Link my GitHub Account' => '链接GitHub账号',
'Unlink my GitHub Account' => '取消GitHub账号链接', 'Unlink my GitHub Account' => '取消GitHub账号链接',
'Created by %s' => '创建者:', 'Created by %s' => '创建者:%s',
'Last modified on %B %e, %Y at %k:%M %p' => '最后修改:%Y/%m/%d/ %H:%M', 'Last modified on %B %e, %Y at %k:%M %p' => '最后修改:%Y/%m/%d/ %H:%M',
'Tasks Export' => '任务导出', 'Tasks Export' => '任务导出',
'Tasks exportation for "%s"' => '导出任务"%s"', 'Tasks exportation for "%s"' => '导出任务"%s"',
@ -468,20 +469,20 @@ return array(
'Unable to change the password.' => '无法修改密码。', 'Unable to change the password.' => '无法修改密码。',
'Change category for the task "%s"' => '变更任务 "%s" 的分类', 'Change category for the task "%s"' => '变更任务 "%s" 的分类',
'Change category' => '变更分类', 'Change category' => '变更分类',
'%s updated the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s 更新了任务 <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s updated the task %s' => '%s 更新了任务 %s',
'%s open the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s 开启了任务 <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s opened the task %s' => '%s 开启了任务 %s',
'%s moved the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to the position #%d in the column "%s"' => '%s 将任务 <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> 移动到了"%s"的第#%d个位置', '%s moved the task %s to the position #%d in the column "%s"' => '%s 将任务 %s 移动到了"%s"的第#%d个位置',
'%s moved the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to the column "%s"' => '%s 移动任务 <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> 到栏目 "%s"', '%s moved the task %s to the column "%s"' => '%s 移动任务 %s 到栏目 "%s"',
'%s created the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s 创建了任务 <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s created the task %s' => '%s 创建了任务 %s',
'%s closed the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s 关闭了任务 <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s closed the task %s' => '%s 关闭了任务 %s',
'%s created a subtask for the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s 创建了 <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>的子任务', '%s created a subtask for the task %s' => '%s 创建了 %s的子任务',
'%s updated a subtask for the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s 更新了 <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>的子任务', '%s updated a subtask for the task %s' => '%s 更新了 %s的子任务',
'Assigned to %s with an estimate of %s/%sh' => '分配给 %s预估需要 %s/%s 小时', 'Assigned to %s with an estimate of %s/%sh' => '分配给 %s预估需要 %s/%s 小时',
'Not assigned, estimate of %sh' => '未分配,预估需要 %s 小时', 'Not assigned, estimate of %sh' => '未分配,预估需要 %s 小时',
'%s updated a comment on the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s 更新了任务 <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>的评论', '%s updated a comment on the task %s' => '%s 更新了任务 %s的评论',
'%s commented the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>' => '%s 评论了任务 <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a>', '%s commented the task %s' => '%s 评论了任务 %s',
'%s\'s activity' => '%s的动', '%s\'s activity' => '%s的',
'No activity.' => '无动', 'No activity.' => '无',
'RSS feed' => 'RSS 链接', 'RSS feed' => 'RSS 链接',
'%s updated a comment on the task #%d' => '%s 更新了任务 #%d 的评论', '%s updated a comment on the task #%d' => '%s 更新了任务 #%d 的评论',
'%s commented on the task #%d' => '%s 评论了任务 #%d', '%s commented on the task #%d' => '%s 评论了任务 #%d',
@ -493,12 +494,12 @@ return array(
'%s open the task #%d' => '%s 开启了任务 #%d', '%s open the task #%d' => '%s 开启了任务 #%d',
'%s moved the task #%d to the column "%s"' => '%s 将任务 #%d 移动到栏目 "%s"', '%s moved the task #%d to the column "%s"' => '%s 将任务 #%d 移动到栏目 "%s"',
'%s moved the task #%d to the position %d in the column "%s"' => '%s将任务#%d移动到"%s"的第 %d 列', '%s moved the task #%d to the position %d in the column "%s"' => '%s将任务#%d移动到"%s"的第 %d 列',
'Activity' => '动', 'Activity' => '',
'Default values are "%s"' => '默认值为 "%s"', 'Default values are "%s"' => '默认值为 "%s"',
'Default columns for new projects (Comma-separated)' => '新建项目的默认栏目(用逗号分开)', 'Default columns for new projects (Comma-separated)' => '新建项目的默认栏目(用逗号分开)',
'Task assignee change' => '任务分配变更', 'Task assignee change' => '任务分配变更',
'%s change the assignee of the task #%d to %s' => '%s 将任务 #%d 分配给了 %s', '%s change the assignee of the task #%d to %s' => '%s 将任务 #%d 分配给了 %s',
'%s change the assignee of the task <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> to %s' => '%s 将任务 <a href="?controller=task&amp;action=show&amp;task_id=%d">#%d</a> 分配给 %s', '%s changed the assignee of the task %s to %s' => '%s 将任务 %s 分配给 %s',
'[%s][Column Change] %s (#%d)' => '[%s][栏目变更] %s (#%d)', '[%s][Column Change] %s (#%d)' => '[%s][栏目变更] %s (#%d)',
'[%s][Position Change] %s (#%d)' => '[%s][位置变更] %s (#%d)', '[%s][Position Change] %s (#%d)' => '[%s][位置变更] %s (#%d)',
'[%s][Assignee Change] %s (#%d)' => '[%s][任务分配变更] %s (#%d)', '[%s][Assignee Change] %s (#%d)' => '[%s][任务分配变更] %s (#%d)',
@ -547,7 +548,7 @@ return array(
'Time estimated' => '预计时间', 'Time estimated' => '预计时间',
'There is nothing assigned to you.' => '无任务指派给你。', 'There is nothing assigned to you.' => '无任务指派给你。',
'My tasks' => '我的任务', 'My tasks' => '我的任务',
'Activity stream' => '活动流', 'Activity stream' => '动态记录',
'Dashboard' => '面板', 'Dashboard' => '面板',
'Confirmation' => '确认', 'Confirmation' => '确认',
'Allow everybody to access to this project' => '允许所有人访问此项目', 'Allow everybody to access to this project' => '允许所有人访问此项目',
@ -555,8 +556,8 @@ return array(
'Webhooks' => '网络钩子', 'Webhooks' => '网络钩子',
'API' => '应用程序接口', 'API' => '应用程序接口',
'Integration' => '整合', 'Integration' => '整合',
'Github webhook' => 'Github 网络钩子', 'Github webhooks' => 'Github 网络钩子',
'Help on Github webhook' => 'Github 网络钩子帮助', 'Help on Github webhooks' => 'Github 网络钩子帮助',
'Create a comment from an external provider' => '从外部创建一个评论', 'Create a comment from an external provider' => '从外部创建一个评论',
'Github issue comment created' => '已经创建了Github问题评论', 'Github issue comment created' => '已经创建了Github问题评论',
'Configure' => '配置', 'Configure' => '配置',
@ -602,4 +603,49 @@ return array(
'Nothing to preview...' => '没有需要预览的内容', 'Nothing to preview...' => '没有需要预览的内容',
'Preview' => '预览', 'Preview' => '预览',
'Write' => '书写', 'Write' => '书写',
'Active swimlanes' => '活动泳道',
'Add a new swimlane' => '添加新泳道',
'Change default swimlane' => '修改默认泳道',
'Default swimlane' => '默认泳道',
'Do you really want to remove this swimlane: "%s"?' => '确定要删除泳道:"%s"?',
'Inactive swimlanes' => '非活动泳道',
// 'Set project manager' => '',
// 'Set project member' => '',
'Remove a swimlane' => '删除泳道',
'Rename' => '重命名',
'Show default swimlane' => '显示默认泳道',
'Swimlane modification for the project "%s"' => '项目"%s"的泳道变更',
'Swimlane not found.' => '未找到泳道。',
'Swimlane removed successfully.' => '成功删除泳道',
'Swimlanes' => '泳道',
'Swimlane updated successfully.' => '成功更新了泳道。',
'The default swimlane have been updated successfully.' => '成功更新了默认泳道。',
'Unable to create your swimlane.' => '无法创建泳道。',
'Unable to remove this swimlane.' => '无法删除此泳道',
'Unable to update this swimlane.' => '无法更新此泳道',
'Your swimlane have been created successfully.' => '已经成功创建泳道。',
// 'Example: "Bug, Feature Request, Improvement"' => '',
// 'Default categories for new projects (Comma-separated)' => '',
// 'Gitlab commit received' => '',
// 'Gitlab issue opened' => '',
// 'Gitlab issue closed' => '',
// 'Gitlab webhooks' => '',
// 'Help on Gitlab webhooks' => '',
// 'Integrations' => '',
// 'Integration with third-party services' => '',
// 'Role for this project' => '',
// 'Project manager' => '',
// 'Project member' => '',
// 'A project manager can change the settings of the project and have more privileges than a standard user.' => '',
// 'Gitlab Issue' => '',
// 'Subtask Id' => '',
// 'Subtasks' => '',
// 'Subtasks Export' => '',
// 'Subtasks exportation for "%s"' => '',
// 'Task Title' => '',
// 'Untitled' => '',
// 'Application default' => '',
// 'Language:' => '',
// 'Timezone:' => '',
// 'Next' => '',
); );

View file

@ -3,7 +3,7 @@
namespace Model; namespace Model;
/** /**
* Acl model * Access List
* *
* @package model * @package model
* @author Frederic Guillot * @author Frederic Guillot
@ -16,36 +16,59 @@ class Acl extends Base
* @access private * @access private
* @var array * @var array
*/ */
private $public_actions = array( private $public_acl = array(
'user' => array('login', 'check', 'google', 'github'), 'user' => array('login', 'check', 'google', 'github'),
'task' => array('readonly'), 'task' => array('readonly'),
'board' => array('readonly'), 'board' => array('readonly'),
'project' => array('feed'), 'project' => array('feed'),
'webhook' => array('task', 'github'), 'webhook' => '*',
); );
/** /**
* Controllers and actions allowed for regular users * Controllers and actions for project members
* *
* @access private * @access private
* @var array * @var array
*/ */
private $user_actions = array( private $member_acl = array(
'app' => array('index', 'preview', 'status'), 'board' => '*',
'project' => array('index', 'show', 'exporttasks', 'exportdaily', 'share', 'edit', 'update', 'users', 'remove', 'duplicate', 'disable', 'enable', 'activity', 'search', 'tasks', 'create', 'save'), 'comment' => '*',
'board' => array('index', 'show', 'save', 'check', 'changeassignee', 'updateassignee', 'changecategory', 'updatecategory', 'movecolumn', 'edit', 'update', 'add', 'confirm', 'remove', 'subtasks', 'togglesubtask', 'attachments', 'comments', 'description'), 'file' => '*',
'user' => array('edit', 'forbidden', 'logout', 'show', 'external', 'unlinkgoogle', 'unlinkgithub', 'sessions', 'removesession', 'last', 'notifications', 'password'), 'project' => array('show', 'tasks', 'search', 'activity'),
'comment' => array('create', 'save', 'confirm', 'remove', 'update', 'edit', 'forbidden'), 'subtask' => '*',
'file' => array('create', 'save', 'download', 'confirm', 'remove', 'open', 'image'), 'task' => '*',
'subtask' => array('create', 'save', 'edit', 'update', 'confirm', 'remove', 'togglestatus'),
'task' => array('show', 'create', 'save', 'edit', 'update', 'close', 'open', 'duplicate', 'remove', 'description', 'move', 'copy', 'time'),
'category' => array('index', 'save', 'edit', 'update', 'confirm', 'remove'),
'action' => array('index', 'event', 'params', 'create', 'confirm', 'remove'),
'analytic' => array('tasks', 'users', 'cfd'),
); );
/** /**
* Return true if the specified controller/action is allowed according to the given acl * Controllers and actions for project managers
*
* @access private
* @var array
*/
private $manager_acl = array(
'action' => '*',
'analytic' => '*',
'board' => array('movecolumn', 'edit', 'update', 'add', 'remove'),
'category' => '*',
'export' => array('tasks', 'subtasks', 'summary'),
'project' => array('edit', 'update', 'share', 'integration', 'users', 'alloweverybody', 'allow', 'setowner', 'revoke', 'duplicate', 'disable', 'enable'),
'swimlane' => '*',
);
/**
* Controllers and actions for admins
*
* @access private
* @var array
*/
private $admin_acl = array(
'user' => array('index', 'create', 'save', 'remove'),
'config' => '*',
'project' => array('remove'),
);
/**
* Return true if the specified controller/action match the given acl
* *
* @access public * @access public
* @param array $acl Acl list * @param array $acl Acl list
@ -53,13 +76,27 @@ class Acl extends Base
* @param string $action Action name * @param string $action Action name
* @return bool * @return bool
*/ */
public function isAllowedAction(array $acl, $controller, $action) public function matchAcl(array $acl, $controller, $action)
{ {
if (isset($acl[$controller])) { $action = strtolower($action);
return in_array($action, $acl[$controller]); return isset($acl[$controller]) && $this->hasAction($action, $acl[$controller]);
}
/**
* Return true if the specified action is inside the list of actions
*
* @access public
* @param string $action Action name
* @param mixed $action Actions list
* @return bool
*/
public function hasAction($action, $actions)
{
if (is_array($actions)) {
return in_array($action, $actions);
} }
return false; return $actions === '*';
} }
/** /**
@ -72,94 +109,90 @@ class Acl extends Base
*/ */
public function isPublicAction($controller, $action) public function isPublicAction($controller, $action)
{ {
return $this->isAllowedAction($this->public_actions, $controller, $action); return $this->matchAcl($this->public_acl, $controller, $action);
} }
/** /**
* Return true if the given action is allowed for a regular user * Return true if the given action is for admins
* *
* @access public * @access public
* @param string $controller Controller name * @param string $controller Controller name
* @param string $action Action name * @param string $action Action name
* @return bool * @return bool
*/ */
public function isUserAction($controller, $action) public function isAdminAction($controller, $action)
{ {
return $this->isAllowedAction($this->user_actions, $controller, $action); return $this->matchAcl($this->admin_acl, $controller, $action);
} }
/** /**
* Return true if the logged user is admin * Return true if the given action is for project managers
* *
* @access public * @access public
* @param string $controller Controller name
* @param string $action Action name
* @return bool * @return bool
*/ */
public function isAdminUser() public function isManagerAction($controller, $action)
{ {
return isset($_SESSION['user']['is_admin']) && $_SESSION['user']['is_admin'] === true; return $this->matchAcl($this->manager_acl, $controller, $action);
} }
/** /**
* Return true if the logged user is not admin * Return true if the given action is for project members
* *
* @access public * @access public
* @param string $controller Controller name
* @param string $action Action name
* @return bool * @return bool
*/ */
public function isRegularUser() public function isMemberAction($controller, $action)
{ {
return isset($_SESSION['user']['is_admin']) && $_SESSION['user']['is_admin'] === false; return $this->matchAcl($this->member_acl, $controller, $action);
} }
/** /**
* Get the connected user id * Return true if the visitor is allowed to access to the given page
* * We suppose the user already authenticated
* @access public
* @return integer
*/
public function getUserId()
{
return isset($_SESSION['user']['id']) ? (int) $_SESSION['user']['id'] : 0;
}
/**
* Check is the user is connected
* *
* @access public * @access public
* @param string $controller Controller name
* @param string $action Action name
* @param integer $project_id Project id
* @return bool * @return bool
*/ */
public function isLogged() public function isAllowed($controller, $action, $project_id = 0)
{ {
return ! empty($_SESSION['user']); // If you are admin you have access to everything
} if ($this->userSession->isAdmin()) {
return true;
/**
* Check is the user was authenticated with the RememberMe or set the value
*
* @access public
* @param bool $value Set true if the user use the RememberMe
* @return bool
*/
public function isRememberMe($value = null)
{
if ($value !== null) {
$_SESSION['is_remember_me'] = $value;
} }
return empty($_SESSION['is_remember_me']) ? false : $_SESSION['is_remember_me']; // If you access to an admin action, your are not allowed
if ($this->isAdminAction($controller, $action)) {
return false;
}
// Check project manager permissions
if ($this->isManagerAction($controller, $action)) {
return $this->isManagerActionAllowed($project_id);
}
// Check project member permissions
if ($this->isMemberAction($controller, $action)) {
return $project_id > 0 && $this->projectPermission->isMember($project_id, $this->userSession->getId());
}
// Other applications actions are allowed
return true;
} }
/** public function isManagerActionAllowed($project_id)
* Check if an action is allowed for the logged user
*
* @access public
* @param string $controller Controller name
* @param string $action Action name
* @return bool
*/
public function isPageAccessAllowed($controller, $action)
{ {
return $this->isPublicAction($controller, $action) || if ($this->userSession->isAdmin()) {
$this->isAdminUser() || return true;
($this->isRegularUser() && $this->isUserAction($controller, $action)); }
return $project_id > 0 && $this->projectPermission->isManager($project_id, $this->userSession->getId());
} }
} }

View file

@ -2,7 +2,8 @@
namespace Model; namespace Model;
use LogicException; use Integration\GitlabWebhook;
use Integration\GithubWebhook;
use SimpleValidator\Validator; use SimpleValidator\Validator;
use SimpleValidator\Validators; use SimpleValidator\Validators;
@ -80,6 +81,9 @@ class Action extends Base
GithubWebhook::EVENT_ISSUE_ASSIGNEE_CHANGE => t('Github issue assignee change'), GithubWebhook::EVENT_ISSUE_ASSIGNEE_CHANGE => t('Github issue assignee change'),
GithubWebhook::EVENT_ISSUE_LABEL_CHANGE => t('Github issue label change'), GithubWebhook::EVENT_ISSUE_LABEL_CHANGE => t('Github issue label change'),
GithubWebhook::EVENT_ISSUE_COMMENT => t('Github issue comment created'), GithubWebhook::EVENT_ISSUE_COMMENT => t('Github issue comment created'),
GitlabWebhook::EVENT_COMMIT => t('Gitlab commit received'),
GitlabWebhook::EVENT_ISSUE_OPENED => t('Gitlab issue opened'),
GitlabWebhook::EVENT_ISSUE_CLOSED => t('Gitlab issue closed'),
); );
asort($values); asort($values);
@ -136,9 +140,17 @@ class Action extends Base
public function getAll() public function getAll()
{ {
$actions = $this->db->table(self::TABLE)->findAll(); $actions = $this->db->table(self::TABLE)->findAll();
$params = $this->db->table(self::TABLE_PARAMS)->findAll();
foreach ($actions as &$action) { foreach ($actions as &$action) {
$action['params'] = $this->db->table(self::TABLE_PARAMS)->eq('action_id', $action['id'])->findAll();
$action['params'] = array();
foreach ($params as $param) {
if ($param['action_id'] === $action['id']) {
$action['params'][] = $param;
}
}
} }
return $actions; return $actions;
@ -187,6 +199,7 @@ class Action extends Base
*/ */
public function remove($action_id) public function remove($action_id)
{ {
// $this->container['fileCache']->remove('proxy_action_getAll');
return $this->db->table(self::TABLE)->eq('id', $action_id)->remove(); return $this->db->table(self::TABLE)->eq('id', $action_id)->remove();
} }
@ -230,6 +243,8 @@ class Action extends Base
$this->db->closeTransaction(); $this->db->closeTransaction();
// $this->container['fileCache']->remove('proxy_action_getAll');
return true; return true;
} }
@ -240,7 +255,10 @@ class Action extends Base
*/ */
public function attachEvents() public function attachEvents()
{ {
foreach ($this->getAll() as $action) { //$actions = $this->container['fileCache']->proxy('action', 'getAll');
$actions = $this->getAll();
foreach ($actions as $action) {
$listener = $this->load($action['action_name'], $action['project_id'], $action['event_name']); $listener = $this->load($action['action_name'], $action['project_id'], $action['event_name']);
@ -248,7 +266,7 @@ class Action extends Base
$listener->setParam($param['name'], $param['value']); $listener->setParam($param['name'], $param['value']);
} }
$this->event->attach($action['event_name'], $listener); $this->container['dispatcher']->addListener($action['event_name'], array($listener, 'execute'));
} }
} }
@ -303,6 +321,8 @@ class Action extends Base
} }
} }
// $this->container['fileCache']->remove('proxy_action_getAll');
return true; return true;
} }

View file

@ -3,7 +3,6 @@
namespace Model; namespace Model;
use Core\Request; use Core\Request;
use Auth\Database;
use SimpleValidator\Validator; use SimpleValidator\Validator;
use SimpleValidator\Validators; use SimpleValidator\Validators;
@ -36,19 +35,12 @@ class Authentication extends Base
* Check if the current user is authenticated * Check if the current user is authenticated
* *
* @access public * @access public
* @param string $controller Controller
* @param string $action Action name
* @return bool * @return bool
*/ */
public function isAuthenticated($controller, $action) public function isAuthenticated()
{ {
// If the action is public we don't need to do any checks
if ($this->acl->isPublicAction($controller, $action)) {
return true;
}
// If the user is already logged it's ok // If the user is already logged it's ok
if ($this->acl->isLogged()) { if ($this->userSession->isLogged()) {
// We update each time the RememberMe cookie tokens // We update each time the RememberMe cookie tokens
if ($this->backend('rememberMe')->hasCookie()) { if ($this->backend('rememberMe')->hasCookie()) {
@ -118,7 +110,7 @@ class Authentication extends Base
if (! empty($values['remember_me'])) { if (! empty($values['remember_me'])) {
$credentials = $this->backend('rememberMe') $credentials = $this->backend('rememberMe')
->create($this->acl->getUserId(), Request::getIpAddress(), Request::getUserAgent()); ->create($this->userSession->getId(), Request::getIpAddress(), Request::getUserAgent());
$this->backend('rememberMe')->writeCookie($credentials['token'], $credentials['sequence'], $credentials['expiration']); $this->backend('rememberMe')->writeCookie($credentials['token'], $credentials['sequence'], $credentials['expiration']);
} }

View file

@ -2,10 +2,7 @@
namespace Model; namespace Model;
use Core\Event;
use Core\Tool;
use Pimple\Container; use Pimple\Container;
use PicoDb\Database;
/** /**
* Base model class * Base model class
@ -13,6 +10,8 @@ use PicoDb\Database;
* @package model * @package model
* @author Frederic Guillot * @author Frederic Guillot
* *
* @property \Core\Session $session
* @property \Core\Template $template
* @property \Model\Acl $acl * @property \Model\Acl $acl
* @property \Model\Action $action * @property \Model\Action $action
* @property \Model\Authentication $authentication * @property \Model\Authentication $authentication
@ -30,6 +29,7 @@ use PicoDb\Database;
* @property \Model\ProjectPermission $projectPermission * @property \Model\ProjectPermission $projectPermission
* @property \Model\SubTask $subTask * @property \Model\SubTask $subTask
* @property \Model\SubtaskHistory $subtaskHistory * @property \Model\SubtaskHistory $subtaskHistory
* @property \Model\Swimlane $swimlane
* @property \Model\Task $task * @property \Model\Task $task
* @property \Model\TaskCreation $taskCreation * @property \Model\TaskCreation $taskCreation
* @property \Model\TaskExport $taskExport * @property \Model\TaskExport $taskExport
@ -39,6 +39,7 @@ use PicoDb\Database;
* @property \Model\TaskValidator $taskValidator * @property \Model\TaskValidator $taskValidator
* @property \Model\TimeTracking $timeTracking * @property \Model\TimeTracking $timeTracking
* @property \Model\User $user * @property \Model\User $user
* @property \Model\UserSession $userSession
* @property \Model\Webhook $webhook * @property \Model\Webhook $webhook
*/ */
abstract class Base abstract class Base
@ -51,14 +52,6 @@ abstract class Base
*/ */
protected $db; protected $db;
/**
* Event dispatcher instance
*
* @access public
* @var \Core\Event
*/
public $event;
/** /**
* Container instance * Container instance
* *
@ -77,7 +70,6 @@ abstract class Base
{ {
$this->container = $container; $this->container = $container;
$this->db = $this->container['db']; $this->db = $this->container['db'];
$this->event = $this->container['event'];
} }
/** /**
@ -89,7 +81,7 @@ abstract class Base
*/ */
public function __get($name) public function __get($name)
{ {
return Tool::loadModel($this->container, $name); return $this->container[$name];
} }
/** /**
@ -117,7 +109,7 @@ abstract class Base
* *
* @access public * @access public
* @param array $values Input array * @param array $values Input array
* @param array $keys List of keys to remove * @param string[] $keys List of keys to remove
*/ */
public function removeFields(array &$values, array $keys) public function removeFields(array &$values, array $keys)
{ {
@ -132,8 +124,8 @@ abstract class Base
* Force some fields to be at 0 if empty * Force some fields to be at 0 if empty
* *
* @access public * @access public
* @param array $values Input array * @param array $values Input array
* @param array $keys List of keys * @param string[] $keys List of keys
*/ */
public function resetFields(array &$values, array $keys) public function resetFields(array &$values, array $keys)
{ {
@ -148,8 +140,8 @@ abstract class Base
* Force some fields to be integer * Force some fields to be integer
* *
* @access public * @access public
* @param array $values Input array * @param array $values Input array
* @param array $keys List of keys * @param string[] $keys List of keys
*/ */
public function convertIntegerFields(array &$values, array $keys) public function convertIntegerFields(array &$values, array $keys)
{ {

View file

@ -24,7 +24,7 @@ class Board extends Base
* Get Kanboard default columns * Get Kanboard default columns
* *
* @access public * @access public
* @return array * @return string[]
*/ */
public function getDefaultColumns() public function getDefaultColumns()
{ {
@ -227,29 +227,47 @@ class Board extends Base
} }
/** /**
* Get all columns and tasks for a given project * Get all tasks sorted by columns and swimlanes
* *
* @access public * @access public
* @param integer $project_id Project id * @param integer $project_id Project id
* @return array * @return array
*/ */
public function get($project_id) public function getBoard($project_id)
{ {
$swimlanes = $this->swimlane->getSwimlanes($project_id);
$columns = $this->getColumns($project_id); $columns = $this->getColumns($project_id);
$tasks = $this->taskFinder->getTasksOnBoard($project_id); $nb_columns = count($columns);
foreach ($columns as &$column) { for ($i = 0, $ilen = count($swimlanes); $i < $ilen; $i++) {
$column['tasks'] = array(); $swimlanes[$i]['columns'] = $columns;
$swimlanes[$i]['nb_columns'] = $nb_columns;
foreach ($tasks as &$task) { for ($j = 0; $j < $nb_columns; $j++) {
if ($task['column_id'] == $column['id']) { $swimlanes[$i]['columns'][$j]['tasks'] = $this->taskFinder->getTasksByColumnAndSwimlane($project_id, $columns[$j]['id'], $swimlanes[$i]['id']);
$column['tasks'][] = $task; $swimlanes[$i]['columns'][$j]['nb_tasks'] = count($swimlanes[$i]['columns'][$j]['tasks']);
}
} }
} }
return $columns; return $swimlanes;
}
/**
* Get the total of tasks per column
*
* @access public
* @param integer $project_id
* @return array
*/
public function getColumnStats($project_id)
{
return $this->db
->table(Task::TABLE)
->eq('project_id', $project_id)
->eq('is_active', 1)
->groupBy('column_id')
->listing('column_id', 'COUNT(*) AS total');
} }
/** /**

View file

@ -118,7 +118,30 @@ class Category extends Base
} }
/** /**
* Create a category * Create default cetegories during project creation (transaction already started in Project::create())
*
* @access public
* @param integer $project_id
*/
public function createDefaultCategories($project_id)
{
$categories = explode(',', $this->config->get('project_categories'));
foreach ($categories as $category) {
$category = trim($category);
if (! empty($category)) {
$this->db->table(self::TABLE)->insert(array(
'project_id' => $project_id,
'name' => $category,
));
}
}
}
/**
* Create a category (run inside a transaction)
* *
* @access public * @access public
* @param array $values Form values * @param array $values Form values

View file

@ -2,6 +2,7 @@
namespace Model; namespace Model;
use Event\CommentEvent;
use SimpleValidator\Validator; use SimpleValidator\Validator;
use SimpleValidator\Validators; use SimpleValidator\Validators;
@ -107,7 +108,7 @@ class Comment extends Base
$comment_id = $this->persist(self::TABLE, $values); $comment_id = $this->persist(self::TABLE, $values);
if ($comment_id) { if ($comment_id) {
$this->event->trigger(self::EVENT_CREATE, array('id' => $comment_id) + $values); $this->container['dispatcher']->dispatch(self::EVENT_CREATE, new CommentEvent(array('id' => $comment_id) + $values));
} }
return $comment_id; return $comment_id;
@ -127,7 +128,7 @@ class Comment extends Base
->eq('id', $values['id']) ->eq('id', $values['id'])
->update(array('comment' => $values['comment'])); ->update(array('comment' => $values['comment']));
$this->event->trigger(self::EVENT_UPDATE, $values); $this->container['dispatcher']->dispatch(self::EVENT_UPDATE, new CommentEvent($values));
return $result; return $result;
} }

View file

@ -2,8 +2,6 @@
namespace Model; namespace Model;
use SimpleValidator\Validator;
use SimpleValidator\Validators;
use Core\Translator; use Core\Translator;
use Core\Security; use Core\Security;
use Core\Session; use Core\Session;
@ -27,30 +25,39 @@ class Config extends Base
* Get available timezones * Get available timezones
* *
* @access public * @access public
* @param boolean $prepend Prepend a default value
* @return array * @return array
*/ */
public function getTimezones() public function getTimezones($prepend = false)
{ {
$timezones = timezone_identifiers_list(); $timezones = timezone_identifiers_list();
return array_combine(array_values($timezones), $timezones); $listing = array_combine(array_values($timezones), $timezones);
if ($prepend) {
return array('' => t('Application default')) + $listing;
}
return $listing;
} }
/** /**
* Get available languages * Get available languages
* *
* @access public * @access public
* @param boolean $prepend Prepend a default value
* @return array * @return array
*/ */
public function getLanguages() public function getLanguages($prepend = false)
{ {
// Sorted by value // Sorted by value
return array( $languages = array(
'da_DK' => 'Dansk', 'da_DK' => 'Dansk',
'de_DE' => 'Deutsch', 'de_DE' => 'Deutsch',
'en_US' => 'English', 'en_US' => 'English',
'es_ES' => 'Español', 'es_ES' => 'Español',
'fr_FR' => 'Français', 'fr_FR' => 'Français',
'it_IT' => 'Italiano', 'it_IT' => 'Italiano',
'hu_HU' => 'Magyar',
'pl_PL' => 'Polski', 'pl_PL' => 'Polski',
'pt_BR' => 'Português (Brasil)', 'pt_BR' => 'Português (Brasil)',
'ru_RU' => 'Русский', 'ru_RU' => 'Русский',
@ -60,6 +67,12 @@ class Config extends Base
'ja_JP' => '日本語', 'ja_JP' => '日本語',
'th_TH' => 'ไทย', 'th_TH' => 'ไทย',
); );
if ($prepend) {
return array('' => t('Application default')) + $languages;
}
return $languages;
} }
/** /**
@ -77,12 +90,13 @@ class Config extends Base
return $value ?: $default_value; return $value ?: $default_value;
} }
if (! isset($_SESSION['config'][$name])) { // Cache config in session
$_SESSION['config'] = $this->getAll(); if (! isset($this->session['config'][$name])) {
$this->session['config'] = $this->getAll();
} }
if (! empty($_SESSION['config'][$name])) { if (! empty($this->session['config'][$name])) {
return $_SESSION['config'][$name]; return $this->session['config'][$name];
} }
return $default_value; return $default_value;
@ -127,7 +141,7 @@ class Config extends Base
*/ */
public function reload() public function reload()
{ {
$_SESSION['config'] = $this->getAll(); $this->session['config'] = $this->getAll();
$this->setupTranslations(); $this->setupTranslations();
} }
@ -138,10 +152,11 @@ class Config extends Base
*/ */
public function setupTranslations() public function setupTranslations()
{ {
$language = $this->get('application_language', 'en_US'); if ($this->userSession->isLogged() && ! empty($this->session['user']['language'])) {
Translator::load($this->session['user']['language']);
if ($language !== 'en_US') { }
Translator::load($language); else {
Translator::load($this->get('application_language', 'en_US'));
} }
} }
@ -152,7 +167,12 @@ class Config extends Base
*/ */
public function setupTimezone() public function setupTimezone()
{ {
date_default_timezone_set($this->get('application_timezone', 'UTC')); if ($this->userSession->isLogged() && ! empty($this->session['user']['timezone'])) {
date_default_timezone_set($this->session['user']['timezone']);
}
else {
date_default_timezone_set($this->get('application_timezone', 'UTC'));
}
} }
/** /**

View file

@ -60,7 +60,7 @@ class DateParser extends Base
* Return the list of supported date formats (for the parser) * Return the list of supported date formats (for the parser)
* *
* @access public * @access public
* @return array * @return string[]
*/ */
public function getDateFormats() public function getDateFormats()
{ {
@ -103,7 +103,7 @@ class DateParser extends Base
* *
* @access public * @access public
* @param array $values Database values * @param array $values Database values
* @param array $fields Date fields * @param string[] $fields Date fields
* @param string $format Date format * @param string $format Date format
*/ */
public function format(array &$values, array $fields, $format = '') public function format(array &$values, array $fields, $format = '')
@ -128,7 +128,7 @@ class DateParser extends Base
* *
* @access public * @access public
* @param array $values Database values * @param array $values Database values
* @param array $fields Date fields * @param string[] $fields Date fields
*/ */
public function convert(array &$values, array $fields) public function convert(array &$values, array $fields)
{ {

View file

@ -2,6 +2,8 @@
namespace Model; namespace Model;
use Event\FileEvent;
/** /**
* File model * File model
* *
@ -89,7 +91,10 @@ class File extends Base
*/ */
public function create($task_id, $name, $path, $is_image) public function create($task_id, $name, $path, $is_image)
{ {
$this->event->trigger(self::EVENT_CREATE, array('task_id' => $task_id, 'name' => $name)); $this->container['dispatcher']->dispatch(
self::EVENT_CREATE,
new FileEvent(array('task_id' => $task_id, 'name' => $name))
);
return $this->db->table(self::TABLE)->save(array( return $this->db->table(self::TABLE)->save(array(
'task_id' => $task_id, 'task_id' => $task_id,

View file

@ -32,7 +32,7 @@ class LastLogin extends Base
* @param integer $user_id User id * @param integer $user_id User id
* @param string $ip IP Address * @param string $ip IP Address
* @param string $user_agent User Agent * @param string $user_agent User Agent
* @return array * @return boolean
*/ */
public function create($auth_type, $user_id, $ip, $user_agent) public function create($auth_type, $user_id, $ip, $user_agent)
{ {

View file

@ -3,9 +3,6 @@
namespace Model; namespace Model;
use Core\Session; use Core\Session;
use Core\Translator;
use Core\Template;
use Event\NotificationListener;
use Swift_Message; use Swift_Message;
use Swift_Mailer; use Swift_Mailer;
use Swift_TransportException; use Swift_TransportException;
@ -29,8 +26,8 @@ class Notification extends Base
* Get a list of people with notifications enabled * Get a list of people with notifications enabled
* *
* @access public * @access public
* @param integer $project_id Project id * @param integer $project_id Project id
* @param array $exlude_users List of user_id to exclude * @param array $exclude_users List of user_id to exclude
* @return array * @return array
*/ */
public function getUsersWithNotification($project_id, array $exclude_users = array()) public function getUsersWithNotification($project_id, array $exclude_users = array())
@ -61,15 +58,15 @@ class Notification extends Base
* Get the list of users to send the notification for a given project * Get the list of users to send the notification for a given project
* *
* @access public * @access public
* @param integer $project_id Project id * @param integer $project_id Project id
* @param array $exlude_users List of user_id to exclude * @param array $exclude_users List of user_id to exclude
* @return array * @return array
*/ */
public function getUsersList($project_id, array $exclude_users = array()) public function getUsersList($project_id, array $exclude_users = array())
{ {
// Exclude the connected user // Exclude the connected user
if (Session::isOpen()) { if (Session::isOpen()) {
$exclude_users[] = $this->acl->getUserId(); $exclude_users[] = $this->userSession->getId();
} }
$users = $this->getUsersWithNotification($project_id, $exclude_users); $users = $this->getUsersWithNotification($project_id, $exclude_users);
@ -93,37 +90,6 @@ class Notification extends Base
return $users; return $users;
} }
/**
* Attach events
*
* @access public
*/
public function attachEvents()
{
$events = array(
Task::EVENT_CREATE => 'task_creation',
Task::EVENT_UPDATE => 'task_update',
Task::EVENT_CLOSE => 'task_close',
Task::EVENT_OPEN => 'task_open',
Task::EVENT_MOVE_COLUMN => 'task_move_column',
Task::EVENT_MOVE_POSITION => 'task_move_position',
Task::EVENT_ASSIGNEE_CHANGE => 'task_assignee_change',
SubTask::EVENT_CREATE => 'subtask_creation',
SubTask::EVENT_UPDATE => 'subtask_update',
Comment::EVENT_CREATE => 'comment_creation',
Comment::EVENT_UPDATE => 'comment_update',
File::EVENT_CREATE => 'file_creation',
);
foreach ($events as $event_name => $template_name) {
$listener = new NotificationListener($this->container);
$listener->setTemplate($template_name);
$this->event->attach($event_name, $listener);
}
}
/** /**
* Send the email notifications * Send the email notifications
* *
@ -148,7 +114,7 @@ class Notification extends Base
} }
} }
catch (Swift_TransportException $e) { catch (Swift_TransportException $e) {
$this->container['logger']->addError($e->getMessage()); $this->container['logger']->error($e->getMessage());
} }
} }
@ -217,8 +183,10 @@ class Notification extends Base
*/ */
public function getMailContent($template, array $data) public function getMailContent($template, array $data)
{ {
$tpl = new Template; return $this->template->render(
return $tpl->load('notification/'.$template, $data + array('application_url' => $this->config->get('application_url'))); 'notification/'.$template,
$data + array('application_url' => $this->config->get('application_url'))
);
} }
/** /**

View file

@ -4,7 +4,6 @@ namespace Model;
use SimpleValidator\Validator; use SimpleValidator\Validator;
use SimpleValidator\Validators; use SimpleValidator\Validators;
use Event\ProjectModificationDateListener;
use Core\Security; use Core\Security;
/** /**
@ -52,12 +51,12 @@ class Project extends Base
* Get a project by the name * Get a project by the name
* *
* @access public * @access public
* @param string $project_name Project name * @param string $name Project name
* @return array * @return array
*/ */
public function getByName($project_name) public function getByName($name)
{ {
return $this->db->table(self::TABLE)->eq('name', $project_name)->findOne(); return $this->db->table(self::TABLE)->eq('name', $name)->findOne();
} }
/** /**
@ -110,7 +109,7 @@ class Project extends Base
foreach ($projects as $key => $project) { foreach ($projects as $key => $project) {
if (! $this->projectPermission->isUserAllowed($project['id'], $this->acl->getUserId())) { if (! $this->projectPermission->isUserAllowed($project['id'], $this->userSession->getId())) {
unset($projects[$key]); unset($projects[$key]);
} }
} }
@ -192,11 +191,12 @@ class Project extends Base
public function getStats($project_id) public function getStats($project_id)
{ {
$stats = array(); $stats = array();
$columns = $this->board->getColumns($project_id);
$stats['nb_active_tasks'] = 0; $stats['nb_active_tasks'] = 0;
$columns = $this->board->getColumns($project_id);
$column_stats = $this->board->getColumnStats($project_id);
foreach ($columns as &$column) { foreach ($columns as &$column) {
$column['nb_active_tasks'] = $this->taskFinder->countByColumnId($project_id, $column['id']); $column['nb_active_tasks'] = isset($column_stats[$column['id']]) ? $column_stats[$column['id']] : 0;
$stats['nb_active_tasks'] += $column['nb_active_tasks']; $stats['nb_active_tasks'] += $column['nb_active_tasks'];
} }
@ -228,7 +228,7 @@ class Project extends Base
); );
if (! $this->db->table(self::TABLE)->save($values)) { if (! $this->db->table(self::TABLE)->save($values)) {
return false; return 0;
} }
return $this->db->getConnection()->getLastId(); return $this->db->getConnection()->getLastId();
@ -296,9 +296,11 @@ class Project extends Base
} }
if ($add_user && $user_id) { if ($add_user && $user_id) {
$this->projectPermission->allowUser($project_id, $user_id); $this->projectPermission->addManager($project_id, $user_id);
} }
$this->category->createDefaultCategories($project_id);
$this->db->closeTransaction(); $this->db->closeTransaction();
return (int) $project_id; return (int) $project_id;
@ -489,34 +491,4 @@ class Project extends Base
$v->getErrors() $v->getErrors()
); );
} }
/**
* Attach events
*
* @access public
*/
public function attachEvents()
{
$events = array(
Task::EVENT_CREATE_UPDATE,
Task::EVENT_CLOSE,
Task::EVENT_OPEN,
Task::EVENT_MOVE_COLUMN,
Task::EVENT_MOVE_POSITION,
Task::EVENT_ASSIGNEE_CHANGE,
GithubWebhook::EVENT_ISSUE_OPENED,
GithubWebhook::EVENT_ISSUE_CLOSED,
GithubWebhook::EVENT_ISSUE_REOPENED,
GithubWebhook::EVENT_ISSUE_ASSIGNEE_CHANGE,
GithubWebhook::EVENT_ISSUE_LABEL_CHANGE,
GithubWebhook::EVENT_ISSUE_COMMENT,
GithubWebhook::EVENT_COMMIT,
);
$listener = new ProjectModificationDateListener($this->container);
foreach ($events as $event_name) {
$this->event->attach($event_name, $listener);
}
}
} }

View file

@ -2,9 +2,6 @@
namespace Model; namespace Model;
use Core\Template;
use Event\ProjectActivityListener;
/** /**
* Project activity model * Project activity model
* *
@ -25,7 +22,7 @@ class ProjectActivity extends Base
* *
* @var integer * @var integer
*/ */
const MAX_EVENTS = 5000; const MAX_EVENTS = 1000;
/** /**
* Add a new event for the project * Add a new event for the project
@ -46,7 +43,7 @@ class ProjectActivity extends Base
'creator_id' => $creator_id, 'creator_id' => $creator_id,
'event_name' => $event_name, 'event_name' => $event_name,
'date_creation' => time(), 'date_creation' => time(),
'data' => serialize($data), 'data' => json_encode($data),
); );
$this->cleanup(self::MAX_EVENTS - 1); $this->cleanup(self::MAX_EVENTS - 1);
@ -70,13 +67,13 @@ class ProjectActivity extends Base
* Get all events for the given projects list * Get all events for the given projects list
* *
* @access public * @access public
* @param integer $project_id Project id * @param integer[] $project_ids Projects id
* @param integer $limit Maximum events number * @param integer $limit Maximum events number
* @return array * @return array
*/ */
public function getProjects(array $projects, $limit = 50) public function getProjects(array $project_ids, $limit = 50)
{ {
if (empty($projects)) { if (empty($project_ids)) {
return array(); return array();
} }
@ -86,7 +83,7 @@ class ProjectActivity extends Base
User::TABLE.'.username AS author_username', User::TABLE.'.username AS author_username',
User::TABLE.'.name AS author_name' User::TABLE.'.name AS author_name'
) )
->in('project_id', $projects) ->in('project_id', $project_ids)
->join(User::TABLE, 'id', 'creator_id') ->join(User::TABLE, 'id', 'creator_id')
->desc('id') ->desc('id')
->limit($limit) ->limit($limit)
@ -94,7 +91,7 @@ class ProjectActivity extends Base
foreach ($events as &$event) { foreach ($events as &$event) {
$event += unserialize($event['data']); $event += $this->decode($event['data']);
unset($event['data']); unset($event['data']);
$event['author'] = $event['author_name'] ?: $event['author_username']; $event['author'] = $event['author_name'] ?: $event['author_username'];
@ -126,34 +123,6 @@ class ProjectActivity extends Base
} }
} }
/**
* Attach events to be able to record the history
*
* @access public
*/
public function attachEvents()
{
$events = array(
Task::EVENT_ASSIGNEE_CHANGE,
Task::EVENT_UPDATE,
Task::EVENT_CREATE,
Task::EVENT_CLOSE,
Task::EVENT_OPEN,
Task::EVENT_MOVE_COLUMN,
Task::EVENT_MOVE_POSITION,
Comment::EVENT_UPDATE,
Comment::EVENT_CREATE,
SubTask::EVENT_UPDATE,
SubTask::EVENT_CREATE,
);
$listener = new ProjectActivityListener($this->container);
foreach ($events as $event_name) {
$this->event->attach($event_name, $listener);
}
}
/** /**
* Get the event html content * Get the event html content
* *
@ -163,8 +132,10 @@ class ProjectActivity extends Base
*/ */
public function getContent(array $params) public function getContent(array $params)
{ {
$tpl = new Template; return $this->template->render(
return $tpl->load('event/'.str_replace('.', '_', $params['event_name']), $params); 'event/'.str_replace('.', '_', $params['event_name']),
$params
);
} }
/** /**
@ -203,4 +174,20 @@ class ProjectActivity extends Base
return ''; return '';
} }
} }
/**
* Decode event data, supports unserialize() and json_decode()
*
* @access public
* @param string $data Serialized data
* @return array
*/
public function decode($data)
{
if ($data{0} === 'a') {
return unserialize($data);
}
return json_decode($data, true) ?: array();
}
} }

View file

@ -2,9 +2,6 @@
namespace Model; namespace Model;
use Core\Template;
use Event\ProjectDailySummaryListener;
/** /**
* Project daily summary * Project daily summary
* *
@ -157,25 +154,4 @@ class ProjectDailySummary extends Base
return $metrics; return $metrics;
} }
/**
* Attach events to be able to record the metrics
*
* @access public
*/
public function attachEvents()
{
$events = array(
Task::EVENT_CREATE,
Task::EVENT_CLOSE,
Task::EVENT_OPEN,
Task::EVENT_MOVE_COLUMN,
);
$listener = new ProjectDailySummaryListener($this->container);
foreach ($events as $event_name) {
$this->event->attach($event_name, $listener);
}
}
} }

View file

@ -38,9 +38,10 @@ class ProjectPaginator extends Base
foreach ($projects as &$project) { foreach ($projects as &$project) {
$project['columns'] = $this->board->getColumns($project['id']); $project['columns'] = $this->board->getColumns($project['id']);
$stats = $this->board->getColumnStats($project['id']);
foreach ($project['columns'] as &$column) { foreach ($project['columns'] as &$column) {
$column['nb_tasks'] = $this->taskFinder->countByColumnId($project['id'], $column['id']); $column['nb_tasks'] = isset($stats[$column['id']]) ? $stats[$column['id']] : 0;
} }
} }

View file

@ -85,6 +85,27 @@ class ProjectPermission extends Base
return $this->user->prepareList($users); return $this->user->prepareList($users);
} }
/**
* Get a list of owners for a project
*
* @access public
* @param integer $project_id Project id
* @return array
*/
public function getManagers($project_id)
{
$users = $this->db
->table(self::TABLE)
->join(User::TABLE, 'id', 'user_id')
->eq('project_id', $project_id)
->eq('is_owner', 1)
->asc('username')
->columns(User::TABLE.'.id', User::TABLE.'.username', User::TABLE.'.name')
->findAll();
return $this->user->prepareList($users);
}
/** /**
* Get allowed and not allowed users for a project * Get allowed and not allowed users for a project
* *
@ -97,11 +118,13 @@ class ProjectPermission extends Base
$users = array( $users = array(
'allowed' => array(), 'allowed' => array(),
'not_allowed' => array(), 'not_allowed' => array(),
'managers' => array(),
); );
$all_users = $this->user->getList(); $all_users = $this->user->getList();
$users['allowed'] = $this->getMembers($project_id); $users['allowed'] = $this->getMembers($project_id);
$users['managers'] = $this->getManagers($project_id);
foreach ($all_users as $user_id => $username) { foreach ($all_users as $user_id => $username) {
@ -114,14 +137,14 @@ class ProjectPermission extends Base
} }
/** /**
* Allow a specific user for a given project * Add a new project member
* *
* @access public * @access public
* @param integer $project_id Project id * @param integer $project_id Project id
* @param integer $user_id User id * @param integer $user_id User id
* @return bool * @return bool
*/ */
public function allowUser($project_id, $user_id) public function addMember($project_id, $user_id)
{ {
return $this->db return $this->db
->table(self::TABLE) ->table(self::TABLE)
@ -129,14 +152,14 @@ class ProjectPermission extends Base
} }
/** /**
* Revoke a specific user for a given project * Remove a member
* *
* @access public * @access public
* @param integer $project_id Project id * @param integer $project_id Project id
* @param integer $user_id User id * @param integer $user_id User id
* @return bool * @return bool
*/ */
public function revokeUser($project_id, $user_id) public function revokeMember($project_id, $user_id)
{ {
return $this->db return $this->db
->table(self::TABLE) ->table(self::TABLE)
@ -145,6 +168,39 @@ class ProjectPermission extends Base
->remove(); ->remove();
} }
/**
* Add a project manager
*
* @access public
* @param integer $project_id Project id
* @param integer $user_id User id
* @return bool
*/
public function addManager($project_id, $user_id)
{
return $this->db
->table(self::TABLE)
->save(array('project_id' => $project_id, 'user_id' => $user_id, 'is_owner' => 1));
}
/**
* Change the role of a member
*
* @access public
* @param integer $project_id Project id
* @param integer $user_id User id
* @param integer $is_owner Is user owner of the project
* @return bool
*/
public function changeRole($project_id, $user_id, $is_owner)
{
return $this->db
->table(self::TABLE)
->eq('project_id', $project_id)
->eq('user_id', $user_id)
->update(array('is_owner' => (int) $is_owner));
}
/** /**
* Check if a specific user is member of a project * Check if a specific user is member of a project
* *
@ -159,11 +215,29 @@ class ProjectPermission extends Base
return true; return true;
} }
return (bool) $this->db return $this->db
->table(self::TABLE) ->table(self::TABLE)
->eq('project_id', $project_id) ->eq('project_id', $project_id)
->eq('user_id', $user_id) ->eq('user_id', $user_id)
->count(); ->count() === 1;
}
/**
* Check if a specific user is manager of a given project
*
* @access public
* @param integer $project_id Project id
* @param integer $user_id User id
* @return bool
*/
public function isManager($project_id, $user_id)
{
return $this->db
->table(self::TABLE)
->eq('project_id', $project_id)
->eq('user_id', $user_id)
->eq('is_owner', 1)
->count() === 1;
} }
/** /**
@ -188,28 +262,11 @@ class ProjectPermission extends Base
*/ */
public function isEverybodyAllowed($project_id) public function isEverybodyAllowed($project_id)
{ {
return (bool) $this->db return $this->db
->table(Project::TABLE) ->table(Project::TABLE)
->eq('id', $project_id) ->eq('id', $project_id)
->eq('is_everybody_allowed', 1) ->eq('is_everybody_allowed', 1)
->count(); ->count() === 1;
}
/**
* Check if a specific user is allowed to manage a project
*
* @access public
* @param integer $project_id Project id
* @param integer $user_id User id
* @return bool
*/
public function adminAllowed($project_id, $user_id)
{
if ($this->isUserAllowed($project_id, $user_id) && $this->project->isPrivate($project_id)) {
return true;
}
return false;
} }
/** /**
@ -241,7 +298,11 @@ class ProjectPermission extends Base
*/ */
public function getAllowedProjects($user_id) public function getAllowedProjects($user_id)
{ {
return $this->filterProjects($this->project->getListByStatus(Project::ACTIVE), $user_id, 'isUserAllowed'); if ($this->user->isAdmin($user_id)) {
return $this->project->getListByStatus(Project::ACTIVE);
}
return $this->getMemberProjects($user_id);
} }
/** /**
@ -253,23 +314,39 @@ class ProjectPermission extends Base
*/ */
public function getMemberProjects($user_id) public function getMemberProjects($user_id)
{ {
return $this->filterProjects($this->project->getListByStatus(Project::ACTIVE), $user_id, 'isMember'); return $this->db
->table(Project::TABLE)
->eq('user_id', $user_id)
->join(self::TABLE, 'project_id', 'id')
->listing('projects.id', 'name');
} }
/** /**
* Copy user access from a project to another one * Copy user access from a project to another one
* *
* @author Antonio Rabelo * @param integer $project_src Project Template
* @param integer $project_from Project Template * @return integer $project_dst Project that receives the copy
* @return integer $project_to Project that receives the copy
* @return boolean * @return boolean
*/ */
public function duplicate($project_from, $project_to) public function duplicate($project_src, $project_dst)
{ {
$users = $this->getMembers($project_from); $rows = $this->db
->table(self::TABLE)
->columns('project_id', 'user_id', 'is_owner')
->eq('project_id', $project_src)
->findAll();
foreach ($users as $user_id => $name) { foreach ($rows as $row) {
if (! $this->allowUser($project_to, $user_id)) {
$result = $this->db
->table(self::TABLE)
->save(array(
'project_id' => $project_dst,
'user_id' => $row['user_id'],
'is_owner' => (int) $row['is_owner'], // (int) for postgres
));
if (! $result) {
return false; return false;
} }
} }
@ -291,6 +368,7 @@ class ProjectPermission extends Base
new Validators\Integer('project_id', t('This value must be an integer')), new Validators\Integer('project_id', t('This value must be an integer')),
new Validators\Required('user_id', t('The user id is required')), new Validators\Required('user_id', t('The user id is required')),
new Validators\Integer('user_id', t('This value must be an integer')), new Validators\Integer('user_id', t('This value must be an integer')),
new Validators\Integer('is_owner', t('This value must be an integer')),
)); ));
return array( return array(

View file

@ -2,6 +2,7 @@
namespace Model; namespace Model;
use Event\SubtaskEvent;
use SimpleValidator\Validator; use SimpleValidator\Validator;
use SimpleValidator\Validators; use SimpleValidator\Validators;
@ -57,15 +58,11 @@ class SubTask extends Base
*/ */
public function getStatusList() public function getStatusList()
{ {
$status = array( return array(
self::STATUS_TODO => t('Todo'), self::STATUS_TODO => t('Todo'),
self::STATUS_INPROGRESS => t('In progress'), self::STATUS_INPROGRESS => t('In progress'),
self::STATUS_DONE => t('Done'), self::STATUS_DONE => t('Done'),
); );
asort($status);
return $status;
} }
/** /**
@ -146,7 +143,10 @@ class SubTask extends Base
$subtask_id = $this->persist(self::TABLE, $values); $subtask_id = $this->persist(self::TABLE, $values);
if ($subtask_id) { if ($subtask_id) {
$this->event->trigger(self::EVENT_CREATE, array('id' => $subtask_id) + $values); $this->container['dispatcher']->dispatch(
self::EVENT_CREATE,
new SubtaskEvent(array('id' => $subtask_id) + $values)
);
} }
return $subtask_id; return $subtask_id;
@ -165,7 +165,10 @@ class SubTask extends Base
$result = $this->db->table(self::TABLE)->eq('id', $values['id'])->save($values); $result = $this->db->table(self::TABLE)->eq('id', $values['id'])->save($values);
if ($result) { if ($result) {
$this->event->trigger(self::EVENT_UPDATE, $values); $this->container['dispatcher']->dispatch(
self::EVENT_UPDATE,
new SubtaskEvent($values)
);
} }
return $result; return $result;
@ -220,6 +223,7 @@ class SubTask extends Base
$subtasks = $db->table(SubTask::TABLE) $subtasks = $db->table(SubTask::TABLE)
->columns('title', 'time_estimated') ->columns('title', 'time_estimated')
->eq('task_id', $src_task_id) ->eq('task_id', $src_task_id)
->asc('id') // Explicit sorting for postgresql
->findAll(); ->findAll();
foreach ($subtasks as &$subtask) { foreach ($subtasks as &$subtask) {

View file

@ -0,0 +1,119 @@
<?php
namespace Model;
/**
* Subtask Export
*
* @package model
* @author Frederic Guillot
*/
class SubtaskExport extends Base
{
/**
* Subtask statuses
*
* @access private
* @var array
*/
private $subtask_status = array();
/**
* Fetch subtasks and return the prepared CSV
*
* @access public
* @param integer $project_id Project id
* @param mixed $from Start date (timestamp or user formatted date)
* @param mixed $to End date (timestamp or user formatted date)
* @return array
*/
public function export($project_id, $from, $to)
{
$this->subtask_status = $this->subTask->getStatusList();
$subtasks = $this->getSubtasks($project_id, $from, $to);
$results = array($this->getColumns());
foreach ($subtasks as $subtask) {
$results[] = $this->format($subtask);
}
return $results;
}
/**
* Get column titles
*
* @access public
* @return string[]
*/
public function getColumns()
{
return array(
e('Subtask Id'),
e('Title'),
e('Status'),
e('Assignee'),
e('Time estimated'),
e('Time spent'),
e('Task Id'),
e('Task Title'),
);
}
/**
* Format the output of a subtask array
*
* @access public
* @param array $subtask Subtask properties
* @return array
*/
public function format(array $subtask)
{
$values = array();
$values[] = $subtask['id'];
$values[] = $subtask['title'];
$values[] = $this->subtask_status[$subtask['status']];
$values[] = $subtask['assignee_name'] ?: $subtask['assignee_username'];
$values[] = $subtask['time_estimated'];
$values[] = $subtask['time_spent'];
$values[] = $subtask['task_id'];
$values[] = $subtask['task_title'];
return $values;
}
/**
* Get all subtasks for a given project
*
* @access public
* @param integer $task_id Task id
* @param mixed $from Start date (timestamp or user formatted date)
* @param mixed $to End date (timestamp or user formatted date)
* @return array
*/
public function getSubtasks($project_id, $from, $to)
{
if (! is_numeric($from)) {
$from = $this->dateParser->resetDateToMidnight($this->dateParser->getTimestamp($from));
}
if (! is_numeric($to)) {
$to = $this->dateParser->resetDateToMidnight(strtotime('+1 day', $this->dateParser->getTimestamp($to)));
}
return $this->db->table(SubTask::TABLE)
->eq('project_id', $project_id)
->columns(
SubTask::TABLE.'.*',
User::TABLE.'.username AS assignee_username',
User::TABLE.'.name AS assignee_name',
Task::TABLE.'.title AS task_title'
)
->gte('date_creation', $from)
->lte('date_creation', $to)
->join(Task::TABLE, 'id', 'task_id')
->join(User::TABLE, 'id', 'user_id')
->asc(SubTask::TABLE.'.id')
->findAll();
}
}

View file

@ -0,0 +1,495 @@
<?php
namespace Model;
use SimpleValidator\Validator;
use SimpleValidator\Validators;
/**
* Swimlanes
*
* @package model
* @author Frederic Guillot
*/
class Swimlane extends Base
{
/**
* SQL table name
*
* @var string
*/
const TABLE = 'swimlanes';
/**
* Value for active swimlanes
*
* @var integer
*/
const ACTIVE = 1;
/**
* Value for inactive swimlanes
*
* @var integer
*/
const INACTIVE = 0;
/**
* Get a swimlane by the id
*
* @access public
* @param integer $swimlane_id Swimlane id
* @return array
*/
public function getById($swimlane_id)
{
return $this->db->table(self::TABLE)->eq('id', $swimlane_id)->findOne();
}
/**
* Get the swimlane name by the id
*
* @access public
* @param integer $swimlane_id Swimlane id
* @return string
*/
public function getNameById($swimlane_id)
{
return $this->db->table(self::TABLE)->eq('id', $swimlane_id)->findOneColumn('name') ?: '';
}
/**
* Get a swimlane id by the project and the name
*
* @access public
* @param integer $project_id Project id
* @param string $name Name
* @return integer
*/
public function getIdByName($project_id, $name)
{
return (int) $this->db->table(self::TABLE)
->eq('project_id', $project_id)
->eq('name', $name)
->findOneColumn('id');
}
/**
* Get default swimlane properties
*
* @access public
* @param integer $project_id Project id
* @return array
*/
public function getDefault($project_id)
{
return $this->db->table(Project::TABLE)
->eq('id', $project_id)
->columns('id', 'default_swimlane', 'show_default_swimlane')
->findOne();
}
/**
* Get all swimlanes for a given project
*
* @access public
* @param integer $project_id Project id
* @return array
*/
public function getAll($project_id)
{
return $this->db->table(self::TABLE)
->eq('project_id', $project_id)
->orderBy('position', 'asc')
->findAll();
}
/**
* Get the list of swimlanes by status
*
* @access public
* @param integer $project_id Project id
* @param integer $status Status
* @return array
*/
public function getAllByStatus($project_id, $status = self::ACTIVE)
{
$query = $this->db->table(self::TABLE)
->eq('project_id', $project_id)
->eq('is_active', $status);
if ($status == self::ACTIVE) {
$query->asc('position');
}
else {
$query->asc('name');
}
return $query->findAll();
}
/**
* Get active swimlanes
*
* @access public
* @param integer $project_id Project id
* @return array
*/
public function getSwimlanes($project_id)
{
$swimlanes = $this->db->table(self::TABLE)
->columns('id', 'name')
->eq('project_id', $project_id)
->eq('is_active', self::ACTIVE)
->orderBy('position', 'asc')
->findAll();
$default_swimlane = $this->db->table(Project::TABLE)
->eq('id', $project_id)
->eq('show_default_swimlane', 1)
->findOneColumn('default_swimlane');
if ($default_swimlane) {
array_unshift($swimlanes, array('id' => 0, 'name' => $default_swimlane));
}
return $swimlanes;
}
/**
* Get list of all swimlanes
*
* @access public
* @param integer $project_id Project id
* @return array
*/
public function getSwimlanesList($project_id)
{
$swimlanes = $this->db->table(self::TABLE)
->eq('project_id', $project_id)
->orderBy('position', 'asc')
->listing('id', 'name');
$swimlanes[0] = $this->db->table(Project::TABLE)
->eq('id', $project_id)
->findOneColumn('default_swimlane');
return $swimlanes;
}
/**
* Add a new swimlane
*
* @access public
* @param integer $project_id
* @param string $name
* @return bool
*/
public function create($project_id, $name)
{
return $this->persist(self::TABLE, array(
'project_id' => $project_id,
'name' => $name,
'position' => $this->getLastPosition($project_id),
));
}
/**
* Rename a swimlane
*
* @access public
* @param integer $swimlane_id Swimlane id
* @param string $name Swimlane name
* @return bool
*/
public function rename($swimlane_id, $name)
{
return $this->db->table(self::TABLE)
->eq('id', $swimlane_id)
->update(array('name' => $name));
}
/**
* Update the default swimlane
*
* @access public
* @param array $values Form values
* @return bool
*/
public function updateDefault(array $values)
{
return $this->db
->table(Project::TABLE)
->eq('id', $values['id'])
->update(array(
'default_swimlane' => $values['default_swimlane'],
'show_default_swimlane' => $values['show_default_swimlane'],
));
}
/**
* Get the last position of a swimlane
*
* @access public
* @param integer $project_id
* @return integer
*/
public function getLastPosition($project_id)
{
return $this->db->table(self::TABLE)
->eq('project_id', $project_id)
->eq('is_active', 1)
->count() + 1;
}
/**
* Disable a swimlane
*
* @access public
* @param integer $project_id Project id
* @param integer $swimlane_id Swimlane id
* @return bool
*/
public function disable($project_id, $swimlane_id)
{
$result = $this->db
->table(self::TABLE)
->eq('id', $swimlane_id)
->update(array(
'is_active' => self::INACTIVE,
'position' => 0,
));
if ($result) {
// Re-order positions
$this->updatePositions($project_id);
}
return $result;
}
/**
* Enable a swimlane
*
* @access public
* @param integer $project_id Project id
* @param integer $swimlane_id Swimlane id
* @return bool
*/
public function enable($project_id, $swimlane_id)
{
return $this->db
->table(self::TABLE)
->eq('id', $swimlane_id)
->update(array(
'is_active' => self::ACTIVE,
'position' => $this->getLastPosition($project_id),
));
}
/**
* Remove a swimlane
*
* @access public
* @param integer $project_id Project id
* @param integer $swimlane_id Swimlane id
* @return bool
*/
public function remove($project_id, $swimlane_id)
{
$this->db->startTransaction();
// Tasks should not be assigned anymore to this swimlane
$this->db->table(Task::TABLE)->eq('swimlane_id', $swimlane_id)->update(array('swimlane_id' => 0));
if (! $this->db->table(self::TABLE)->eq('id', $swimlane_id)->remove()) {
$this->db->cancelTransaction();
return false;
}
// Re-order positions
$this->updatePositions($project_id);
$this->db->closeTransaction();
return true;
}
/**
* Update swimlane positions after disabling or removing a swimlane
*
* @access public
* @param integer $project_id Project id
* @return boolean
*/
public function updatePositions($project_id)
{
$position = 0;
$swimlanes = $this->db->table(self::TABLE)
->eq('project_id', $project_id)
->eq('is_active', 1)
->asc('position')
->findAllByColumn('id');
if (! $swimlanes) {
return false;
}
foreach ($swimlanes as $swimlane_id) {
$this->db->table(self::TABLE)
->eq('id', $swimlane_id)
->update(array('position' => ++$position));
}
return true;
}
/**
* Move a swimlane down, increment the position value
*
* @access public
* @param integer $project_id Project id
* @param integer $swimlane_id Swimlane id
* @return boolean
*/
public function moveDown($project_id, $swimlane_id)
{
$swimlanes = $this->db->table(self::TABLE)
->eq('project_id', $project_id)
->eq('is_active', self::ACTIVE)
->asc('position')
->listing('id', 'position');
$positions = array_flip($swimlanes);
if (isset($swimlanes[$swimlane_id]) && $swimlanes[$swimlane_id] < count($swimlanes)) {
$position = ++$swimlanes[$swimlane_id];
$swimlanes[$positions[$position]]--;
$this->db->startTransaction();
$this->db->table(self::TABLE)->eq('id', $swimlane_id)->update(array('position' => $position));
$this->db->table(self::TABLE)->eq('id', $positions[$position])->update(array('position' => $swimlanes[$positions[$position]]));
$this->db->closeTransaction();
return true;
}
return false;
}
/**
* Move a swimlane up, decrement the position value
*
* @access public
* @param integer $project_id Project id
* @param integer $swimlane_id Swimlane id
* @return boolean
*/
public function moveUp($project_id, $swimlane_id)
{
$swimlanes = $this->db->table(self::TABLE)
->eq('project_id', $project_id)
->eq('is_active', self::ACTIVE)
->asc('position')
->listing('id', 'position');
$positions = array_flip($swimlanes);
if (isset($swimlanes[$swimlane_id]) && $swimlanes[$swimlane_id] > 1) {
$position = --$swimlanes[$swimlane_id];
$swimlanes[$positions[$position]]++;
$this->db->startTransaction();
$this->db->table(self::TABLE)->eq('id', $swimlane_id)->update(array('position' => $position));
$this->db->table(self::TABLE)->eq('id', $positions[$position])->update(array('position' => $swimlanes[$positions[$position]]));
$this->db->closeTransaction();
return true;
}
return false;
}
/**
* Validate creation
*
* @access public
* @param array $values Form values
* @return array $valid, $errors [0] = Success or not, [1] = List of errors
*/
public function validateCreation(array $values)
{
$rules = array(
new Validators\Required('project_id', t('The project id is required')),
new Validators\Required('name', t('The name is required')),
);
$v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
return array(
$v->execute(),
$v->getErrors()
);
}
/**
* Validate modification
*
* @access public
* @param array $values Form values
* @return array $valid, $errors [0] = Success or not, [1] = List of errors
*/
public function validateModification(array $values)
{
$rules = array(
new Validators\Required('id', t('The id is required')),
new Validators\Required('name', t('The name is required')),
);
$v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
return array(
$v->execute(),
$v->getErrors()
);
}
/**
* Validate default swimlane modification
*
* @access public
* @param array $values Form values
* @return array $valid, $errors [0] = Success or not, [1] = List of errors
*/
public function validateDefaultModification(array $values)
{
$rules = array(
new Validators\Required('id', t('The id is required')),
new Validators\Required('default_swimlane', t('The name is required')),
);
$v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
return array(
$v->execute(),
$v->getErrors()
);
}
/**
* Common validation rules
*
* @access private
* @return array
*/
private function commonValidationRules()
{
return array(
new Validators\Integer('id', t('The id must be an integer')),
new Validators\Integer('project_id', t('The project id must be an integer')),
new Validators\MaxLength('name', t('The maximum length is %d characters', 50), 50)
);
}
}

Some files were not shown because too many files have changed in this diff Show more