summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/Action/CommentCreation.php1
-rw-r--r--app/Api/Project.php6
-rw-r--r--app/Api/Task.php2
-rw-r--r--app/Auth/GitHub.php163
-rw-r--r--app/Auth/Github.php122
-rw-r--r--app/Auth/Google.php85
-rw-r--r--app/Auth/Ldap.php2
-rw-r--r--app/Auth/RememberMe.php4
-rw-r--r--app/Controller/Action.php8
-rw-r--r--app/Controller/Auth.php8
-rw-r--r--app/Controller/Base.php22
-rw-r--r--app/Controller/Board.php58
-rw-r--r--app/Controller/Category.php8
-rw-r--r--app/Controller/Comment.php8
-rw-r--r--app/Controller/Config.php6
-rw-r--r--app/Controller/Oauth.php123
-rw-r--r--app/Controller/Project.php25
-rw-r--r--app/Controller/Search.php2
-rw-r--r--app/Controller/Subtask.php12
-rw-r--r--app/Controller/Swimlane.php18
-rw-r--r--app/Controller/Task.php42
-rw-r--r--app/Controller/User.php168
-rw-r--r--app/Core/HttpClient.php21
-rw-r--r--app/Core/Lexer.php2
-rw-r--r--app/Core/OAuth2.php120
-rw-r--r--app/Core/Request.php11
-rw-r--r--app/Core/Router.php195
-rw-r--r--app/Core/Session.php2
-rw-r--r--app/Helper/Asset.php4
-rw-r--r--app/Helper/Url.php96
-rw-r--r--app/Integration/GitlabWebhook.php67
-rw-r--r--app/Integration/HipchatWebhook.php3
-rw-r--r--app/Integration/Jabber.php3
-rw-r--r--app/Integration/SlackWebhook.php3
-rw-r--r--app/Locale/da_DK/translations.php63
-rw-r--r--app/Locale/de_DE/translations.php315
-rw-r--r--app/Locale/es_ES/translations.php59
-rw-r--r--app/Locale/fi_FI/translations.php59
-rw-r--r--app/Locale/fr_FR/translations.php63
-rw-r--r--app/Locale/hu_HU/translations.php73
-rw-r--r--app/Locale/it_IT/translations.php59
-rw-r--r--app/Locale/ja_JP/translations.php63
-rw-r--r--app/Locale/nl_NL/translations.php59
-rw-r--r--app/Locale/pl_PL/translations.php59
-rw-r--r--app/Locale/pt_BR/translations.php303
-rw-r--r--app/Locale/ru_RU/translations.php79
-rw-r--r--app/Locale/sr_Latn_RS/translations.php59
-rw-r--r--app/Locale/sv_SE/translations.php63
-rw-r--r--app/Locale/th_TH/translations.php59
-rw-r--r--app/Locale/tr_TR/translations.php59
-rw-r--r--app/Locale/zh_CN/translations.php59
-rw-r--r--app/Model/Acl.php4
-rw-r--r--app/Model/Action.php1
-rw-r--r--app/Model/TaskFilter.php27
-rw-r--r--app/Model/TaskFinder.php3
-rw-r--r--app/Model/User.php14
-rw-r--r--app/ServiceProvider/ClassProvider.php6
-rw-r--r--app/Template/app/overview.php4
-rw-r--r--app/Template/auth/index.php22
-rw-r--r--app/Template/board/task_menu.php1
-rw-r--r--app/Template/config/integrations.php30
-rw-r--r--app/Template/config/webhook.php2
-rw-r--r--app/Template/feed/project.php6
-rw-r--r--app/Template/feed/user.php6
-rw-r--r--app/Template/layout.php10
-rw-r--r--app/Template/listing/show.php18
-rw-r--r--app/Template/notification/footer.php4
-rw-r--r--app/Template/notification/task_overdue.php2
-rw-r--r--app/Template/project/filters.php11
-rw-r--r--app/Template/project/integrations.php12
-rw-r--r--app/Template/search/index.php2
-rw-r--r--app/Template/search/results.php20
-rw-r--r--app/Template/task/edit_recurrence.php9
-rw-r--r--app/Template/user/authentication.php32
-rw-r--r--app/Template/user/create_local.php (renamed from app/Template/user/new.php)1
-rw-r--r--app/Template/user/create_remote.php57
-rw-r--r--app/Template/user/edit.php11
-rw-r--r--app/Template/user/external.php8
-rw-r--r--app/Template/user/index.php3
-rw-r--r--app/Template/user/layout.php3
-rw-r--r--app/Template/user/sidebar.php3
-rw-r--r--app/common.php96
-rw-r--r--app/constants.php12
83 files changed, 2211 insertions, 1202 deletions
diff --git a/app/Action/CommentCreation.php b/app/Action/CommentCreation.php
index 5dfd1c89..4029c875 100644
--- a/app/Action/CommentCreation.php
+++ b/app/Action/CommentCreation.php
@@ -28,6 +28,7 @@ class CommentCreation extends Base
BitbucketWebhook::EVENT_ISSUE_COMMENT,
BitbucketWebhook::EVENT_COMMIT,
GitlabWebhook::EVENT_COMMIT,
+ GitlabWebhook::EVENT_ISSUE_COMMENT,
);
}
diff --git a/app/Api/Project.php b/app/Api/Project.php
index faf2a3da..4e4e10b8 100644
--- a/app/Api/Project.php
+++ b/app/Api/Project.php
@@ -87,9 +87,9 @@ class Project extends Base
{
if (! empty($project)) {
$project['url'] = array(
- 'board' => $this->helper->url->base().$this->helper->url->to('board', 'show', array('project_id' => $project['id'])),
- 'calendar' => $this->helper->url->base().$this->helper->url->to('calendar', 'show', array('project_id' => $project['id'])),
- 'list' => $this->helper->url->base().$this->helper->url->to('listing', 'show', array('project_id' => $project['id'])),
+ 'board' => $this->helper->url->to('board', 'show', array('project_id' => $project['id']), '', true),
+ 'calendar' => $this->helper->url->to('calendar', 'show', array('project_id' => $project['id']), '', true),
+ 'list' => $this->helper->url->to('listing', 'show', array('project_id' => $project['id']), '', true),
);
}
diff --git a/app/Api/Task.php b/app/Api/Task.php
index ade49a6d..3b8c1ec8 100644
--- a/app/Api/Task.php
+++ b/app/Api/Task.php
@@ -119,7 +119,7 @@ class Task extends Base
private function formatTask($task)
{
if (! empty($task)) {
- $task['url'] = $this->helper->url->base().$this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']));
+ $task['url'] = $this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), '', true);
}
return $task;
diff --git a/app/Auth/GitHub.php b/app/Auth/GitHub.php
deleted file mode 100644
index 816cc9c1..00000000
--- a/app/Auth/GitHub.php
+++ /dev/null
@@ -1,163 +0,0 @@
-<?php
-
-namespace Auth;
-
-use Event\AuthEvent;
-use OAuth\Common\Storage\Session;
-use OAuth\Common\Consumer\Credentials;
-use OAuth\Common\Http\Uri\UriFactory;
-use OAuth\ServiceFactory;
-use OAuth\Common\Http\Exception\TokenResponseException;
-
-/**
- * GitHub backend
- *
- * @package auth
- */
-class GitHub extends Base
-{
- /**
- * Backend name
- *
- * @var string
- */
- const AUTH_NAME = 'Github';
-
- /**
- * Authenticate a GitHub user
- *
- * @access public
- * @param string $github_id GitHub user id
- * @return boolean
- */
- public function authenticate($github_id)
- {
- $user = $this->user->getByGitHubId($github_id);
-
- if (! empty($user)) {
- $this->userSession->refresh($user);
- $this->container['dispatcher']->dispatch('auth.success', new AuthEvent(self::AUTH_NAME, $user['id']));
- return true;
- }
-
- return false;
- }
-
- /**
- * Unlink a GitHub account for a given user
- *
- * @access public
- * @param integer $user_id User id
- * @return boolean
- */
- public function unlink($user_id)
- {
- return $this->user->update(array(
- 'id' => $user_id,
- 'github_id' => '',
- ));
- }
-
- /**
- * Update the user table based on the GitHub profile information
- *
- * @access public
- * @param integer $user_id User id
- * @param array $profile GitHub profile
- * @return boolean
- * @todo Don't overwrite existing email/name with empty GitHub data
- */
- public function updateUser($user_id, array $profile)
- {
- return $this->user->update(array(
- 'id' => $user_id,
- 'github_id' => $profile['id'],
- 'email' => $profile['email'],
- 'name' => $profile['name'],
- ));
- }
-
- /**
- * Get the GitHub service instance
- *
- * @access public
- * @return \OAuth\OAuth2\Service\GitHub
- */
- public function getService()
- {
- $uriFactory = new UriFactory();
- $currentUri = $uriFactory->createFromSuperGlobalArray($_SERVER);
- $currentUri->setQuery('controller=user&action=gitHub');
-
- $storage = new Session(false);
-
- $credentials = new Credentials(
- GITHUB_CLIENT_ID,
- GITHUB_CLIENT_SECRET,
- $currentUri->getAbsoluteUri()
- );
-
- $serviceFactory = new ServiceFactory();
-
- return $serviceFactory->createService(
- 'gitHub',
- $credentials,
- $storage,
- array('')
- );
- }
-
- /**
- * Get the authorization URL
- *
- * @access public
- * @return \OAuth\Common\Http\Uri\Uri
- */
- public function getAuthorizationUrl()
- {
- return $this->getService()->getAuthorizationUri();
- }
-
- /**
- * Get GitHub profile information from the API
- *
- * @access public
- * @param string $code GitHub authorization code
- * @return bool|array
- */
- public function getGitHubProfile($code)
- {
- try {
- $gitHubService = $this->getService();
- $gitHubService->requestAccessToken($code);
-
- return json_decode($gitHubService->request('user'), true);
- }
- catch (TokenResponseException $e) {
- return false;
- }
- }
-
- /**
- * Revokes this user's GitHub tokens for Kanboard
- *
- * @access public
- * @return bool|array
- * @todo Currently this simply removes all our tokens for this user, ideally it should
- * restrict itself to the one in question
- */
- public function revokeGitHubAccess()
- {
- try {
- $gitHubService = $this->getService();
-
- $basicAuthHeader = array('Authorization' => 'Basic ' .
- base64_encode(GITHUB_CLIENT_ID.':'.GITHUB_CLIENT_SECRET));
-
- return json_decode($gitHubService->request('/applications/'.GITHUB_CLIENT_ID.'/tokens', 'DELETE', null, $basicAuthHeader), true);
- }
- catch (TokenResponseException $e) {
- return false;
- }
- }
-}
diff --git a/app/Auth/Github.php b/app/Auth/Github.php
new file mode 100644
index 00000000..44bcc6c8
--- /dev/null
+++ b/app/Auth/Github.php
@@ -0,0 +1,122 @@
+<?php
+
+namespace Auth;
+
+use Event\AuthEvent;
+
+/**
+ * Github backend
+ *
+ * @package auth
+ */
+class Github extends Base
+{
+ /**
+ * Backend name
+ *
+ * @var string
+ */
+ const AUTH_NAME = 'Github';
+
+ /**
+ * OAuth2 instance
+ *
+ * @access private
+ * @var \Core\OAuth2
+ */
+ private $service;
+
+ /**
+ * Authenticate a Github user
+ *
+ * @access public
+ * @param string $github_id Github user id
+ * @return boolean
+ */
+ public function authenticate($github_id)
+ {
+ $user = $this->user->getByGithubId($github_id);
+
+ if (! empty($user)) {
+ $this->userSession->refresh($user);
+ $this->container['dispatcher']->dispatch('auth.success', new AuthEvent(self::AUTH_NAME, $user['id']));
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Unlink a Github account for a given user
+ *
+ * @access public
+ * @param integer $user_id User id
+ * @return boolean
+ */
+ public function unlink($user_id)
+ {
+ return $this->user->update(array(
+ 'id' => $user_id,
+ 'github_id' => '',
+ ));
+ }
+
+ /**
+ * Update the user table based on the Github profile information
+ *
+ * @access public
+ * @param integer $user_id User id
+ * @param array $profile Github profile
+ * @return boolean
+ */
+ public function updateUser($user_id, array $profile)
+ {
+ $user = $this->user->getById($user_id);
+
+ return $this->user->update(array(
+ 'id' => $user_id,
+ 'github_id' => $profile['id'],
+ 'email' => $profile['email'] ?: $user['email'],
+ 'name' => $profile['name'] ?: $user['name'],
+ ));
+ }
+
+ /**
+ * Get OAuth2 configured service
+ *
+ * @access public
+ * @return \Core\OAuth2
+ */
+ public function getService()
+ {
+ if (empty($this->service)) {
+ $this->service = $this->oauth->createService(
+ GITHUB_CLIENT_ID,
+ GITHUB_CLIENT_SECRET,
+ $this->helper->url->to('oauth', 'github', array(), '', true),
+ 'https://github.com/login/oauth/authorize',
+ 'https://github.com/login/oauth/access_token',
+ array()
+ );
+ }
+
+ return $this->service;
+ }
+
+ /**
+ * Get Github profile
+ *
+ * @access public
+ * @param string $code
+ * @return array
+ */
+ public function getProfile($code)
+ {
+ $this->getService()->getAccessToken($code);
+
+ return $this->httpClient->getJson(
+ 'https://api.github.com/user',
+ array($this->getService()->getAuthorizationHeader())
+ );
+ }
+}
diff --git a/app/Auth/Google.php b/app/Auth/Google.php
index 9a977037..972dd748 100644
--- a/app/Auth/Google.php
+++ b/app/Auth/Google.php
@@ -3,11 +3,6 @@
namespace Auth;
use Event\AuthEvent;
-use OAuth\Common\Storage\Session;
-use OAuth\Common\Consumer\Credentials;
-use OAuth\Common\Http\Uri\UriFactory;
-use OAuth\ServiceFactory;
-use OAuth\Common\Http\Exception\TokenResponseException;
/**
* Google backend
@@ -25,6 +20,14 @@ class Google extends Base
const AUTH_NAME = 'Google';
/**
+ * OAuth2 instance
+ *
+ * @access private
+ * @var \Core\OAuth2
+ */
+ private $service;
+
+ /**
* Authenticate a Google user
*
* @access public
@@ -69,72 +72,52 @@ class Google extends Base
*/
public function updateUser($user_id, array $profile)
{
+ $user = $this->user->getById($user_id);
+
return $this->user->update(array(
'id' => $user_id,
'google_id' => $profile['id'],
- 'email' => $profile['email'],
- 'name' => $profile['name'],
+ 'email' => $profile['email'] ?: $user['email'],
+ 'name' => $profile['name'] ?: $user['name'],
));
}
/**
- * Get the Google service instance
+ * Get OAuth2 configured service
*
* @access public
- * @return \OAuth\OAuth2\Service\Google
+ * @return \Core\OAuth2
*/
public function getService()
{
- $uriFactory = new UriFactory();
- $currentUri = $uriFactory->createFromSuperGlobalArray($_SERVER);
- $currentUri->setQuery('controller=user&action=google');
-
- $storage = new Session(false);
-
- $credentials = new Credentials(
- GOOGLE_CLIENT_ID,
- GOOGLE_CLIENT_SECRET,
- $currentUri->getAbsoluteUri()
- );
-
- $serviceFactory = new ServiceFactory();
-
- return $serviceFactory->createService(
- 'google',
- $credentials,
- $storage,
- array('userinfo_email', 'userinfo_profile')
- );
- }
+ if (empty($this->service)) {
+ $this->service = $this->oauth->createService(
+ GOOGLE_CLIENT_ID,
+ GOOGLE_CLIENT_SECRET,
+ $this->helper->url->to('oauth', 'google', array(), '', true),
+ 'https://accounts.google.com/o/oauth2/auth',
+ 'https://accounts.google.com/o/oauth2/token',
+ array('https://www.googleapis.com/auth/userinfo.email', 'https://www.googleapis.com/auth/userinfo.profile')
+ );
+ }
- /**
- * Get the authorization URL
- *
- * @access public
- * @return \OAuth\Common\Http\Uri\Uri
- */
- public function getAuthorizationUrl()
- {
- return $this->getService()->getAuthorizationUri();
+ return $this->service;
}
/**
- * Get Google profile information from the API
+ * Get Google profile
*
* @access public
- * @param string $code Google authorization code
- * @return bool|array
+ * @param string $code
+ * @return array
*/
- public function getGoogleProfile($code)
+ public function getProfile($code)
{
- try {
+ $this->getService()->getAccessToken($code);
- $googleService = $this->getService();
- $googleService->requestAccessToken($code);
- return json_decode($googleService->request('https://www.googleapis.com/oauth2/v1/userinfo'), true);
- }
- catch (TokenResponseException $e) {
- return false;
- }
+ return $this->httpClient->getJson(
+ 'https://www.googleapis.com/oauth2/v1/userinfo',
+ array($this->getService()->getAuthorizationHeader())
+ );
}
}
diff --git a/app/Auth/Ldap.php b/app/Auth/Ldap.php
index 3ee6ec9b..c1459b4e 100644
--- a/app/Auth/Ldap.php
+++ b/app/Auth/Ldap.php
@@ -46,7 +46,7 @@ class Ldap extends Base
else {
// We create automatically a new user
- if ($this->createUser($username, $result['name'], $result['email'])) {
+ if (LDAP_ACCOUNT_CREATION && $this->createUser($username, $result['name'], $result['email'])) {
$user = $this->user->getByUsername($username);
}
else {
diff --git a/app/Auth/RememberMe.php b/app/Auth/RememberMe.php
index eebf4f4b..54e60422 100644
--- a/app/Auth/RememberMe.php
+++ b/app/Auth/RememberMe.php
@@ -282,7 +282,7 @@ class RememberMe extends Base
self::COOKIE_NAME,
$this->encodeCookie($token, $sequence),
$expiration,
- BASE_URL_DIRECTORY,
+ $this->helper->url->dir(),
null,
Request::isHTTPS(),
true
@@ -315,7 +315,7 @@ class RememberMe extends Base
self::COOKIE_NAME,
'',
time() - 3600,
- BASE_URL_DIRECTORY,
+ $this->helper->url->dir(),
null,
Request::isHTTPS(),
true
diff --git a/app/Controller/Action.php b/app/Controller/Action.php
index cd24453a..74a5326d 100644
--- a/app/Controller/Action.php
+++ b/app/Controller/Action.php
@@ -46,7 +46,7 @@ class Action extends Base
$values = $this->request->getValues();
if (empty($values['action_name']) || empty($values['project_id'])) {
- $this->response->redirect('?controller=action&action=index&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('action', 'index', array('project_id' => $project['id'])));
}
$this->response->html($this->projectLayout('action/event', array(
@@ -68,7 +68,7 @@ class Action extends Base
$values = $this->request->getValues();
if (empty($values['action_name']) || empty($values['project_id']) || empty($values['event_name'])) {
- $this->response->redirect('?controller=action&action=index&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('action', 'index', array('project_id' => $project['id'])));
}
$action = $this->action->load($values['action_name'], $values['project_id'], $values['event_name']);
@@ -125,7 +125,7 @@ class Action extends Base
}
}
- $this->response->redirect('?controller=action&action=index&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('action', 'index', array('project_id' => $project['id'])));
}
/**
@@ -163,6 +163,6 @@ class Action extends Base
$this->session->flashError(t('Unable to remove this action.'));
}
- $this->response->redirect('?controller=action&action=index&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('action', 'index', array('project_id' => $project['id'])));
}
}
diff --git a/app/Controller/Auth.php b/app/Controller/Auth.php
index 24e6e242..e8889b7f 100644
--- a/app/Controller/Auth.php
+++ b/app/Controller/Auth.php
@@ -25,7 +25,6 @@ class Auth extends Base
'errors' => $errors,
'values' => $values,
'no_layout' => true,
- 'redirect_query' => $this->request->getStringParam('redirect_query'),
'title' => t('Login')
)));
}
@@ -37,14 +36,15 @@ class Auth extends Base
*/
public function check()
{
- $redirect_query = $this->request->getStringParam('redirect_query');
$values = $this->request->getValues();
list($valid, $errors) = $this->authentication->validateForm($values);
if ($valid) {
- if ($redirect_query !== '') {
- $this->response->redirect('?'.urldecode($redirect_query));
+ if (! empty($this->session['login_redirect']) && ! filter_var($this->session['login_redirect'], FILTER_VALIDATE_URL)) {
+ $redirect = $this->session['login_redirect'];
+ unset($this->session['login_redirect']);
+ $this->response->redirect($redirect);
}
$this->response->redirect($this->helper->url->to('app', 'index'));
diff --git a/app/Controller/Base.php b/app/Controller/Base.php
index 9f5d6dc6..31eb023d 100644
--- a/app/Controller/Base.php
+++ b/app/Controller/Base.php
@@ -101,7 +101,7 @@ abstract class Base extends \Core\Base
public function beforeAction($controller, $action)
{
// Start the session
- $this->session->open(BASE_URL_DIRECTORY);
+ $this->session->open($this->helper->url->dir());
$this->sendHeaders($action);
$this->container['dispatcher']->dispatch('session.bootstrap', new Event);
@@ -127,7 +127,8 @@ abstract class Base extends \Core\Base
$this->response->text('Not Authorized', 401);
}
- $this->response->redirect($this->helper->url->to('auth', 'login', array('redirect_query' => urlencode($this->request->getQueryString()))));
+ $this->session['login_redirect'] = $this->request->getUri();
+ $this->response->redirect($this->helper->url->to('auth', 'login'));
}
}
@@ -223,17 +224,6 @@ abstract class Base extends \Core\Base
}
/**
- * Redirection when there is no project in the database
- *
- * @access protected
- */
- protected function redirectNoProject()
- {
- $this->session->flash(t('There is no active project, the first step is to create a new project.'));
- $this->response->redirect('?controller=project&action=create');
- }
-
- /**
* Common layout for task views
*
* @access protected
@@ -301,7 +291,7 @@ abstract class Base extends \Core\Base
if (empty($project)) {
$this->session->flashError(t('Project not found.'));
- $this->response->redirect('?controller=project');
+ $this->response->redirect($this->helper->url->to('project', 'index'));
}
return $project;
@@ -344,10 +334,10 @@ abstract class Base extends \Core\Base
'controller' => $controller,
'action' => $action,
'project_id' => $project['id'],
- 'search' => $search,
+ 'search' => urldecode($search),
);
- $this->userSession->setFilters($project['id'], $search);
+ $this->userSession->setFilters($project['id'], $filters['search']);
return array(
'project' => $project,
diff --git a/app/Controller/Board.php b/app/Controller/Board.php
index ac80a192..50d9c62e 100644
--- a/app/Controller/Board.php
+++ b/app/Controller/Board.php
@@ -88,15 +88,7 @@ class Board extends Base
return $this->response->status(400);
}
- $this->response->html(
- $this->template->render('board/table_container', array(
- 'project' => $this->project->getById($project_id),
- 'swimlanes' => $this->taskFilter->search($this->userSession->getFilters($project_id))->getBoard($project_id),
- 'board_private_refresh_interval' => $this->config->get('board_private_refresh_interval'),
- 'board_highlight_period' => $this->config->get('board_highlight_period'),
- )),
- 201
- );
+ $this->response->html($this->renderBoard($project_id), 201);
}
/**
@@ -121,14 +113,7 @@ class Board extends Base
return $this->response->status(304);
}
- $this->response->html(
- $this->template->render('board/table_container', array(
- 'project' => $this->project->getById($project_id),
- 'swimlanes' => $this->taskFilter->search($this->userSession->getFilters($project_id))->getBoard($project_id),
- 'board_private_refresh_interval' => $this->config->get('board_private_refresh_interval'),
- 'board_highlight_period' => $this->config->get('board_highlight_period'),
- ))
- );
+ $this->response->html($this->renderBoard($project_id));
}
/**
@@ -318,9 +303,7 @@ class Board extends Base
*/
public function collapse()
{
- $project_id = $this->request->getIntegerParam('project_id');
- $this->userSession->setBoardDisplayMode($project_id, true);
- $this->response->redirect($this->helper->url->to('board', 'show', array('project_id' => $project_id)));
+ $this->changeDisplayMode(true);
}
/**
@@ -330,8 +313,39 @@ class Board extends Base
*/
public function expand()
{
+ $this->changeDisplayMode(false);
+ }
+
+ /**
+ * Change display mode
+ *
+ * @access private
+ */
+ private function changeDisplayMode($mode)
+ {
$project_id = $this->request->getIntegerParam('project_id');
- $this->userSession->setBoardDisplayMode($project_id, false);
- $this->response->redirect($this->helper->url->to('board', 'show', array('project_id' => $project_id)));
+ $this->userSession->setBoardDisplayMode($project_id, $mode);
+
+ if ($this->request->isAjax()) {
+ $this->response->html($this->renderBoard($project_id));
+ }
+ else {
+ $this->response->redirect($this->helper->url->to('board', 'show', array('project_id' => $project_id)));
+ }
+ }
+
+ /**
+ * Render board
+ *
+ * @access private
+ */
+ private function renderBoard($project_id)
+ {
+ return $this->template->render('board/table_container', array(
+ 'project' => $this->project->getById($project_id),
+ 'swimlanes' => $this->taskFilter->search($this->userSession->getFilters($project_id))->getBoard($project_id),
+ 'board_private_refresh_interval' => $this->config->get('board_private_refresh_interval'),
+ 'board_highlight_period' => $this->config->get('board_highlight_period'),
+ ));
}
}
diff --git a/app/Controller/Category.php b/app/Controller/Category.php
index 515cc9c8..e8d83f2d 100644
--- a/app/Controller/Category.php
+++ b/app/Controller/Category.php
@@ -23,7 +23,7 @@ class Category extends Base
if (empty($category)) {
$this->session->flashError(t('Category not found.'));
- $this->response->redirect('?controller=category&action=index&project_id='.$project_id);
+ $this->response->redirect($this->helper->url->to('category', 'index', array('project_id' => $project_id)));
}
return $category;
@@ -63,7 +63,7 @@ class Category extends Base
if ($this->category->create($values)) {
$this->session->flash(t('Your category have been created successfully.'));
- $this->response->redirect('?controller=category&action=index&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('category', 'index', array('project_id' => $project['id'])));
}
else {
$this->session->flashError(t('Unable to create your category.'));
@@ -107,7 +107,7 @@ class Category extends Base
if ($this->category->update($values)) {
$this->session->flash(t('Your category have been updated successfully.'));
- $this->response->redirect('?controller=category&action=index&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('category', 'index', array('project_id' => $project['id'])));
}
else {
$this->session->flashError(t('Unable to update your category.'));
@@ -151,6 +151,6 @@ class Category extends Base
$this->session->flashError(t('Unable to remove this category.'));
}
- $this->response->redirect('?controller=category&action=index&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('category', 'index', array('project_id' => $project['id'])));
}
}
diff --git a/app/Controller/Comment.php b/app/Controller/Comment.php
index a5f6b1f8..ca701a88 100644
--- a/app/Controller/Comment.php
+++ b/app/Controller/Comment.php
@@ -90,10 +90,10 @@ class Comment extends Base
}
if ($ajax) {
- $this->response->redirect('?controller=board&action=show&project_id='.$task['project_id']);
+ $this->response->redirect($this->helper->url->to('board', 'show', array('project_id' => $task['project_id'])));
}
- $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id'].'#comments');
+ $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])), 'comments');
}
$this->create($values, $errors);
@@ -140,7 +140,7 @@ class Comment extends Base
$this->session->flashError(t('Unable to update your comment.'));
}
- $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id'].'#comment-'.$comment['id']);
+ $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])), 'comment-'.$comment['id']);
}
$this->edit($values, $errors);
@@ -181,6 +181,6 @@ class Comment extends Base
$this->session->flashError(t('Unable to remove this comment.'));
}
- $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id'].'#comments');
+ $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])), 'comments');
}
}
diff --git a/app/Controller/Config.php b/app/Controller/Config.php
index 19bc2767..1e6b3dc8 100644
--- a/app/Controller/Config.php
+++ b/app/Controller/Config.php
@@ -60,7 +60,7 @@ class Config extends Base
$this->session->flashError(t('Unable to save your settings.'));
}
- $this->response->redirect('?controller=config&action='.$redirect);
+ $this->response->redirect($this->helper->url->to('config', $redirect));
}
}
@@ -199,7 +199,7 @@ class Config extends Base
$this->checkCSRFParam();
$this->config->optimizeDatabase();
$this->session->flash(t('Database optimization done.'));
- $this->response->redirect('?controller=config');
+ $this->response->redirect($this->helper->url->to('config', 'index'));
}
/**
@@ -215,6 +215,6 @@ class Config extends Base
$this->config->regenerateToken($type.'_token');
$this->session->flash(t('Token regenerated.'));
- $this->response->redirect('?controller=config&action='.$type);
+ $this->response->redirect($this->helper->url->to('config', $type));
}
}
diff --git a/app/Controller/Oauth.php b/app/Controller/Oauth.php
new file mode 100644
index 00000000..8ba5b252
--- /dev/null
+++ b/app/Controller/Oauth.php
@@ -0,0 +1,123 @@
+<?php
+
+namespace Controller;
+
+/**
+ * OAuth controller
+ *
+ * @package controller
+ * @author Frederic Guillot
+ */
+class Oauth extends Base
+{
+ /**
+ * Link or authenticate a Google account
+ *
+ * @access public
+ */
+ public function google()
+ {
+ $this->step1('google');
+ }
+
+ /**
+ * Link or authenticate a Github account
+ *
+ * @access public
+ */
+ public function github()
+ {
+ $this->step1('github');
+ }
+
+ /**
+ * Unlink external account
+ *
+ * @access public
+ */
+ public function unlink($backend = '')
+ {
+ $backend = $this->request->getStringParam('backend', $backend);
+ $this->checkCSRFParam();
+
+ if ($this->authentication->backend($backend)->unlink($this->userSession->getId())) {
+ $this->session->flash(t('Your external account is not linked anymore to your profile.'));
+ }
+ else {
+ $this->session->flashError(t('Unable to unlink your external account.'));
+ }
+
+ $this->response->redirect($this->helper->url->to('user', 'external', array('user_id' => $this->userSession->getId())));
+ }
+
+ /**
+ * Redirect to the provider if no code received
+ *
+ * @access private
+ */
+ private function step1($backend)
+ {
+ $code = $this->request->getStringParam('code');
+
+ if (! empty($code)) {
+ $this->step2($backend, $code);
+ }
+ else {
+ $this->response->redirect($this->authentication->backend($backend)->getService()->getAuthorizationUrl());
+ }
+ }
+
+ /**
+ * Link or authenticate the user
+ *
+ * @access private
+ */
+ private function step2($backend, $code)
+ {
+ $profile = $this->authentication->backend($backend)->getProfile($code);
+
+ if ($this->userSession->isLogged()) {
+ $this->link($backend, $profile);
+ }
+
+ $this->authenticate($backend, $profile);
+ }
+
+ /**
+ * Link the account
+ *
+ * @access private
+ */
+ private function link($backend, $profile)
+ {
+ if (empty($profile)) {
+ $this->session->flashError(t('External authentication failed'));
+ }
+ else {
+ $this->session->flash(t('Your external account is linked to your profile successfully.'));
+ $this->authentication->backend($backend)->updateUser($this->userSession->getId(), $profile);
+ }
+
+ $this->response->redirect($this->helper->url->to('user', 'external', array('user_id' => $this->userSession->getId())));
+ }
+
+ /**
+ * Authenticate the account
+ *
+ * @access private
+ */
+ private function authenticate($backend, $profile)
+ {
+ if (! empty($profile) && $this->authentication->backend($backend)->authenticate($profile['id'])) {
+ $this->response->redirect($this->helper->url->to('app', 'index'));
+ }
+ else {
+ $this->response->html($this->template->layout('auth/index', array(
+ 'errors' => array('login' => t('External authentication failed')),
+ 'values' => array(),
+ 'no_layout' => true,
+ 'title' => t('Login')
+ )));
+ }
+ }
+}
diff --git a/app/Controller/Project.php b/app/Controller/Project.php
index faebac38..45bc2a46 100644
--- a/app/Controller/Project.php
+++ b/app/Controller/Project.php
@@ -73,11 +73,12 @@ class Project extends Base
if ($this->project->{$switch.'PublicAccess'}($project['id'])) {
$this->session->flash(t('Project updated successfully.'));
- } else {
+ }
+ else {
$this->session->flashError(t('Unable to update this project.'));
}
- $this->response->redirect('?controller=project&action=share&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('project', 'share', array('project_id' => $project['id'])));
}
$this->response->html($this->projectLayout('project/share', array(
@@ -150,7 +151,7 @@ class Project extends Base
if ($this->project->update($values)) {
$this->session->flash(t('Project updated successfully.'));
- $this->response->redirect('?controller=project&action=edit&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('project', 'edit', array('project_id' => $project['id'])));
}
else {
$this->session->flashError(t('Unable to update this project.'));
@@ -197,7 +198,7 @@ class Project extends Base
}
}
- $this->response->redirect('?controller=project&action=users&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('project', 'users', array('project_id' => $project['id'])));
}
/**
@@ -220,7 +221,7 @@ class Project extends Base
}
}
- $this->response->redirect('?controller=project&action=users&project_id='.$values['project_id']);
+ $this->response->redirect($this->helper->url->to('project', 'users', array('project_id' => $values['project_id'])));
}
/**
@@ -250,7 +251,7 @@ class Project extends Base
}
}
- $this->response->redirect('?controller=project&action=users&project_id='.$values['project_id']);
+ $this->response->redirect($this->helper->url->to('project', 'users', array('project_id' => $values['project_id'])));
}
/**
@@ -279,7 +280,7 @@ class Project extends Base
}
}
- $this->response->redirect('?controller=project&action=users&project_id='.$values['project_id']);
+ $this->response->redirect($this->helper->url->to('project', 'users', array('project_id' => $values['project_id'])));
}
/**
@@ -301,7 +302,7 @@ class Project extends Base
$this->session->flashError(t('Unable to remove this project.'));
}
- $this->response->redirect('?controller=project');
+ $this->response->redirect($this->helper->url->to('project', 'index'));
}
$this->response->html($this->projectLayout('project/remove', array(
@@ -329,7 +330,7 @@ class Project extends Base
$this->session->flashError(t('Unable to clone this project.'));
}
- $this->response->redirect('?controller=project');
+ $this->response->redirect($this->helper->url->to('project', 'index'));
}
$this->response->html($this->projectLayout('project/duplicate', array(
@@ -357,7 +358,7 @@ class Project extends Base
$this->session->flashError(t('Unable to disable this project.'));
}
- $this->response->redirect('?controller=project&action=show&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('project', 'show', array('project_id' => $project['id'])));
}
$this->response->html($this->projectLayout('project/disable', array(
@@ -385,7 +386,7 @@ class Project extends Base
$this->session->flashError(t('Unable to activate this project.'));
}
- $this->response->redirect('?controller=project&action=show&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('project', 'show', array('project_id' => $project['id'])));
}
$this->response->html($this->projectLayout('project/enable', array(
@@ -428,7 +429,7 @@ class Project extends Base
if ($project_id > 0) {
$this->session->flash(t('Your project have been created successfully.'));
- $this->response->redirect('?controller=project&action=show&project_id='.$project_id);
+ $this->response->redirect($this->helper->url->to('project', 'show', array('project_id' => $project_id)));
}
$this->session->flashError(t('Unable to create your project.'));
diff --git a/app/Controller/Search.php b/app/Controller/Search.php
index 519f9ce4..f6dc7a32 100644
--- a/app/Controller/Search.php
+++ b/app/Controller/Search.php
@@ -13,7 +13,7 @@ class Search extends Base
public function index()
{
$projects = $this->projectPermission->getAllowedProjects($this->userSession->getId());
- $search = $this->request->getStringParam('search');
+ $search = urldecode($this->request->getStringParam('search'));
$nb_tasks = 0;
$paginator = $this->paginator
diff --git a/app/Controller/Subtask.php b/app/Controller/Subtask.php
index 6ee94333..87f3fcb4 100644
--- a/app/Controller/Subtask.php
+++ b/app/Controller/Subtask.php
@@ -75,10 +75,10 @@ class Subtask extends Base
}
if (isset($values['another_subtask']) && $values['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($this->helper->url->to('subtask', 'create', array('project_id' => $task['project_id'], 'task_id' => $task['id'], 'another_subtask' => 1)));
}
- $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id'].'#subtasks');
+ $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id']), 'subtasks'));
}
$this->create($values, $errors);
@@ -126,7 +126,7 @@ class Subtask extends Base
$this->session->flashError(t('Unable to update your sub-task.'));
}
- $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id'].'#subtasks');
+ $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id']), 'subtasks'));
}
$this->edit($values, $errors);
@@ -166,7 +166,7 @@ class Subtask extends Base
$this->session->flashError(t('Unable to remove this sub-task.'));
}
- $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id'].'#subtasks');
+ $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id']), 'subtasks'));
}
/**
@@ -256,7 +256,7 @@ class Subtask extends Base
case 'dashboard':
$this->response->redirect($this->helper->url->to('app', 'index'));
default:
- $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])).'#subtasks');
+ $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), 'subtasks'));
}
}
@@ -275,6 +275,6 @@ class Subtask extends Base
$method = $direction === 'up' ? 'moveUp' : 'moveDown';
$this->subtask->$method($task_id, $subtask_id);
- $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $project_id, 'task_id' => $task_id)).'#subtasks');
+ $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $project_id, 'task_id' => $task_id), 'subtasks'));
}
}
diff --git a/app/Controller/Swimlane.php b/app/Controller/Swimlane.php
index c6862d47..054fa4ba 100644
--- a/app/Controller/Swimlane.php
+++ b/app/Controller/Swimlane.php
@@ -25,7 +25,7 @@ class Swimlane extends Base
if (empty($swimlane)) {
$this->session->flashError(t('Swimlane not found.'));
- $this->response->redirect('?controller=swimlane&action=index&project_id='.$project_id);
+ $this->response->redirect($this->helper->url->to('swimlane', 'index', array('project_id' => $project_id)));
}
return $swimlane;
@@ -67,7 +67,7 @@ class Swimlane extends Base
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']);
+ $this->response->redirect($this->helper->url->to('swimlane', 'index', array('project_id' => $project['id'])));
}
else {
$this->session->flashError(t('Unable to create your swimlane.'));
@@ -93,7 +93,7 @@ class Swimlane extends Base
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']);
+ $this->response->redirect($this->helper->url->to('swimlane', 'index', array('project_id' => $project['id'])));
}
else {
$this->session->flashError(t('Unable to update this swimlane.'));
@@ -137,7 +137,7 @@ class Swimlane extends Base
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']);
+ $this->response->redirect($this->helper->url->to('swimlane', 'index', array('project_id' => $project['id'])));
}
else {
$this->session->flashError(t('Unable to update this swimlane.'));
@@ -181,7 +181,7 @@ class Swimlane extends Base
$this->session->flashError(t('Unable to remove this swimlane.'));
}
- $this->response->redirect('?controller=swimlane&action=index&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('swimlane', 'index', array('project_id' => $project['id'])));
}
/**
@@ -201,7 +201,7 @@ class Swimlane extends Base
$this->session->flashError(t('Unable to update this swimlane.'));
}
- $this->response->redirect('?controller=swimlane&action=index&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('swimlane', 'index', array('project_id' => $project['id'])));
}
/**
@@ -221,7 +221,7 @@ class Swimlane extends Base
$this->session->flashError(t('Unable to update this swimlane.'));
}
- $this->response->redirect('?controller=swimlane&action=index&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('swimlane', 'index', array('project_id' => $project['id'])));
}
/**
@@ -236,7 +236,7 @@ class Swimlane extends Base
$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']);
+ $this->response->redirect($this->helper->url->to('swimlane', 'index', array('project_id' => $project['id'])));
}
/**
@@ -251,6 +251,6 @@ class Swimlane extends Base
$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']);
+ $this->response->redirect($this->helper->url->to('swimlane', 'index', array('project_id' => $project['id'])));
}
}
diff --git a/app/Controller/Task.php b/app/Controller/Task.php
index 0d85f411..676dccbe 100644
--- a/app/Controller/Task.php
+++ b/app/Controller/Task.php
@@ -163,10 +163,10 @@ class Task extends Base
if (isset($values['another_task']) && $values['another_task'] == 1) {
unset($values['title']);
unset($values['description']);
- $this->response->redirect('?controller=task&action=create&'.http_build_query($values));
+ $this->response->redirect($this->helper->url->to('task', 'create', $values));
}
else {
- $this->response->redirect('?controller=board&action=show&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('board', 'show', array('project_id' => $project['id'])));
}
}
else {
@@ -231,10 +231,10 @@ class Task extends Base
$this->session->flash(t('Task updated successfully.'));
if ($this->request->getIntegerParam('ajax')) {
- $this->response->redirect('?controller=board&action=show&project_id='.$task['project_id']);
+ $this->response->redirect($this->helper->url->to('board', 'show', array('project_id' => $task['project_id'])));
}
else {
- $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id']);
+ $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])));
}
}
else {
@@ -264,7 +264,7 @@ class Task extends Base
$this->session->flashError(t('Unable to update your task.'));
}
- $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id']);
+ $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])));
}
/**
@@ -326,7 +326,7 @@ class Task extends Base
$this->session->flashError(t('Unable to open this task.'));
}
- $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id']);
+ $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])));
}
$this->response->html($this->taskLayout('task/open', array(
@@ -357,7 +357,7 @@ class Task extends Base
$this->session->flashError(t('Unable to remove this task.'));
}
- $this->response->redirect('?controller=board&action=show&project_id='.$task['project_id']);
+ $this->response->redirect($this->helper->url->to('board', 'show', array('project_id' => $task['project_id'])));
}
$this->response->html($this->taskLayout('task/remove', array(
@@ -381,10 +381,10 @@ class Task extends Base
if ($task_id) {
$this->session->flash(t('Task created successfully.'));
- $this->response->redirect('?controller=task&action=show&task_id='.$task_id.'&project_id='.$task['project_id']);
+ $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])));
} else {
$this->session->flashError(t('Unable to create this task.'));
- $this->response->redirect('?controller=task&action=duplicate&task_id='.$task['id'].'&project_id='.$task['project_id']);
+ $this->response->redirect($this->helper->url->to('task', 'duplicate', array('project_id' => $task['project_id'], 'task_id' => $task['id'])));
}
}
@@ -419,10 +419,10 @@ class Task extends Base
}
if ($ajax) {
- $this->response->redirect('?controller=board&action=show&project_id='.$task['project_id']);
+ $this->response->redirect($this->helper->url->to('board', 'show', array('project_id' => $task['project_id'])));
}
else {
- $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id']);
+ $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])));
}
}
}
@@ -454,7 +454,6 @@ class Task extends Base
public function recurrence()
{
$task = $this->getTask();
- $ajax = $this->request->isAjax() || $this->request->getIntegerParam('ajax');
if ($this->request->isPost()) {
@@ -471,12 +470,7 @@ class Task extends Base
$this->session->flashError(t('Unable to update your task.'));
}
- if ($ajax) {
- $this->response->redirect('?controller=board&action=show&project_id='.$task['project_id']);
- }
- else {
- $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id']);
- }
+ $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])));
}
}
else {
@@ -488,19 +482,13 @@ class Task extends Base
'values' => $values,
'errors' => $errors,
'task' => $task,
- 'ajax' => $ajax,
'recurrence_status_list' => $this->task->getRecurrenceStatusList(),
'recurrence_trigger_list' => $this->task->getRecurrenceTriggerList(),
'recurrence_timeframe_list' => $this->task->getRecurrenceTimeframeList(),
'recurrence_basedate_list' => $this->task->getRecurrenceBasedateList(),
);
- if ($ajax) {
- $this->response->html($this->template->render('task/edit_recurrence', $params));
- }
- else {
- $this->response->html($this->taskLayout('task/edit_recurrence', $params));
- }
+ $this->response->html($this->taskLayout('task/edit_recurrence', $params));
}
/**
@@ -526,7 +514,7 @@ class Task extends Base
if ($this->taskDuplication->moveToProject($task['id'], $values['project_id'])) {
$this->session->flash(t('Task updated successfully.'));
- $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$values['project_id']);
+ $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])));
}
else {
$this->session->flashError(t('Unable to update your task.'));
@@ -565,7 +553,7 @@ class Task extends Base
$task_id = $this->taskDuplication->duplicateToProject($task['id'], $values['project_id']);
if ($task_id) {
$this->session->flash(t('Task created successfully.'));
- $this->response->redirect('?controller=task&action=show&task_id='.$task_id.'&project_id='.$values['project_id']);
+ $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])));
}
else {
$this->session->flashError(t('Unable to create your task.'));
diff --git a/app/Controller/User.php b/app/Controller/User.php
index 119041e5..10a3a931 100644
--- a/app/Controller/User.php
+++ b/app/Controller/User.php
@@ -60,7 +60,9 @@ class User extends Base
*/
public function create(array $values = array(), array $errors = array())
{
- $this->response->html($this->template->layout('user/new', array(
+ $is_remote = $this->request->getIntegerParam('remote') == 1 || (isset($values['is_ldap_user']) && $values['is_ldap_user'] == 1);
+
+ $this->response->html($this->template->layout($is_remote ? 'user/create_remote' : 'user/create_local', array(
'timezones' => $this->config->getTimezones(true),
'languages' => $this->config->getLanguages(true),
'board_selector' => $this->projectPermission->getAllowedProjects($this->userSession->getId()),
@@ -178,7 +180,7 @@ class User extends Base
$this->checkCSRFParam();
$user = $this->getUser();
$this->authentication->backend('rememberMe')->remove($this->request->getIntegerParam('id'));
- $this->response->redirect('?controller=user&action=sessions&user_id='.$user['id']);
+ $this->response->redirect($this->helper->url->to('user', 'session', array('user_id' => $user['id'])));
}
/**
@@ -194,7 +196,7 @@ class User extends Base
$values = $this->request->getValues();
$this->notification->saveSettings($user['id'], $values);
$this->session->flash(t('User updated successfully.'));
- $this->response->redirect('?controller=user&action=notifications&user_id='.$user['id']);
+ $this->response->redirect($this->helper->url->to('user', 'notifications', array('user_id' => $user['id'])));
}
$this->response->html($this->layout('user/notifications', array(
@@ -272,7 +274,7 @@ class User extends Base
$this->session->flashError(t('Unable to change the password.'));
}
- $this->response->redirect('?controller=user&action=show&user_id='.$user['id']);
+ $this->response->redirect($this->helper->url->to('user', 'show', array('user_id' => $user['id'])));
}
}
@@ -298,7 +300,7 @@ class User extends Base
if ($this->request->isPost()) {
- $values = $this->request->getValues() + array('disable_login_form' => 0);
+ $values = $this->request->getValues();
if ($this->userSession->isAdmin()) {
$values += array('is_admin' => 0);
@@ -321,7 +323,7 @@ class User extends Base
$this->session->flashError(t('Unable to update your user.'));
}
- $this->response->redirect('?controller=user&action=show&user_id='.$user['id']);
+ $this->response->redirect($this->helper->url->to('user', 'show', array('user_id' => $user['id'])));
}
}
@@ -335,157 +337,67 @@ class User extends Base
}
/**
- * Remove a user
+ * Display a form to edit authentication
*
* @access public
*/
- public function remove()
+ public function authentication()
{
$user = $this->getUser();
+ $values = $user;
+ $errors = array();
- if ($this->request->getStringParam('confirmation') === 'yes') {
-
- $this->checkCSRFParam();
-
- if ($this->user->remove($user['id'])) {
- $this->session->flash(t('User removed successfully.'));
- } else {
- $this->session->flashError(t('Unable to remove this user.'));
- }
-
- $this->response->redirect('?controller=user');
- }
-
- $this->response->html($this->layout('user/remove', array(
- 'user' => $user,
- )));
- }
-
- /**
- * Google authentication
- *
- * @access public
- */
- public function google()
- {
- $code = $this->request->getStringParam('code');
-
- if ($code) {
-
- $profile = $this->authentication->backend('google')->getGoogleProfile($code);
+ unset($values['password']);
- if (is_array($profile)) {
+ if ($this->request->isPost()) {
- // If the user is already logged, link the account otherwise authenticate
- if ($this->userSession->isLogged()) {
+ $values = $this->request->getValues() + array('disable_login_form' => 0, 'is_ldap_user' => 0);
+ list($valid, $errors) = $this->user->validateModification($values);
- if ($this->authentication->backend('google')->updateUser($this->userSession->getId(), $profile)) {
- $this->session->flash(t('Your Google Account is linked to your profile successfully.'));
- }
- else {
- $this->session->flashError(t('Unable to link your Google Account.'));
- }
+ if ($valid) {
- $this->response->redirect('?controller=user&action=external&user_id='.$this->userSession->getId());
- }
- else if ($this->authentication->backend('google')->authenticate($profile['id'])) {
- $this->response->redirect('?controller=app');
+ if ($this->user->update($values)) {
+ $this->session->flash(t('User updated successfully.'));
}
else {
- $this->response->html($this->template->layout('auth/index', array(
- 'errors' => array('login' => t('Google authentication failed')),
- 'values' => array(),
- 'no_layout' => true,
- 'redirect_query' => '',
- 'title' => t('Login')
- )));
+ $this->session->flashError(t('Unable to update your user.'));
}
- }
- }
-
- $this->response->redirect($this->authentication->backend('google')->getAuthorizationUrl());
- }
- /**
- * Unlink a Google account
- *
- * @access public
- */
- public function unlinkGoogle()
- {
- $this->checkCSRFParam();
- if ($this->authentication->backend('google')->unlink($this->userSession->getId())) {
- $this->session->flash(t('Your Google Account is not linked anymore to your profile.'));
- }
- else {
- $this->session->flashError(t('Unable to unlink your Google Account.'));
+ $this->response->redirect($this->helper->url->to('user', 'authentication', array('user_id' => $user['id'])));
+ }
}
- $this->response->redirect('?controller=user&action=external&user_id='.$this->userSession->getId());
+ $this->response->html($this->layout('user/authentication', array(
+ 'values' => $values,
+ 'errors' => $errors,
+ 'user' => $user,
+ )));
}
/**
- * GitHub authentication
+ * Remove a user
*
* @access public
*/
- public function github()
+ public function remove()
{
- $code = $this->request->getStringParam('code');
-
- if ($code) {
- $profile = $this->authentication->backend('gitHub')->getGitHubProfile($code);
-
- if (is_array($profile)) {
+ $user = $this->getUser();
- // If the user is already logged, link the account otherwise authenticate
- if ($this->userSession->isLogged()) {
+ if ($this->request->getStringParam('confirmation') === 'yes') {
- if ($this->authentication->backend('gitHub')->updateUser($this->userSession->getId(), $profile)) {
- $this->session->flash(t('Your GitHub account was successfully linked to your profile.'));
- }
- else {
- $this->session->flashError(t('Unable to link your GitHub Account.'));
- }
+ $this->checkCSRFParam();
- $this->response->redirect('?controller=user&action=external&user_id='.$this->userSession->getId());
- }
- else if ($this->authentication->backend('gitHub')->authenticate($profile['id'])) {
- $this->response->redirect('?controller=app');
- }
- else {
- $this->response->html($this->template->layout('auth/index', array(
- 'errors' => array('login' => t('GitHub authentication failed')),
- 'values' => array(),
- 'no_layout' => true,
- 'redirect_query' => '',
- 'title' => t('Login')
- )));
- }
+ if ($this->user->remove($user['id'])) {
+ $this->session->flash(t('User removed successfully.'));
+ } else {
+ $this->session->flashError(t('Unable to remove this user.'));
}
- }
-
- $this->response->redirect($this->authentication->backend('gitHub')->getAuthorizationUrl());
- }
- /**
- * Unlink a GitHub account
- *
- * @access public
- */
- public function unlinkGithub()
- {
- $this->checkCSRFParam();
-
- $this->authentication->backend('gitHub')->revokeGitHubAccess();
-
- if ($this->authentication->backend('gitHub')->unlink($this->userSession->getId())) {
- $this->session->flash(t('Your GitHub account is no longer linked to your profile.'));
- }
- else {
- $this->session->flashError(t('Unable to unlink your GitHub Account.'));
+ $this->response->redirect($this->helper->url->to('user', 'index'));
}
- $this->response->redirect('?controller=user&action=external&user_id='.$this->userSession->getId());
+ $this->response->html($this->layout('user/remove', array(
+ 'user' => $user,
+ )));
}
}
diff --git a/app/Core/HttpClient.php b/app/Core/HttpClient.php
index 805c1e5a..b808f756 100644
--- a/app/Core/HttpClient.php
+++ b/app/Core/HttpClient.php
@@ -32,6 +32,20 @@ class HttpClient extends Base
const HTTP_USER_AGENT = 'Kanboard';
/**
+ * Send a GET HTTP request and parse JSON response
+ *
+ * @access public
+ * @param string $url
+ * @param string[] $headers
+ * @return array
+ */
+ public function getJson($url, array $headers = array())
+ {
+ $response = $this->doRequest('GET', $url, '', array_merge(array('Accept: application/json'), $headers));
+ return json_decode($response, true) ?: array();
+ }
+
+ /**
* Send a POST HTTP request encoded in JSON
*
* @access public
@@ -43,6 +57,7 @@ class HttpClient extends Base
public function postJson($url, array $data, array $headers = array())
{
return $this->doRequest(
+ 'POST',
$url,
json_encode($data),
array_merge(array('Content-type: application/json'), $headers)
@@ -61,6 +76,7 @@ class HttpClient extends Base
public function postForm($url, array $data, array $headers = array())
{
return $this->doRequest(
+ 'POST',
$url,
http_build_query($data),
array_merge(array('Content-type: application/x-www-form-urlencoded'), $headers)
@@ -71,12 +87,13 @@ class HttpClient extends Base
* Make the HTTP request
*
* @access private
+ * @param string $method
* @param string $url
* @param string $content
* @param string[] $headers
* @return string
*/
- private function doRequest($url, $content, array $headers)
+ private function doRequest($method, $url, $content, array $headers)
{
if (empty($url)) {
return '';
@@ -86,7 +103,7 @@ class HttpClient extends Base
$context = stream_context_create(array(
'http' => array(
- 'method' => 'POST',
+ 'method' => $method,
'protocol_version' => 1.1,
'timeout' => self::HTTP_TIMEOUT,
'max_redirects' => self::HTTP_MAX_REDIRECTS,
diff --git a/app/Core/Lexer.php b/app/Core/Lexer.php
index 3887dc82..0a237254 100644
--- a/app/Core/Lexer.php
+++ b/app/Core/Lexer.php
@@ -33,6 +33,7 @@ class Lexer
"/^(category:)/" => 'T_CATEGORY',
"/^(column:)/" => 'T_COLUMN',
"/^(project:)/" => 'T_PROJECT',
+ "/^(swimlane:)/" => 'T_SWIMLANE',
"/^(ref:)/" => 'T_REFERENCE',
"/^(reference:)/" => 'T_REFERENCE',
"/^(\s+)/" => 'T_WHITESPACE',
@@ -116,6 +117,7 @@ class Lexer
case 'T_CATEGORY':
case 'T_COLUMN':
case 'T_PROJECT':
+ case 'T_SWIMLANE':
$next = next($tokens);
if ($next !== false && $next['token'] === 'T_STRING') {
diff --git a/app/Core/OAuth2.php b/app/Core/OAuth2.php
new file mode 100644
index 00000000..a7d04f33
--- /dev/null
+++ b/app/Core/OAuth2.php
@@ -0,0 +1,120 @@
+<?php
+
+namespace Core;
+
+/**
+ * OAuth2 client
+ *
+ * @package core
+ * @author Frederic Guillot
+ */
+class OAuth2 extends Base
+{
+ private $clientId;
+ private $secret;
+ private $callbackUrl;
+ private $authUrl;
+ private $tokenUrl;
+ private $scopes;
+ private $tokenType;
+ private $accessToken;
+
+ /**
+ * Create OAuth2 service
+ *
+ * @access public
+ * @param string $clientId
+ * @param string $secret
+ * @param string $callbackUrl
+ * @param string $authUrl
+ * @param string $tokenUrl
+ * @param array $scopes
+ * @return OAuth2
+ */
+ public function createService($clientId, $secret, $callbackUrl, $authUrl, $tokenUrl, array $scopes)
+ {
+ $this->clientId = $clientId;
+ $this->secret = $secret;
+ $this->callbackUrl = $callbackUrl;
+ $this->authUrl = $authUrl;
+ $this->tokenUrl = $tokenUrl;
+ $this->scopes = $scopes;
+
+ return $this;
+ }
+
+ /**
+ * Get authorization url
+ *
+ * @access public
+ * @return string
+ */
+ public function getAuthorizationUrl()
+ {
+ $params = array(
+ 'response_type' => 'code',
+ 'client_id' => $this->clientId,
+ 'redirect_uri' => $this->callbackUrl,
+ 'scope' => implode(' ', $this->scopes),
+ );
+
+ return $this->authUrl.'?'.http_build_query($params);
+ }
+
+ /**
+ * Get authorization header
+ *
+ * @access public
+ * @return string
+ */
+ public function getAuthorizationHeader()
+ {
+ if (strtolower($this->tokenType) === 'bearer') {
+ return 'Authorization: Bearer '.$this->accessToken;
+ }
+
+ return '';
+ }
+
+ /**
+ * Get access token
+ *
+ * @access public
+ * @param string $code
+ * @return string
+ */
+ public function getAccessToken($code)
+ {
+ if (empty($this->accessToken) && ! empty($code)) {
+
+ $params = array(
+ 'code' => $code,
+ 'client_id' => $this->clientId,
+ 'client_secret' => $this->secret,
+ 'redirect_uri' => $this->callbackUrl,
+ 'grant_type' => 'authorization_code',
+ );
+
+ $response = json_decode($this->httpClient->postForm($this->tokenUrl, $params, array('Accept: application/json')), true);
+
+ $this->tokenType = isset($response['token_type']) ? $response['token_type'] : '';
+ $this->accessToken = isset($response['access_token']) ? $response['access_token'] : '';
+ }
+
+ return $this->accessToken;
+ }
+
+ /**
+ * Set access token
+ *
+ * @access public
+ * @param string $token
+ * @param string $type
+ * @return string
+ */
+ public function setAccessToken($token, $type = 'bearer')
+ {
+ $this->accessToken = $token;
+ $this->tokenType = $type;
+ }
+}
diff --git a/app/Core/Request.php b/app/Core/Request.php
index b399a1f0..1eff66fa 100644
--- a/app/Core/Request.php
+++ b/app/Core/Request.php
@@ -163,6 +163,17 @@ class Request
}
/**
+ * Returns uri
+ *
+ * @access public
+ * @return string
+ */
+ public function getUri()
+ {
+ return isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
+ }
+
+ /**
* Get the user agent
*
* @static
diff --git a/app/Core/Router.php b/app/Core/Router.php
index 36c11a0a..ae989de5 100644
--- a/app/Core/Router.php
+++ b/app/Core/Router.php
@@ -2,53 +2,151 @@
namespace Core;
-use Pimple\Container;
-
/**
* Router class
*
* @package core
* @author Frederic Guillot
*/
-class Router
+class Router extends Base
{
/**
- * Controller name
+ * Store routes for path lookup
*
* @access private
- * @var string
+ * @var array
*/
- private $controller = '';
+ private $paths = array();
/**
- * Action name
+ * Store routes for url lookup
*
* @access private
- * @var string
+ * @var array
*/
- private $action = '';
+ private $urls = array();
/**
- * Container instance
+ * Get the path to compare patterns
*
- * @access private
- * @var \Pimple\Container
+ * @access public
+ * @param string $uri
+ * @param string $query_string
+ * @return string
*/
- private $container;
+ public function getPath($uri, $query_string = '')
+ {
+ $path = substr($uri, strlen($this->helper->url->dir()));
+
+ if (! empty($query_string)) {
+ $path = substr($path, 0, - strlen($query_string) - 1);
+ }
+
+ if ($path{0} === '/') {
+ $path = substr($path, 1);
+ }
+
+ return $path;
+ }
+
+ /**
+ * Add route
+ *
+ * @access public
+ * @param string $path
+ * @param string $controller
+ * @param string $action
+ * @param array $params
+ */
+ public function addRoute($path, $controller, $action, array $params = array())
+ {
+ $pattern = explode('/', $path);
+
+ $this->paths[] = array(
+ 'pattern' => $pattern,
+ 'count' => count($pattern),
+ 'controller' => $controller,
+ 'action' => $action,
+ );
+
+ $this->urls[$controller][$action][] = array(
+ 'path' => $path,
+ 'params' => array_flip($params),
+ 'count' => count($params),
+ );
+ }
+
+ /**
+ * Find a route according to the given path
+ *
+ * @access public
+ * @param string $path
+ * @return array
+ */
+ public function findRoute($path)
+ {
+ $parts = explode('/', $path);
+ $count = count($parts);
+
+ foreach ($this->paths as $route) {
+
+ if ($count === $route['count']) {
+
+ $params = array();
+
+ for ($i = 0; $i < $count; $i++) {
+
+ if ($route['pattern'][$i]{0} === ':') {
+ $params[substr($route['pattern'][$i], 1)] = $parts[$i];
+ }
+ else if ($route['pattern'][$i] !== $parts[$i]) {
+ break;
+ }
+ }
+
+ if ($i === $count) {
+ $_GET = array_merge($_GET, $params);
+ return array($route['controller'], $route['action']);
+ }
+ }
+ }
+
+ return array('app', 'index');
+ }
/**
- * Constructor
+ * Find route url
*
* @access public
- * @param \Pimple\Container $container Container instance
- * @param string $controller Controller name
- * @param string $action Action name
+ * @param string $controller
+ * @param string $action
+ * @param array $params
+ * @return string
*/
- public function __construct(Container $container, $controller = '', $action = '')
+ public function findUrl($controller, $action, array $params = array())
{
- $this->container = $container;
- $this->controller = empty($_GET['controller']) ? $controller : $_GET['controller'];
- $this->action = empty($_GET['action']) ? $action : $_GET['action'];
+ if (! isset($this->urls[$controller][$action])) {
+ return '';
+ }
+
+ foreach ($this->urls[$controller][$action] as $pattern) {
+
+ if (array_diff_key($params, $pattern['params']) === array()) {
+ $url = $pattern['path'];
+ $i = 0;
+
+ foreach ($params as $variable => $value) {
+ $url = str_replace(':'.$variable, $value, $url);
+ $i++;
+ }
+
+ if ($i === $pattern['count']) {
+ return $url;
+ }
+ }
+ }
+
+ return '';
}
/**
@@ -65,15 +163,42 @@ class Router
}
/**
- * Load a controller and execute the action
+ * Find controller/action from the route table or from get arguments
*
* @access public
- * @param string $filename Controller filename
- * @param string $class Class name
- * @param string $method Method name
+ * @param string $uri
+ * @param string $query_string
+ * @return boolean
+ */
+ public function dispatch($uri, $query_string = '')
+ {
+ if (! empty($_GET['controller']) && ! empty($_GET['action'])) {
+ $controller = $this->sanitize($_GET['controller'], 'app');
+ $action = $this->sanitize($_GET['action'], 'index');
+ }
+ else {
+ list($controller, $action) = $this->findRoute($this->getPath($uri, $query_string));
+ }
+
+ return $this->load(
+ __DIR__.'/../Controller/'.ucfirst($controller).'.php',
+ $controller,
+ '\Controller\\'.ucfirst($controller),
+ $action
+ );
+ }
+
+ /**
+ * Load a controller and execute the action
+ *
+ * @access private
+ * @param string $filename
+ * @param string $controller
+ * @param string $class
+ * @param string $method
* @return bool
*/
- public function load($filename, $class, $method)
+ private function load($filename, $controller, $class, $method)
{
if (file_exists($filename)) {
@@ -84,7 +209,7 @@ class Router
}
$instance = new $class($this->container);
- $instance->beforeAction($this->controller, $this->action);
+ $instance->beforeAction($controller, $method);
$instance->$method();
return true;
@@ -92,20 +217,4 @@ class Router
return false;
}
-
- /**
- * Find a route
- *
- * @access public
- */
- public function execute()
- {
- $this->controller = $this->sanitize($this->controller, 'app');
- $this->action = $this->sanitize($this->action, 'index');
- $filename = __DIR__.'/../Controller/'.ucfirst($this->controller).'.php';
-
- if (! $this->load($filename, '\Controller\\'.$this->controller, $this->action)) {
- die('Page not found!');
- }
- }
}
diff --git a/app/Core/Session.php b/app/Core/Session.php
index c35014cd..0e5f7426 100644
--- a/app/Core/Session.php
+++ b/app/Core/Session.php
@@ -41,8 +41,6 @@ class Session implements ArrayAccess
*/
public function open($base_path = '/')
{
- $base_path = str_replace('\\', '/', $base_path);
-
// HttpOnly and secure flags for session cookie
session_set_cookie_params(
self::SESSION_LIFETIME,
diff --git a/app/Helper/Asset.php b/app/Helper/Asset.php
index 1b1e47c5..fd555e07 100644
--- a/app/Helper/Asset.php
+++ b/app/Helper/Asset.php
@@ -18,7 +18,7 @@ class Asset extends \Core\Base
*/
public function js($filename, $async = false)
{
- return '<script '.($async ? 'async' : '').' type="text/javascript" src="'.$filename.'?'.filemtime($filename).'"></script>';
+ return '<script '.($async ? 'async' : '').' type="text/javascript" src="'.$this->helper->url->dir().$filename.'?'.filemtime($filename).'"></script>';
}
/**
@@ -31,7 +31,7 @@ class Asset extends \Core\Base
*/
public function css($filename, $is_file = true, $media = 'screen')
{
- return '<link rel="stylesheet" href="'.$filename.($is_file ? '?'.filemtime($filename) : '').'" media="'.$media.'">';
+ return '<link rel="stylesheet" href="'.$this->helper->url->dir().$filename.($is_file ? '?'.filemtime($filename) : '').'" media="'.$media.'">';
}
/**
diff --git a/app/Helper/Url.php b/app/Helper/Url.php
index 8de63f8d..964e0762 100644
--- a/app/Helper/Url.php
+++ b/app/Helper/Url.php
@@ -13,6 +13,9 @@ use Core\Security;
*/
class Url extends \Core\Base
{
+ private $base = '';
+ private $directory = '';
+
/**
* HTML Link tag
*
@@ -33,7 +36,7 @@ class Url extends \Core\Base
}
/**
- * Hyperlink
+ * HTML Hyperlink
*
* @access public
* @param string $controller Controller name
@@ -41,22 +44,12 @@ class Url extends \Core\Base
* @param array $params Url parameters
* @param boolean $csrf Add a CSRF token
* @param string $anchor Link Anchor
+ * @param boolean $absolute Absolute or relative link
* @return string
*/
- public function href($controller, $action, array $params = array(), $csrf = false, $anchor = '')
+ public function href($controller, $action, array $params = array(), $csrf = false, $anchor = '', $absolute = false)
{
- $values = array(
- 'controller' => $controller,
- 'action' => $action,
- );
-
- if ($csrf) {
- $params['csrf_token'] = Security::getCSRFToken();
- }
-
- $values += $params;
-
- return '?'.http_build_query($values, '', '&amp;').(empty($anchor) ? '' : '#'.$anchor);
+ return $this->build('&amp;', $controller, $action, $params, $csrf, $anchor, $absolute);
}
/**
@@ -66,18 +59,13 @@ class Url extends \Core\Base
* @param string $controller Controller name
* @param string $action Action name
* @param array $params Url parameters
+ * @param string $anchor Link Anchor
+ * @param boolean $absolute Absolute or relative link
* @return string
*/
- public function to($controller, $action, array $params = array())
+ public function to($controller, $action, array $params = array(), $anchor = '', $absolute = false)
{
- $values = array(
- 'controller' => $controller,
- 'action' => $action,
- );
-
- $values += $params;
-
- return '?'.http_build_query($values, '', '&');
+ return $this->build('&', $controller, $action, $params, false, $anchor, $absolute);
}
/**
@@ -88,7 +76,28 @@ class Url extends \Core\Base
*/
public function base()
{
- return $this->config->get('application_url') ?: $this->server();
+ if (empty($this->base)) {
+ $this->base = $this->config->get('application_url') ?: $this->server();
+ }
+
+ return $this->base;
+ }
+
+ /**
+ * Get application base directory
+ *
+ * @access public
+ * @return string
+ */
+ public function dir()
+ {
+ if (empty($this->directory) && isset($_SERVER['REQUEST_METHOD'])) {
+ $this->directory = str_replace('\\', '/', dirname($_SERVER['PHP_SELF']));
+ $this->directory = $this->directory !== '/' ? $this->directory.'/' : '/';
+ $this->directory = str_replace('//', '/', $this->directory);
+ }
+
+ return $this->directory;
}
/**
@@ -103,13 +112,46 @@ class Url extends \Core\Base
return 'http://localhost/';
}
- $self = str_replace('\\', '/', dirname($_SERVER['PHP_SELF']));
-
$url = Request::isHTTPS() ? 'https://' : 'http://';
$url .= $_SERVER['SERVER_NAME'];
$url .= $_SERVER['SERVER_PORT'] == 80 || $_SERVER['SERVER_PORT'] == 443 ? '' : ':'.$_SERVER['SERVER_PORT'];
- $url .= $self !== '/' ? $self.'/' : '/';
+ $url .= $this->dir() ?: '/';
return $url;
}
+
+ /**
+ * Build relative url
+ *
+ * @access private
+ * @param string $separator Querystring argument separator
+ * @param string $controller Controller name
+ * @param string $action Action name
+ * @param array $params Url parameters
+ * @param boolean $csrf Add a CSRF token
+ * @param string $anchor Link Anchor
+ * @param boolean $absolute Absolute or relative link
+ * @return string
+ */
+ private function build($separator, $controller, $action, array $params = array(), $csrf = false, $anchor = '', $absolute = false)
+ {
+ $path = $this->router->findUrl($controller, $action, $params);
+ $qs = array();
+
+ if (empty($path)) {
+ $qs['controller'] = $controller;
+ $qs['action'] = $action;
+ $qs += $params;
+ }
+
+ if ($csrf) {
+ $qs['csrf_token'] = Security::getCSRFToken();
+ }
+
+ if (! empty($qs)) {
+ $path .= '?'.http_build_query($qs, '', $separator);
+ }
+
+ return ($absolute ? $this->base() : $this->dir()).$path.(empty($anchor) ? '' : '#'.$anchor);
+ }
}
diff --git a/app/Integration/GitlabWebhook.php b/app/Integration/GitlabWebhook.php
index dce7413a..b8925daf 100644
--- a/app/Integration/GitlabWebhook.php
+++ b/app/Integration/GitlabWebhook.php
@@ -21,14 +21,16 @@ class GitlabWebhook extends \Core\Base
const EVENT_ISSUE_OPENED = 'gitlab.webhook.issue.opened';
const EVENT_ISSUE_CLOSED = 'gitlab.webhook.issue.closed';
const EVENT_COMMIT = 'gitlab.webhook.commit';
+ const EVENT_ISSUE_COMMENT = 'gitlab.webhook.issue.commented';
/**
* Supported webhook events
*
* @var string
*/
- const TYPE_PUSH = 'push';
- const TYPE_ISSUE = 'issue';
+ const TYPE_PUSH = 'push';
+ const TYPE_ISSUE = 'issue';
+ const TYPE_COMMENT = 'comment';
/**
* Project id
@@ -63,6 +65,8 @@ class GitlabWebhook extends \Core\Base
return $this->handlePushEvent($payload);
case self::TYPE_ISSUE;
return $this->handleIssueEvent($payload);
+ case self::TYPE_COMMENT;
+ return $this->handleCommentEvent($payload);
}
return false;
@@ -77,15 +81,20 @@ class GitlabWebhook extends \Core\Base
*/
public function getType(array $payload)
{
- if (isset($payload['object_kind']) && $payload['object_kind'] === 'issue') {
- return self::TYPE_ISSUE;
+ if (empty($payload['object_kind'])) {
+ return '';
}
- if (isset($payload['commits'])) {
- return self::TYPE_PUSH;
+ switch ($payload['object_kind']) {
+ case 'issue':
+ return self::TYPE_ISSUE;
+ case 'note':
+ return self::TYPE_COMMENT;
+ case 'push':
+ return self::TYPE_PUSH;
+ default:
+ return '';
}
-
- return '';
}
/**
@@ -213,4 +222,46 @@ class GitlabWebhook extends \Core\Base
return false;
}
+
+ /**
+ * Parse comment issue events
+ *
+ * @access public
+ * @param array $payload Event data
+ * @return boolean
+ */
+ public function handleCommentEvent(array $payload)
+ {
+ if (! isset($payload['issue'])) {
+ return false;
+ }
+
+ $task = $this->taskFinder->getByReference($this->project_id, $payload['issue']['id']);
+
+ if (! empty($task)) {
+
+ $user = $this->user->getByUsername($payload['user']['username']);
+
+ if (! empty($user) && ! $this->projectPermission->isMember($this->project_id, $user['id'])) {
+ $user = array();
+ }
+
+ $event = array(
+ 'project_id' => $this->project_id,
+ 'reference' => $payload['object_attributes']['id'],
+ 'comment' => $payload['object_attributes']['note']."\n\n[".t('By @%s on Gitlab', $payload['user']['username']).']('.$payload['object_attributes']['url'].')',
+ 'user_id' => ! empty($user) ? $user['id'] : 0,
+ 'task_id' => $task['id'],
+ );
+
+ $this->container['dispatcher']->dispatch(
+ self::EVENT_ISSUE_COMMENT,
+ new GenericEvent($event)
+ );
+
+ return true;
+ }
+
+ return false;
+ }
}
diff --git a/app/Integration/HipchatWebhook.php b/app/Integration/HipchatWebhook.php
index f1be0f34..1d08e514 100644
--- a/app/Integration/HipchatWebhook.php
+++ b/app/Integration/HipchatWebhook.php
@@ -72,8 +72,7 @@ class HipchatWebhook extends \Core\Base
$html .= $this->projectActivity->getTitle($event);
if ($this->config->get('application_url')) {
- $html .= '<br/><a href="'.$this->config->get('application_url');
- $html .= $this->helper->url->href('task', 'show', array('task_id' => $task_id, 'project_id' => $project_id)).'">';
+ $html .= '<br/><a href="'.$this->helper->url->href('task', 'show', array('task_id' => $task_id, 'project_id' => $project_id), false, '', true).'">';
$html .= t('view the task on Kanboard').'</a>';
}
diff --git a/app/Integration/Jabber.php b/app/Integration/Jabber.php
index a1191662..3e403aab 100644
--- a/app/Integration/Jabber.php
+++ b/app/Integration/Jabber.php
@@ -81,8 +81,7 @@ class Jabber extends \Core\Base
$payload = '['.$project['name'].'] '.str_replace('&quot;', '"', $this->projectActivity->getTitle($event)).(isset($event['task']['title']) ? ' ('.$event['task']['title'].')' : '');
if ($this->config->get('application_url')) {
- $payload .= ' '.$this->config->get('application_url');
- $payload .= $this->helper->url->to('task', 'show', array('task_id' => $task_id, 'project_id' => $project_id));
+ $payload .= ' '.$this->helper->url->to('task', 'show', array('task_id' => $task_id, 'project_id' => $project_id), false, '', true);
}
$this->sendMessage($project_id, $payload);
diff --git a/app/Integration/SlackWebhook.php b/app/Integration/SlackWebhook.php
index 498cea09..d238652f 100644
--- a/app/Integration/SlackWebhook.php
+++ b/app/Integration/SlackWebhook.php
@@ -83,8 +83,7 @@ class SlackWebhook extends \Core\Base
);
if ($this->config->get('application_url')) {
- $payload['text'] .= ' - <'.$this->config->get('application_url');
- $payload['text'] .= $this->helper->url->href('task', 'show', array('task_id' => $task_id, 'project_id' => $project_id));
+ $payload['text'] .= ' - <'.$this->helper->url->href('task', 'show', array('task_id' => $task_id, 'project_id' => $project_id), false, '', true);
$payload['text'] .= '|'.t('view the task on Kanboard').'>';
}
diff --git a/app/Locale/da_DK/translations.php b/app/Locale/da_DK/translations.php
index 91d7b98a..5f55f3e8 100644
--- a/app/Locale/da_DK/translations.php
+++ b/app/Locale/da_DK/translations.php
@@ -126,7 +126,6 @@ return array(
'The project name is required' => 'Projektets navn er krævet',
'This project must be unique' => 'Projektets navn skal være unikt',
'The title is required' => 'Titel er krævet',
- 'There is no active project, the first step is to create a new project.' => 'Der er ingen aktive projekter. Første step er at oprette et nyt projekt.',
'Settings saved successfully.' => 'Indstillinger gemt.',
'Unable to save your settings.' => 'Indstillinger kunne ikke gemmes.',
'Database optimization done.' => 'Databaseoptimeringen er fuldført.',
@@ -264,11 +263,10 @@ return array(
'%d comments' => '%d kommentarer',
'%d comment' => '%d kommentar',
'Email address invalid' => 'Ugyldig email',
- 'Your Google Account is not linked anymore to your profile.' => 'Din Google-konto er ikke længere forbundet til din profil.',
- 'Unable to unlink your Google Account.' => 'Det var ikke muligt at fjerne din Google-konto.',
- 'Google authentication failed' => 'Google autentificering mislykkedes',
- 'Unable to link your Google Account.' => 'Det var ikke muligt at forbinde til din Google-konto.',
- 'Your Google Account is linked to your profile successfully.' => 'Din Google-konto er forbundet til din profil.',
+ // 'Your external account is not linked anymore to your profile.' => '',
+ // 'Unable to unlink your external account.' => '',
+ // 'External authentication failed' => '',
+ // 'Your external account is linked to your profile successfully.' => '',
'Email' => 'E-Mail',
'Link my Google Account' => 'Forbind min Google-konto',
'Unlink my Google Account' => 'Fjern forbindelsen til min Google-konto',
@@ -338,14 +336,9 @@ return array(
'Maximum size: ' => 'Maksimum størrelse: ',
'Unable to upload the file.' => 'Filen kunne ikke uploades.',
'Display another project' => 'Vis et andet projekt...',
- 'Your GitHub account was successfully linked to your profile.' => 'Din GitHub-konto er forbundet til din profil.',
- 'Unable to link your GitHub Account.' => 'Det var ikke muligt er forbinde til din GitHub-konto.',
- 'GitHub authentication failed' => 'GitHub autentificering mislykkedes',
- 'Your GitHub account is no longer linked to your profile.' => 'Din GitHub-konto er ikke længere forbundet til din profil.',
- 'Unable to unlink your GitHub Account.' => 'Det var ikke muligt at fjerne forbindelsen til din GitHub-konto.',
- 'Login with my GitHub Account' => 'Login med min GitHub-konto',
- 'Link my GitHub Account' => 'Forbind min GitHub-konto',
- 'Unlink my GitHub Account' => 'Fjern forbindelsen til min GitHub-konto',
+ 'Login with my Github Account' => 'Login med min Github-konto',
+ 'Link my Github Account' => 'Forbind min Github-konto',
+ 'Unlink my Github Account' => 'Fjern forbindelsen til min Github-konto',
'Created by %s' => 'Oprettet af %s',
'Last modified on %B %e, %Y at %k:%M %p' => 'Sidst redigeret %d.%m.%Y - %H:%M',
'Tasks Export' => 'Opgave eksport',
@@ -403,7 +396,7 @@ return array(
'Enabled' => 'Aktiv',
'Disabled' => 'Deaktiveret',
'Google account linked' => 'Google-konto forbundet',
- 'Github account linked' => 'GitHub-konto forbundet',
+ 'Github account linked' => 'Github-konto forbundet',
'Username:' => 'Brugernavn',
'Name:' => 'Navn:',
'Email:' => 'Email:',
@@ -417,7 +410,7 @@ return array(
'Password modification' => 'Adgangskode ændring',
'External authentications' => 'Ekstern autentificering',
'Google Account' => 'Google-konto',
- 'Github Account' => 'GitHub-konto',
+ 'Github Account' => 'Github-konto',
'Never connected.' => 'Aldrig forbundet.',
'No account linked.' => 'Ingen kontoer forfundet.',
'Account linked.' => 'Konto forbundet.',
@@ -615,8 +608,7 @@ return array(
// 'Time Tracking' => '',
// 'You already have one subtask in progress' => '',
// 'Which parts of the project do you want to duplicate?' => '',
- // 'Disable login form' => '',
- // 'Show/hide calendar' => '',
+ // 'Disallow login form' => '',
// 'Bitbucket commit received' => '',
// 'Bitbucket webhooks' => '',
// 'Help on Bitbucket webhooks' => '',
@@ -971,4 +963,39 @@ return array(
// 'Search by category: ' => '',
// 'Search by description: ' => '',
// 'Search by due date: ' => '',
+ // 'Lead and Cycle time for "%s"' => '',
+ // 'Average time spent into each column for "%s"' => '',
+ // 'Average time spent into each column' => '',
+ // 'Average time spent' => '',
+ // 'This chart show the average time spent into each column for the last %d tasks.' => '',
+ // 'Average Lead and Cycle time' => '',
+ // 'Average lead time: ' => '',
+ // 'Average cycle time: ' => '',
+ // 'Cycle Time' => '',
+ // 'Lead Time' => '',
+ // 'This chart show the average lead and cycle time for the last %d tasks over the time.' => '',
+ // 'Average time into each column' => '',
+ // 'Lead and cycle time' => '',
+ // 'Google Authentication' => '',
+ // 'Help on Google authentication' => '',
+ // 'Github Authentication' => '',
+ // 'Help on Github authentication' => '',
+ // 'Channel/Group/User (Optional)' => '',
+ // 'Lead time: ' => '',
+ // 'Cycle time: ' => '',
+ // 'Time spent into each column' => '',
+ // 'The lead time is the duration between the task creation and the completion.' => '',
+ // 'The cycle time is the duration between the start date and the completion.' => '',
+ // 'If the task is not closed the current time is used instead of the completion date.' => '',
+ // 'Set automatically the start date' => '',
+ // 'Edit Authentication' => '',
+ // 'Google Id' => '',
+ // 'Github Id' => '',
+ // 'Remote user' => '',
+ // 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '',
+ // 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '',
+ // 'By @%s on Gitlab' => '',
+ // 'Gitlab issue comment created' => '',
+ // 'New remote user' => '',
+ // 'New local user' => '',
);
diff --git a/app/Locale/de_DE/translations.php b/app/Locale/de_DE/translations.php
index 100335c5..90c029ba 100644
--- a/app/Locale/de_DE/translations.php
+++ b/app/Locale/de_DE/translations.php
@@ -91,7 +91,7 @@ return array(
'Download the database' => 'Datenbank herunterladen',
'Optimize the database' => 'Datenbank optimieren',
'(VACUUM command)' => '(VACUUM Befehl)',
- '(Gzip compressed Sqlite file)' => '(Gzip-komprimierte Sqlite Datei)',
+ '(Gzip compressed Sqlite file)' => '(Gzip-komprimierte SQLite-Datei)',
'Close a task' => 'Aufgabe abschließen',
'Edit a task' => 'Aufgabe bearbeiten',
'Column' => 'Spalte',
@@ -117,7 +117,7 @@ return array(
'The password is required' => 'Das Passwort wird benötigt',
'This value must be an integer' => 'Dieser Wert muss eine ganze Zahl sein',
'The username must be unique' => 'Der Benutzername muss eindeutig sein',
- 'The user id is required' => 'Die Benutzer ID ist anzugeben',
+ 'The user id is required' => 'Die Benutzer-ID ist anzugeben',
'Passwords don\'t match' => 'Passwörter nicht gleich',
'The confirmation is required' => 'Die Bestätigung ist erforderlich',
'The project is required' => 'Das Projekt ist anzugeben',
@@ -126,7 +126,6 @@ return array(
'The project name is required' => 'Der Projektname ist anzugeben',
'This project must be unique' => 'Der Projektname muss eindeutig sein',
'The title is required' => 'Der Titel ist anzugeben',
- 'There is no active project, the first step is to create a new project.' => 'Es gibt kein aktives Projekt. Zunächst muss ein Projekt erstellt werden.',
'Settings saved successfully.' => 'Einstellungen erfolgreich gespeichert.',
'Unable to save your settings.' => 'Speichern der Einstellungen nicht möglich.',
'Database optimization done.' => 'Optimieren der Datenbank abgeschlossen.',
@@ -246,8 +245,8 @@ return array(
'Last logins' => 'Letzte Anmeldungen',
'Login date' => 'Anmeldedatum',
'Authentication method' => 'Authentisierungsmethode',
- 'IP address' => 'IP Adresse',
- 'User agent' => 'User Agent',
+ 'IP address' => 'IP-Adresse',
+ 'User agent' => 'User-Agent',
'Persistent connections' => 'Bestehende Verbindungen',
'No session.' => 'Keine Sitzung.',
'Expiration date' => 'Ablaufdatum',
@@ -264,15 +263,14 @@ return array(
'%d comments' => '%d Kommentare',
'%d comment' => '%d Kommentar',
'Email address invalid' => 'Ungültige E-Mail-Adresse',
- 'Your Google Account is not linked anymore to your profile.' => 'Google Account nicht mehr mit dem Profil verbunden.',
- 'Unable to unlink your Google Account.' => 'Trennung der Verbindung zum Google Account nicht möglich.',
- 'Google authentication failed' => 'Zugriff mit Google fehlgeschlagen',
- 'Unable to link your Google Account.' => 'Verbindung mit diesem Google Account nicht möglich.',
- 'Your Google Account is linked to your profile successfully.' => 'Der Google Account wurde erfolgreich verbunden.',
+ // 'Your external account is not linked anymore to your profile.' => '',
+ // 'Unable to unlink your external account.' => '',
+ // 'External authentication failed' => '',
+ // 'Your external account is linked to your profile successfully.' => '',
'Email' => 'E-Mail',
- 'Link my Google Account' => 'Verbinde meinen Google Account',
- 'Unlink my Google Account' => 'Verbindung mit meinem Google Account trennen',
- 'Login with my Google Account' => 'Anmelden mit meinem Google Account',
+ 'Link my Google Account' => 'Verbinde meinen Google-Account',
+ 'Unlink my Google Account' => 'Verbindung mit meinem Google-Account trennen',
+ 'Login with my Google Account' => 'Anmelden mit meinem Google-Account',
'Project not found.' => 'Das Projekt wurde nicht gefunden.',
'Task removed successfully.' => 'Aufgabe erfolgreich gelöscht.',
'Unable to remove this task.' => 'Löschen der Aufgabe nicht möglich.',
@@ -338,14 +336,9 @@ return array(
'Maximum size: ' => 'Maximalgröße: ',
'Unable to upload the file.' => 'Hochladen der Datei nicht möglich.',
'Display another project' => 'Zu Projekt wechseln',
- '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.',
- 'GitHub authentication failed' => 'Zugriff mit GitHub fehlgeschlagen',
- 'Your GitHub account is no longer linked to your profile.' => 'GitHub Account nicht mehr mit dem Profil verbunden.',
- 'Unable to unlink your GitHub Account.' => 'Trennung der Verbindung zum GitHub Account nicht möglich.',
- 'Login with my GitHub Account' => 'Anmelden mit meinem GitHub Account',
- 'Link my GitHub Account' => 'Mit meinem GitHub Account verbinden',
- 'Unlink my GitHub Account' => 'Verbindung mit meinem GitHub Account trennen',
+ 'Login with my Github Account' => 'Anmelden mit meinem Github-Account',
+ 'Link my Github Account' => 'Mit meinem Github-Account verbinden',
+ 'Unlink my Github Account' => 'Verbindung mit meinem Github-Account trennen',
'Created by %s' => 'Erstellt durch %s',
'Last modified on %B %e, %Y at %k:%M %p' => 'Letzte Änderung am %d.%m.%Y um %H:%M',
'Tasks Export' => 'Aufgaben exportieren',
@@ -360,8 +353,8 @@ return array(
'Clone' => 'duplizieren',
'Project cloned successfully.' => 'Projekt wurde dupliziert.',
'Unable to clone this project.' => 'Duplizieren dieses Projekts schlug fehl.',
- 'Email notifications' => 'E-Mail Benachrichtigungen',
- 'Enable email notifications' => 'E-Mail Benachrichtigungen einschalten',
+ 'Email notifications' => 'E-Mail-Benachrichtigungen',
+ 'Enable email notifications' => 'E-Mail-Benachrichtigungen einschalten',
'Task position:' => 'Position der Aufgabe',
'The task #%d have been opened.' => 'Die Aufgabe #%d wurde geöffnet.',
'The task #%d have been closed.' => 'Die Aufgabe #%d wurde geschlossen.',
@@ -402,8 +395,8 @@ return array(
'Remote' => 'Remote',
'Enabled' => 'angeschaltet',
'Disabled' => 'abgeschaltet',
- 'Google account linked' => 'Mit Googleaccount verbunden',
- 'Github account linked' => 'Mit Githubaccount verbunden',
+ 'Google account linked' => 'Mit Google-Account verbunden',
+ 'Github account linked' => 'Mit Github-Account verbunden',
'Username:' => 'Benutzername',
'Name:' => 'Name',
'Email:' => 'E-Mail',
@@ -416,8 +409,8 @@ return array(
'Change password' => 'Passwort ändern',
'Password modification' => 'Passwortänderung',
'External authentications' => 'Externe Authentisierungsmethoden',
- 'Google Account' => 'Googleaccount',
- 'Github Account' => 'Githubaccount',
+ 'Google Account' => 'Google-Account',
+ 'Github Account' => 'Github-Account',
'Never connected.' => 'Noch nie verbunden.',
'No account linked.' => 'Kein Account verbunden.',
'Account linked.' => 'Account verbunden',
@@ -475,17 +468,17 @@ return array(
'Database driver:' => 'Datenbanktreiber',
'Board settings' => 'Pinnwandeinstellungen',
'URL and token' => 'URL und Token',
- 'Webhook settings' => 'Webhook Einstellungen',
+ 'Webhook settings' => 'Webhook-Einstellungen',
'URL for task creation:' => 'URL zur Aufgabenerstellung',
'Reset token' => 'Token zurücksetzen',
- 'API endpoint:' => 'API Endpunkt',
+ 'API endpoint:' => 'API-Endpunkt',
'Refresh interval for private board' => 'Aktualisierungsintervall für private Pinnwände',
'Refresh interval for public board' => 'Aktualisierungsintervall für öffentliche Pinnwände',
'Task highlight period' => 'Aufgaben-Hervorhebungsdauer',
'Period (in second) to consider a task was modified recently (0 to disable, 2 days by default)' => 'Dauer (in Sekunden), wie lange eine Aufgabe als kürzlich verändert gilt (0 um diese Funktion zu deaktivieren, standardmäßig 2 Tage)',
'Frequency in second (60 seconds by default)' => 'Frequenz in Sekunden (standardmäßig 60 Sekunden)',
'Frequency in second (0 to disable this feature, 10 seconds by default)' => 'Frequenz in Sekunden (0 um diese Funktion zu deaktivieren, standardmäßig 10 Sekunden)',
- 'Application URL' => 'Applikations URL',
+ 'Application URL' => 'Applikations-URL',
'Example: http://example.kanboard.net/ (used by email notifications)' => 'Beispiel: http://example.kanboard.net/ (wird für E-Mail-Benachrichtigungen verwendet)',
'Token regenerated.' => 'Token wurde neu generiert.',
'Date format' => 'Datumsformat',
@@ -508,10 +501,10 @@ return array(
'Everybody have access to this project.' => 'Jeder hat Zugriff zu diesem Projekt',
'Webhooks' => 'Webhooks',
'API' => 'API',
- 'Github webhooks' => 'Github Webhook',
- 'Help on Github webhooks' => 'Hilfe für Github Webhooks',
+ 'Github webhooks' => 'Github-Webhook',
+ 'Help on Github webhooks' => 'Hilfe für Github-Webhooks',
'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' => 'Kommentar zum Github-Issue hinzugefügt',
'Project management' => 'Projektmanagement',
'My projects' => 'Meine Projekte',
'Columns' => 'Spalten',
@@ -533,15 +526,15 @@ return array(
'Not enough data to show the graph.' => 'Nicht genügend Daten, um die Grafik zu zeigen.',
'Previous' => 'Vorherige',
'The id must be an integer' => 'Die Id muss eine ganze Zahl sein',
- 'The project id must be an integer' => 'Der Projektid muss eine ganze Zahl sein',
+ 'The project id must be an integer' => 'Der Projekt-ID muss eine ganze Zahl sein',
'The status must be an integer' => 'Der Status muss eine ganze Zahl sein',
- 'The subtask id is required' => 'Die Teilaufgabenid ist benötigt',
- 'The subtask id must be an integer' => 'Die Teilaufgabenid muss eine ganze Zahl sein',
- 'The task id is required' => 'Die Aufgabenid ist benötigt',
- 'The task id must be an integer' => 'Die Aufgabenid muss eine ganze Zahl sein',
- 'The user id must be an integer' => 'Die Userid muss eine ganze Zahl sein',
+ 'The subtask id is required' => 'Die Teilaufgaben-ID ist benötigt',
+ 'The subtask id must be an integer' => 'Die Teilaufgaben-ID muss eine ganze Zahl sein',
+ 'The task id is required' => 'Die Aufgaben-ID ist benötigt',
+ 'The task id must be an integer' => 'Die Aufgaben-ID muss eine ganze Zahl sein',
+ 'The user id must be an integer' => 'Die User-ID muss eine ganze Zahl sein',
'This value is required' => 'Dieser Wert ist erforderlich',
- 'This value must be numeric' => 'Dieser Wert muss numerisch sein',
+ 'This value must be numeric' => 'Dieser Wert muss nummerisch sein',
'Unable to create this task.' => 'Diese Aufgabe kann nicht erstellt werden',
'Cumulative flow diagram' => 'Kumulatives Flussdiagramm',
'Cumulative flow diagram for "%s"' => 'Kumulatives Flussdiagramm für "%s"',
@@ -555,44 +548,44 @@ return array(
'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',
+ '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"',
+ '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.',
+ '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, 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 Swimlane 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 Fehler eröffnet',
- 'Gitlab issue closed' => 'Gitlab Fehler geschlossen',
- 'Gitlab webhooks' => 'Gitlab Webhook',
- 'Help on Gitlab webhooks' => 'Hilfe für Gitlab Webhooks',
+ '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-Issue eröffnet',
+ 'Gitlab issue closed' => 'Gitlab-Issue geschlossen',
+ 'Gitlab webhooks' => 'Gitlab-Webhook',
+ 'Help on Gitlab webhooks' => 'Hilfe für Gitlab-Webhooks',
'Integrations' => 'Integration',
- 'Integration with third-party services' => 'Integration von Fremdleistungen',
+ 'Integration with third-party services' => 'Integration von externen Diensten',
'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 Fehler',
- 'Subtask Id' => 'Teilaufgaben Id',
+ 'Gitlab Issue' => 'Gitlab-Issue',
+ 'Subtask Id' => 'Teilaufgaben-ID',
'Subtasks' => 'Teilaufgaben',
- 'Subtasks Export' => 'Teilaufgaben Export',
- 'Subtasks exportation for "%s"' => 'Teilaufgaben Export für "%s"',
- 'Task Title' => 'Aufgaben Titel',
+ 'Subtasks Export' => 'Export von Teilaufgaben',
+ 'Subtasks exportation for "%s"' => 'Export von Teilaufgaben für "%s"',
+ 'Task Title' => 'Aufgaben-Titel',
'Untitled' => 'unbetitelt',
'Application default' => 'Anwendungsstandard',
'Language:' => 'Sprache:',
@@ -606,20 +599,19 @@ return array(
'All status' => 'Alle Status',
'Moved to column %s' => 'In Spalte %s verschoben',
'Change description' => 'Beschreibung ändern',
- 'User dashboard' => 'Benutzer Dashboard',
+ 'User dashboard' => 'Benutzer-Dashboard',
'Allow only one subtask in progress at the same time for a user' => 'Erlaube nur eine Teilaufgabe pro Benutzer zu bearbeiten',
'Edit column "%s"' => 'Spalte "%s" bearbeiten',
'Select the new status of the subtask: "%s"' => 'Wähle einen neuen Status für Teilaufgabe: "%s"',
'Subtask timesheet' => 'Teilaufgaben Zeiterfassung',
'There is nothing to show.' => 'Es ist nichts zum Anzeigen vorhanden.',
'Time Tracking' => 'Zeiterfassung',
- 'You already have one subtask in progress' => 'Bereits eine Teilaufgabe in bearbeitung',
+ 'You already have one subtask in progress' => 'Bereits eine Teilaufgabe in Bearbeitung',
'Which parts of the project do you want to duplicate?' => 'Welcher Teil des Projekts soll kopiert werden?',
- 'Disable login form' => 'Anmeldeformular deaktivieren',
- 'Show/hide calendar' => 'Kalender anzeigen/verbergen',
- 'Bitbucket commit received' => 'Bitbucket commit erhalten',
- 'Bitbucket webhooks' => 'Bitbucket webhooks',
- 'Help on Bitbucket webhooks' => 'Hilfe für Bitbucket webhooks',
+ // 'Disallow login form' => '',
+ 'Bitbucket commit received' => 'Bitbucket-Commit erhalten',
+ 'Bitbucket webhooks' => 'Bitbucket-Webhooks',
+ 'Help on Bitbucket webhooks' => 'Hilfe für Bitbucket-Webhooks',
'Start' => 'Start',
'End' => 'Ende',
'Task age in days' => 'Aufgabenalter in Tagen',
@@ -639,7 +631,7 @@ return array(
'Link settings' => 'Verbindungseinstellungen',
'Opposite label' => 'Gegenteil',
'Remove a link' => 'Verbindung entfernen',
- 'Task\'s links' => 'Aufgaben Verbindungen',
+ 'Task\'s links' => 'Aufgaben-Verbindungen',
'The labels must be different' => 'Die Beschriftung muss unterschiedlich sein',
'There is no link.' => 'Es gibt keine Verbindung',
'This label must be unique' => 'Die Beschriftung muss einzigartig sein',
@@ -707,18 +699,18 @@ return array(
'Do you really want to remove this time slot?' => 'Soll diese Zeitfenster wirklich gelöscht werden?',
'Remove time slot' => 'Zeitfenster entfernen',
'Add new time slot' => 'Neues Zeitfenster hinzufügen',
- 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => 'Dieses Zeitfenster wird verwendet, wenn die Checkbox "gantägig" für Freizeit und Überstunden angeklickt ist.',
+ 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => 'Dieses Zeitfenster wird verwendet, wenn die Checkbox "ganztägig" für Freizeit und Überstunden angeklickt ist.',
'Files' => 'Dateien',
'Images' => 'Bilder',
'Private project' => 'privates Projekt',
'Amount' => 'Betrag',
- // 'AUD - Australian Dollar' => '',
+ 'AUD - Australian Dollar' => 'AUD - Australische Dollar',
'Budget' => 'Budget',
'Budget line' => 'Budgetlinie',
'Budget line removed successfully.' => 'Budgetlinie erfolgreich entfernt',
'Budget lines' => 'Budgetlinien',
- // 'CAD - Canadian Dollar' => '',
- // 'CHF - Swiss Francs' => '',
+ 'CAD - Canadian Dollar' => 'CAD - Kanadische Dollar',
+ 'CHF - Swiss Francs' => 'CHF - Schweizer Franken',
'Cost' => 'Kosten',
'Cost breakdown' => 'Kostenaufschlüsselung',
'Custom Stylesheet' => 'benutzerdefiniertes Stylesheet',
@@ -726,9 +718,9 @@ return array(
'Do you really want to remove this budget line?' => 'Soll diese Budgetlinie wirklich entfernt werden?',
'EUR - Euro' => 'EUR - Euro',
'Expenses' => 'Kosten',
- 'GBP - British Pound' => 'GBP - Britische Pfung',
+ 'GBP - British Pound' => 'GBP - Britische Pfund',
'INR - Indian Rupee' => 'INR - Indische Rupien',
- 'JPY - Japanese Yen' => 'JPY - Japanischer Yen',
+ 'JPY - Japanese Yen' => 'JPY - Japanische Yen',
'New budget line' => 'Neue Budgetlinie',
'NZD - New Zealand Dollar' => 'NZD - Neuseeland-Dollar',
'Remove a budget line' => 'Budgetlinie entfernen',
@@ -737,37 +729,37 @@ return array(
'The budget line have been created successfully.' => 'Die Budgetlinie wurde erfolgreich angelegt.',
'Unable to create the budget line.' => 'Budgetlinie konnte nicht erstellt werden.',
'Unable to remove this budget line.' => 'Budgetlinie konnte nicht gelöscht werden.',
- 'USD - US Dollar' => 'USD - US Dollar',
+ 'USD - US Dollar' => 'USD - US-Dollar',
'Remaining' => 'Verbleibend',
'Destination column' => 'Zielspalte',
'Move the task to another column when assigned to a user' => 'Aufgabe in eine andere Spalte verschieben, wenn ein User zugeordnet wurde.',
'Move the task to another column when assignee is cleared' => 'Aufgabe in eine andere Spalte verschieben, wenn die Zuordnung gelöscht wurde.',
'Source column' => 'Quellspalte',
- 'Show subtask estimates (forecast of future work)' => 'Teilaufgaben Schätzungen anzeigen (Prognose)',
+ 'Show subtask estimates (forecast of future work)' => 'Teilaufgaben-Schätzungen anzeigen (Prognose)',
'Transitions' => 'Übergänge',
'Executer' => 'Ausführender',
'Time spent in the column' => 'Zeit in Spalte verbracht',
- 'Task transitions' => 'Aufgaben Übergänge',
- 'Task transitions export' => 'Aufgaben Übergänge exportieren',
+ 'Task transitions' => 'Aufgaben-Übergänge',
+ 'Task transitions export' => 'Aufgaben-Übergänge exportieren',
'This report contains all column moves for each task with the date, the user and the time spent for each transition.' => 'Diese Auswertung enthält alle Spaltenbewegungen für jede Aufgabe mit Datum, Benutzer und Zeit vor jedem Wechsel.',
'Currency rates' => 'Währungskurse',
'Rate' => 'Kurse',
'Change reference currency' => 'Referenzwährung ändern',
'Add a new currency rate' => 'Neuen Währungskurs hinzufügen',
- 'Currency rates are used to calculate project budget.' => 'Währungskurse werden verwendet um das Projektbudget zu berechnen.',
+ 'Currency rates are used to calculate project budget.' => 'Währungskurse werden verwendet, um das Projektbudget zu berechnen.',
'Reference currency' => 'Referenzwährung',
'The currency rate have been added successfully.' => 'Der Währungskurs wurde erfolgreich hinzugefügt.',
'Unable to add this currency rate.' => 'Währungskurs konnte nicht hinzugefügt werden',
'Send notifications to a Slack channel' => 'Benachrichtigung an einen Slack-Kanal senden',
- 'Webhook URL' => 'Webhook URL',
- 'Help on Slack integration' => 'Hilfe für Slack integration.',
+ 'Webhook URL' => 'Webhook-URL',
+ 'Help on Slack integration' => 'Hilfe für Slack-Integration.',
'%s remove the assignee of the task %s' => '%s Zuordnung für die Aufgabe %s entfernen',
'Send notifications to Hipchat' => 'Sende Benachrichtigung an Hipchat',
- 'API URL' => 'API URL',
- 'Room API ID or name' => 'Raum API ID oder Name',
- 'Room notification token' => 'Raum Benachrichtigungstoken',
- 'Help on Hipchat integration' => 'Hilfe bei Hipchat Integration',
- 'Enable Gravatar images' => 'Aktiviere Gravatar Bilder',
+ 'API URL' => 'API-URL',
+ 'Room API ID or name' => 'Raum-API-ID oder -Name',
+ 'Room notification token' => 'Raum-Benachrichtigungstoken',
+ 'Help on Hipchat integration' => 'Hilfe bei Hipchat-Integration',
+ 'Enable Gravatar images' => 'Aktiviere Gravatar-Bilder',
'Information' => 'Information',
'Check two factor authentication code' => 'Prüfe Zwei-Faktor-Authentifizierungscode',
'The two factor authentication code is not valid.' => 'Der Zwei-Faktor-Authentifizierungscode ist ungültig.',
@@ -810,7 +802,7 @@ return array(
'Recurrent task is scheduled to be generated' => 'Wiederkehrende Aufgabe ist zur Generierung eingeplant',
'Recurring information' => 'Wiederkehrende Information',
'Score' => 'Wertung',
- 'The identifier must be unique' => 'Der Schlüssel miss einzigartig sein',
+ 'The identifier must be unique' => 'Der Schlüssel muss einzigartig sein',
'This linked task id doesn\'t exists' => 'Die verbundene Aufgabe existiert nicht',
'This value must be alphanumeric' => 'Der Wert muss alphanumerisch sein',
'Edit recurrence' => 'Wiederholung bearbeiten',
@@ -836,40 +828,40 @@ return array(
'When task is moved to last column' => 'Wenn Aufgabe in letzte Spalte verschoben wird',
'Year(s)' => 'Jahr(e)',
// 'Jabber (XMPP)' => '',
- // 'Send notifications to Jabber' => '',
- // 'XMPP server address' => '',
- // 'Jabber domain' => '',
- // 'Jabber nickname' => '',
- // 'Multi-user chat room' => '',
- // 'Help on Jabber integration' => '',
- // 'The server address must use this format: "tcp://hostname:5222"' => '',
- 'Calendar settings' => 'Kalendar Einstellungen',
+ 'Send notifications to Jabber' => 'Benachrichtigungen an Jabber senden',
+ 'XMPP server address' => 'XMPP-Server-Adresse',
+ 'Jabber domain' => 'Jabber-Domain',
+ 'Jabber nickname' => 'Jabber-Nickname',
+ 'Multi-user chat room' => 'Multi-User-Chatroom',
+ 'Help on Jabber integration' => 'Hilfe zur Jabber-Integration',
+ 'The server address must use this format: "tcp://hostname:5222"' => 'Die Server-Adresse muss in diesem Format sein: "tcp://hostname:5222"',
+ 'Calendar settings' => 'Kalender-Einstellungen',
'Project calendar view' => 'Projekt-Kalendarsicht',
'Project settings' => 'Projekteinstellungen',
'Show subtasks based on the time tracking' => 'Zeige Teilaufgaben basierend auf Zeiterfassung',
'Show tasks based on the creation date' => 'Zeige Aufgaben basierend auf Erstelldatum',
'Show tasks based on the start date' => 'Zeige Aufgaben basierend auf Beginndatum',
- 'Subtasks time tracking' => 'Teilaufgaben Zeiterfassung',
- 'User calendar view' => 'Benutzer-Kalendarsicht',
+ 'Subtasks time tracking' => 'Teilaufgaben-Zeiterfassung',
+ 'User calendar view' => 'Benutzer-Kalendersicht',
'Automatically update the start date' => 'Beginndatum automatisch aktualisieren',
// 'iCal feed' => '',
'Preferences' => 'Einstellungen',
'Security' => 'Sicherheit',
- 'Two factor authentication disabled' => 'Zweifaktorauthentifizierung deaktiviert',
- 'Two factor authentication enabled' => 'Zweifaktorauthentifizierung aktiviert',
- 'Unable to update this user.' => 'User kann nicht bearbeitet werden',
+ 'Two factor authentication disabled' => 'Zwei-Faktor-Authentifizierung deaktiviert',
+ 'Two factor authentication enabled' => 'Zwei-Faktor-Authentifizierung aktiviert',
+ 'Unable to update this user.' => 'Benutzer kann nicht bearbeitet werden',
'There is no user management for private projects.' => 'Es gibt keine Benutzerverwaltung für private Projekte',
'User that will receive the email' => 'Empfänger der E-Mail',
- 'Email subject' => 'E-Mail Betreff',
+ 'Email subject' => 'E-Mail-Betreff',
'Date' => 'Datum',
// 'By @%s on Bitbucket' => '',
- // 'Bitbucket Issue' => '',
+ 'Bitbucket Issue' => 'Bitbucket-Issue',
// 'Commit made by @%s on Bitbucket' => '',
// 'Commit made by @%s on Github' => '',
// 'By @%s on Github' => '',
// 'Commit made by @%s on Gitlab' => '',
- 'Add a comment log when moving the task between columns' => 'Kommentar hinzufügen, wenn Aufgabe in andere Spalte geschoben wird',
- 'Move the task to another column when the category is changed' => 'Aufgabe in andere Spalte verschieben, wenn Kategorie geändert',
+ 'Add a comment log when moving the task between columns' => 'Kommentar hinzufügen, wenn Aufgabe in andere Spalte verschoben wird',
+ 'Move the task to another column when the category is changed' => 'Aufgabe in andere Spalte verschieben, wenn Kategorie geändert wird',
'Send a task by email to someone' => 'Aufgabe per E-Mail versenden',
'Reopen a task' => 'Aufgabe wieder öffnen',
// 'Bitbucket issue opened' => '',
@@ -886,16 +878,16 @@ return array(
'%s moved the task #%d to the first swimlane' => '%s hat die Aufgabe #%d in die erste Swimlane verschoben',
'%s moved the task #%d to the swimlane "%s"' => '%s hat die Aufgabe #%d in die Swimlane "%s" verschoben',
// 'Swimlane' => '',
- 'Budget overview' => 'Budget Übersicht',
+ 'Budget overview' => 'Budget-Übersicht',
'Type' => 'Typ',
- 'There is not enough data to show something.' => 'Es gibt nicht genug Daten für die Anzeige',
+ 'There is not enough data to show something.' => 'Es gibt nicht genügend Daten für diese Anzeige',
// 'Gravatar' => '',
// 'Hipchat' => '',
// 'Slack' => '',
'%s moved the task %s to the first swimlane' => '%s hat die Aufgabe %s in die erste Swimlane verschoben',
'%s moved the task %s to the swimlane "%s"' => '%s hat die Aufgaben %s in die Swimlane "%s" verschoben',
- 'This report contains all subtasks information for the given date range.' => 'Der Bericht beinhaltet alle Teilaufgaben im ausgewählten Zeitraum',
- 'This report contains all tasks information for the given date range.' => 'Der Bericht beinhaltet alle Aufgaben im ausgewählten Zeitraum',
+ 'This report contains all subtasks information for the given date range.' => 'Der Bericht beinhaltet alle Teilaufgaben im gewählten Zeitraum',
+ 'This report contains all tasks information for the given date range.' => 'Der Bericht beinhaltet alle Aufgaben im gewählten Zeitraum',
'Project activities for %s' => 'Projektaktivitäten für %s',
'view the board on Kanboard' => 'Pinnwand in Kanboard anzeigen',
'The task have been moved to the first swimlane' => 'Die Aufgabe wurde in die erste Swimlane verschoben',
@@ -909,7 +901,7 @@ return array(
'New color: %s' => 'Neue Farbe: %s',
'New complexity: %d' => 'Neue Komplexität: %d',
'The due date have been removed' => 'Das Ablaufdatum wurde entfernt',
- 'There is no description anymore' => 'Es gibt keine BEschreibung mehr',
+ 'There is no description anymore' => 'Es gibt keine Beschreibung mehr',
'Recurrence settings have been modified' => 'Die Einstellungen für Wiederholung wurden geändert',
'Time spent changed: %sh' => 'Verbrauchte Zeit geändert: %sh',
'Time estimated changed: %sh' => 'Geschätzte Zeit geändert: %sh',
@@ -917,7 +909,7 @@ return array(
'The description have been modified' => 'Die Beschreibung wurde geändert',
'Do you really want to close the task "%s" as well as all subtasks?' => 'Soll die Aufgabe "%s" wirklich geschlossen werden? (einschließlich Teilaufgaben)',
// 'Swimlane: %s' => '',
- 'I want to receive notifications for:' => 'Ich möchte Benachrichtigungn erhalten für:',
+ 'I want to receive notifications for:' => 'Ich möchte Benachrichtigungen erhalten für:',
'All tasks' => 'Alle Aufgaben',
'Only for tasks assigned to me' => 'nur mir zugeordnete Aufgane',
'Only for tasks created by me' => 'nur von mir erstellte Aufgaben',
@@ -936,39 +928,74 @@ return array(
'Start timer' => 'Starte Timer',
'Add project member' => 'Projektmitglied hinzufügen',
'Enable notifications' => 'Benachrichtigung aktivieren',
- // 'My activity stream' => '',
- // 'My calendar' => '',
- // 'Search tasks' => '',
- // 'Back to the calendar' => '',
- // 'Filters' => '',
- // 'Reset filters' => '',
- // 'My tasks due tomorrow' => '',
- // 'Tasks due today' => '',
- // 'Tasks due tomorrow' => '',
- // 'Tasks due yesterday' => '',
- // 'Closed tasks' => '',
- // 'Open tasks' => '',
- // 'Not assigned' => '',
- // 'View advanced search syntax' => '',
- // 'Overview' => '',
+ 'My activity stream' => 'Aktivitätsstream',
+ 'My calendar' => 'Mein Kalender',
+ 'Search tasks' => 'Suche nach Aufgaben',
+ 'Back to the calendar' => 'Zurück zum Kalender',
+ 'Filters' => 'Filter',
+ 'Reset filters' => 'Filter zurücksetzen',
+ 'My tasks due tomorrow' => 'Meine morgen fälligen Aufgaben',
+ 'Tasks due today' => 'Heute fällige Aufgaben',
+ 'Tasks due tomorrow' => 'Morgen fällige Aufgaben',
+ 'Tasks due yesterday' => 'Gestern fällige Aufgaben',
+ 'Closed tasks' => 'Abgeschlossene Aufgaben',
+ 'Open tasks' => 'Offene Aufgaben',
+ 'Not assigned' => 'Nicht zugewiesen',
+ 'View advanced search syntax' => 'Zur erweiterten Suchsyntax',
+ 'Overview' => 'Überblick',
// '%b %e %Y' => '',
- // 'Board/Calendar/List view' => '',
- // 'Switch to the board view' => '',
- // 'Switch to the calendar view' => '',
- // 'Switch to the list view' => '',
- // 'Go to the search/filter box' => '',
- // 'There is no activity yet.' => '',
- // 'No tasks found.' => '',
- // 'Keyboard shortcut: "%s"' => '',
- // 'List' => '',
- // 'Filter' => '',
- // 'Advanced search' => '',
- // 'Example of query: ' => '',
- // 'Search by project: ' => '',
- // 'Search by column: ' => '',
- // 'Search by assignee: ' => '',
- // 'Search by color: ' => '',
- // 'Search by category: ' => '',
- // 'Search by description: ' => '',
- // 'Search by due date: ' => '',
+ 'Board/Calendar/List view' => 'Board-/Kalender-/Listen-Ansicht',
+ 'Switch to the board view' => 'Zur Board-Ansicht',
+ 'Switch to the calendar view' => 'Zur Kalender-Ansicht',
+ 'Switch to the list view' => 'Zur Listen-Ansicht',
+ 'Go to the search/filter box' => 'Zum Such- und Filterfeld',
+ 'There is no activity yet.' => 'Es gibt bislang keine Aktivitäten.',
+ 'No tasks found.' => 'Keine Aufgaben gefunden.',
+ 'Keyboard shortcut: "%s"' => 'Tastaturkürzel: "%s"',
+ 'List' => 'Liste',
+ 'Filter' => 'Filter',
+ 'Advanced search' => 'Fortgeschrittene Suche',
+ 'Example of query: ' => 'Beispiel einer Abfrage: ',
+ 'Search by project: ' => 'Suche nach Projekt: ',
+ 'Search by column: ' => 'Suche nach Spalte: ',
+ 'Search by assignee: ' => 'Suche nach zugeordnetem Benutzer: ',
+ 'Search by color: ' => 'Suche nach Farbe: ',
+ 'Search by category: ' => 'Suche nach Kategorie: ',
+ 'Search by description: ' => 'Suche nach Beschreibung: ',
+ 'Search by due date: ' => 'Suche nach Fälligkeitsdatum: ',
+ // 'Lead and Cycle time for "%s"' => '',
+ // 'Average time spent into each column for "%s"' => '',
+ // 'Average time spent into each column' => '',
+ // 'Average time spent' => '',
+ // 'This chart show the average time spent into each column for the last %d tasks.' => '',
+ // 'Average Lead and Cycle time' => '',
+ // 'Average lead time: ' => '',
+ // 'Average cycle time: ' => '',
+ // 'Cycle Time' => '',
+ // 'Lead Time' => '',
+ // 'This chart show the average lead and cycle time for the last %d tasks over the time.' => '',
+ // 'Average time into each column' => '',
+ // 'Lead and cycle time' => '',
+ // 'Google Authentication' => '',
+ // 'Help on Google authentication' => '',
+ // 'Github Authentication' => '',
+ // 'Help on Github authentication' => '',
+ // 'Channel/Group/User (Optional)' => '',
+ // 'Lead time: ' => '',
+ // 'Cycle time: ' => '',
+ // 'Time spent into each column' => '',
+ // 'The lead time is the duration between the task creation and the completion.' => '',
+ // 'The cycle time is the duration between the start date and the completion.' => '',
+ // 'If the task is not closed the current time is used instead of the completion date.' => '',
+ // 'Set automatically the start date' => '',
+ // 'Edit Authentication' => '',
+ // 'Google Id' => '',
+ // 'Github Id' => '',
+ // 'Remote user' => '',
+ // 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '',
+ // 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '',
+ // 'By @%s on Gitlab' => '',
+ // 'Gitlab issue comment created' => '',
+ // 'New remote user' => '',
+ // 'New local user' => '',
);
diff --git a/app/Locale/es_ES/translations.php b/app/Locale/es_ES/translations.php
index 36259a8a..ecaf8a23 100644
--- a/app/Locale/es_ES/translations.php
+++ b/app/Locale/es_ES/translations.php
@@ -126,7 +126,6 @@ return array(
'The project name is required' => 'El nombre del proyecto es obligatorio',
'This project must be unique' => 'El nombre del proyecto debe ser único',
'The title is required' => 'El titulo es obligatorio',
- 'There is no active project, the first step is to create a new project.' => 'No hay proyectos activados, la primera etapa consiste en crear un nuevo proyecto.',
'Settings saved successfully.' => 'Parámetros guardados correctamente.',
'Unable to save your settings.' => 'No se pueden guardar sus parámetros.',
'Database optimization done.' => 'Optimización de la base de datos terminada.',
@@ -264,11 +263,10 @@ return array(
'%d comments' => '%d comentarios',
'%d comment' => '%d comentario',
'Email address invalid' => 'Dirección de correo inválida',
- 'Your Google Account is not linked anymore to your profile.' => 'Tu Cuenta en Google ya no se encuentra vinculada con tu perfil',
- 'Unable to unlink your Google Account.' => 'No puedo desvincular tu Cuenta en Google.',
- 'Google authentication failed' => 'Ha fallado tu autenticación en Google',
- 'Unable to link your Google Account.' => 'No puedo vincular con tu Cuenta en Google.',
- 'Your Google Account is linked to your profile successfully.' => 'Se ha vinculado correctamente tu Cuenta en Google con tu perfil.',
+ // 'Your external account is not linked anymore to your profile.' => '',
+ // 'Unable to unlink your external account.' => '',
+ // 'External authentication failed' => '',
+ // 'Your external account is linked to your profile successfully.' => '',
'Email' => 'Correo',
'Link my Google Account' => 'Vincular con mi Cuenta en Google',
'Unlink my Google Account' => 'Desvincular de mi Cuenta en Google',
@@ -338,14 +336,9 @@ return array(
'Maximum size: ' => 'Tamaño máximo',
'Unable to upload the file.' => 'No pude cargar el fichero.',
'Display another project' => 'Mostrar otro proyecto',
- 'Your GitHub account was successfully linked to your profile.' => 'Tu cuenta de GitHub ha sido correctamente vinculada con tu perfil',
- 'Unable to link your GitHub Account.' => 'Imposible vincular tu cuenta de GitHub',
- 'GitHub authentication failed' => 'Falló la autenticación de GitHub',
- 'Your GitHub account is no longer linked to your profile.' => 'Tu cuenta de GitHub ya no está vinculada a tu perfil',
- 'Unable to unlink your GitHub Account.' => 'Imposible desvincular tu cuenta de GitHub',
- 'Login with my GitHub Account' => 'Ingresar con mi cuenta de GitHub',
- 'Link my GitHub Account' => 'Vincular mi cuenta de GitHub',
- 'Unlink my GitHub Account' => 'Desvincular mi cuenta de GitHub',
+ 'Login with my Github Account' => 'Ingresar con mi cuenta de Github',
+ 'Link my Github Account' => 'Vincular mi cuenta de Github',
+ 'Unlink my Github Account' => 'Desvincular mi cuenta de Github',
'Created by %s' => 'Creado por %s',
'Last modified on %B %e, %Y at %k:%M %p' => 'Última modificación %B %e, %Y a las %k:%M %p',
'Tasks Export' => 'Exportar tareas',
@@ -615,8 +608,7 @@ return array(
'Time Tracking' => 'Seguimiento Temporal',
'You already have one subtask in progress' => 'Ya dispones de una subtarea en progreso',
'Which parts of the project do you want to duplicate?' => '¿Qué partes del proyecto deseas duplicar?',
- 'Disable login form' => 'Desactivar formulario de ingreso',
- 'Show/hide calendar' => 'Mostrar/ocultar calendario',
+ // 'Disallow login form' => '',
'Bitbucket commit received' => 'Recibida envío desde Bitbucket',
'Bitbucket webhooks' => 'Disparadores Web (webhooks) de Bitbucket',
'Help on Bitbucket webhooks' => 'Ayuda sobre disparadores web (webhooks) de Bitbucket',
@@ -971,4 +963,39 @@ return array(
// 'Search by category: ' => '',
// 'Search by description: ' => '',
// 'Search by due date: ' => '',
+ // 'Lead and Cycle time for "%s"' => '',
+ // 'Average time spent into each column for "%s"' => '',
+ // 'Average time spent into each column' => '',
+ // 'Average time spent' => '',
+ // 'This chart show the average time spent into each column for the last %d tasks.' => '',
+ // 'Average Lead and Cycle time' => '',
+ // 'Average lead time: ' => '',
+ // 'Average cycle time: ' => '',
+ // 'Cycle Time' => '',
+ // 'Lead Time' => '',
+ // 'This chart show the average lead and cycle time for the last %d tasks over the time.' => '',
+ // 'Average time into each column' => '',
+ // 'Lead and cycle time' => '',
+ // 'Google Authentication' => '',
+ // 'Help on Google authentication' => '',
+ // 'Github Authentication' => '',
+ // 'Help on Github authentication' => '',
+ // 'Channel/Group/User (Optional)' => '',
+ // 'Lead time: ' => '',
+ // 'Cycle time: ' => '',
+ // 'Time spent into each column' => '',
+ // 'The lead time is the duration between the task creation and the completion.' => '',
+ // 'The cycle time is the duration between the start date and the completion.' => '',
+ // 'If the task is not closed the current time is used instead of the completion date.' => '',
+ // 'Set automatically the start date' => '',
+ // 'Edit Authentication' => '',
+ // 'Google Id' => '',
+ // 'Github Id' => '',
+ // 'Remote user' => '',
+ // 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '',
+ // 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '',
+ // 'By @%s on Gitlab' => '',
+ // 'Gitlab issue comment created' => '',
+ // 'New remote user' => '',
+ // 'New local user' => '',
);
diff --git a/app/Locale/fi_FI/translations.php b/app/Locale/fi_FI/translations.php
index beb61d96..ddbb26c3 100644
--- a/app/Locale/fi_FI/translations.php
+++ b/app/Locale/fi_FI/translations.php
@@ -126,7 +126,6 @@ return array(
'The project name is required' => 'Projektin nimi on pakollinen',
'This project must be unique' => 'Projektin nimi täytyy olla uniikki',
'The title is required' => 'Otsikko vaaditaan',
- 'There is no active project, the first step is to create a new project.' => 'Aktiivista projektia ei ole, ensimmäinen vaihe on luoda uusi projekti.',
'Settings saved successfully.' => 'Asetukset tallennettu onnistuneesti.',
'Unable to save your settings.' => 'Asetusten tallentaminen epäonnistui.',
'Database optimization done.' => 'Tietokannan optimointi suoritettu.',
@@ -264,11 +263,10 @@ return array(
'%d comments' => '%d kommenttia',
'%d comment' => '%d kommentti',
'Email address invalid' => 'Email ei kelpaa',
- 'Your Google Account is not linked anymore to your profile.' => 'Google tunnustasi ei ole enää linkattu profiiliisi',
- 'Unable to unlink your Google Account.' => 'Google tunnuksen linkkaamisen poistaminen epäonnistui.',
- 'Google authentication failed' => 'Google autentikointi epäonnistui',
- 'Unable to link your Google Account.' => 'Google tunnuksen linkkaaminen epäonnistui.',
- 'Your Google Account is linked to your profile successfully.' => 'Google tunnuksesi linkitettiin profiiliisi onnistuneesti.',
+ // 'Your external account is not linked anymore to your profile.' => '',
+ // 'Unable to unlink your external account.' => '',
+ // 'External authentication failed' => '',
+ // 'Your external account is linked to your profile successfully.' => '',
'Email' => 'Sähköposti',
'Link my Google Account' => 'Linkitä Google-tili',
'Unlink my Google Account' => 'Poista Google-tilin linkitys',
@@ -338,14 +336,9 @@ return array(
'Maximum size: ' => 'Maksimikoko: ',
'Unable to upload the file.' => 'Tiedoston lataus epäonnistui.',
'Display another project' => 'Näytä toinen projekti',
- 'Your GitHub account was successfully linked to your profile.' => 'Github-tilisi on onnistuneesti liitetty profiiliisi',
- 'Unable to link your GitHub Account.' => 'Github-tilin liittäminen epäonnistui',
- 'GitHub authentication failed' => 'Github-todennus epäonnistui',
- 'Your GitHub account is no longer linked to your profile.' => 'Github-tiliäsi ei ole enää liitetty profiiliisi.',
- 'Unable to unlink your GitHub Account.' => 'Github-tilisi liitoksen poisto epäonnistui',
- 'Login with my GitHub Account' => 'Kirjaudu sisään Github-tililläni',
- 'Link my GitHub Account' => 'Liitä Github-tilini',
- 'Unlink my GitHub Account' => 'Poista liitos Github-tiliini',
+ 'Login with my Github Account' => 'Kirjaudu sisään Github-tililläni',
+ 'Link my Github Account' => 'Liitä Github-tilini',
+ 'Unlink my Github Account' => 'Poista liitos Github-tiliini',
'Created by %s' => 'Luonut: %s',
'Last modified on %B %e, %Y at %k:%M %p' => 'Viimeksi muokattu %B %e, %Y kello %H:%M',
'Tasks Export' => 'Tehtävien vienti',
@@ -615,8 +608,7 @@ return array(
// 'Time Tracking' => '',
// 'You already have one subtask in progress' => '',
// 'Which parts of the project do you want to duplicate?' => '',
- // 'Disable login form' => '',
- // 'Show/hide calendar' => '',
+ // 'Disallow login form' => '',
// 'Bitbucket commit received' => '',
// 'Bitbucket webhooks' => '',
// 'Help on Bitbucket webhooks' => '',
@@ -971,4 +963,39 @@ return array(
// 'Search by category: ' => '',
// 'Search by description: ' => '',
// 'Search by due date: ' => '',
+ // 'Lead and Cycle time for "%s"' => '',
+ // 'Average time spent into each column for "%s"' => '',
+ // 'Average time spent into each column' => '',
+ // 'Average time spent' => '',
+ // 'This chart show the average time spent into each column for the last %d tasks.' => '',
+ // 'Average Lead and Cycle time' => '',
+ // 'Average lead time: ' => '',
+ // 'Average cycle time: ' => '',
+ // 'Cycle Time' => '',
+ // 'Lead Time' => '',
+ // 'This chart show the average lead and cycle time for the last %d tasks over the time.' => '',
+ // 'Average time into each column' => '',
+ // 'Lead and cycle time' => '',
+ // 'Google Authentication' => '',
+ // 'Help on Google authentication' => '',
+ // 'Github Authentication' => '',
+ // 'Help on Github authentication' => '',
+ // 'Channel/Group/User (Optional)' => '',
+ // 'Lead time: ' => '',
+ // 'Cycle time: ' => '',
+ // 'Time spent into each column' => '',
+ // 'The lead time is the duration between the task creation and the completion.' => '',
+ // 'The cycle time is the duration between the start date and the completion.' => '',
+ // 'If the task is not closed the current time is used instead of the completion date.' => '',
+ // 'Set automatically the start date' => '',
+ // 'Edit Authentication' => '',
+ // 'Google Id' => '',
+ // 'Github Id' => '',
+ // 'Remote user' => '',
+ // 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '',
+ // 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '',
+ // 'By @%s on Gitlab' => '',
+ // 'Gitlab issue comment created' => '',
+ // 'New remote user' => '',
+ // 'New local user' => '',
);
diff --git a/app/Locale/fr_FR/translations.php b/app/Locale/fr_FR/translations.php
index 34839a12..1c4c76ee 100644
--- a/app/Locale/fr_FR/translations.php
+++ b/app/Locale/fr_FR/translations.php
@@ -126,7 +126,6 @@ return array(
'The project name is required' => 'Le nom du projet est obligatoire',
'This project must be unique' => 'Le nom du projet doit être unique',
'The title is required' => 'Le titre est obligatoire',
- 'There is no active project, the first step is to create a new project.' => 'Il n\'y a aucun projet actif, la première étape est de créer un nouveau projet.',
'Settings saved successfully.' => 'Paramètres sauvegardés avec succès.',
'Unable to save your settings.' => 'Impossible de sauvegarder vos réglages.',
'Database optimization done.' => 'Optmisation de la base de données terminée.',
@@ -264,11 +263,10 @@ return array(
'%d comments' => '%d commentaires',
'%d comment' => '%d commentaire',
'Email address invalid' => 'Adresse email invalide',
- 'Your Google Account is not linked anymore to your profile.' => 'Votre compte Google n\'est plus relié à votre profile.',
- 'Unable to unlink your Google Account.' => 'Impossible de supprimer votre compte Google.',
- 'Google authentication failed' => 'Authentification Google échouée',
- 'Unable to link your Google Account.' => 'Impossible de lier votre compte Google.',
- 'Your Google Account is linked to your profile successfully.' => 'Votre compte Google est désormais lié à votre profile.',
+ 'Your external account is not linked anymore to your profile.' => 'Votre compte externe n\'est plus relié à votre profile.',
+ 'Unable to unlink your external account.' => 'Impossible de supprimer votre compte externe.',
+ 'External authentication failed' => 'Authentification externe échouée',
+ 'Your external account is linked to your profile successfully.' => 'Votre compte externe est désormais lié à votre profile.',
'Email' => 'Email',
'Link my Google Account' => 'Lier mon compte Google',
'Unlink my Google Account' => 'Ne plus utiliser mon compte Google',
@@ -338,14 +336,9 @@ return array(
'Maximum size: ' => 'Taille maximum : ',
'Unable to upload the file.' => 'Impossible de transférer le fichier.',
'Display another project' => 'Afficher un autre projet',
- 'Your GitHub account was successfully linked to your profile.' => 'Votre compte Github est désormais lié avec votre profile.',
- 'Unable to link your GitHub Account.' => 'Impossible de lier votre compte Github.',
- 'GitHub authentication failed' => 'L\'authentification avec Github à échouée',
- 'Your GitHub account is no longer linked to your profile.' => 'Votre compte Github n\'est plus relié avec votre profile.',
- 'Unable to unlink your GitHub Account.' => 'Impossible de déconnecter votre compte Github.',
- 'Login with my GitHub Account' => 'Se connecter avec mon compte Github',
- 'Link my GitHub Account' => 'Lier mon compte Github',
- 'Unlink my GitHub Account' => 'Ne plus utiliser mon compte Github',
+ 'Login with my Github Account' => 'Se connecter avec mon compte Github',
+ 'Link my Github Account' => 'Lier mon compte Github',
+ 'Unlink my Github Account' => 'Ne plus utiliser mon compte Github',
'Created by %s' => 'Créé par %s',
'Last modified on %B %e, %Y at %k:%M %p' => 'Modifié le %d/%m/%Y à %H:%M',
'Tasks Export' => 'Exportation des tâches',
@@ -617,8 +610,7 @@ return array(
'Time Tracking' => 'Feuille de temps',
'You already have one subtask in progress' => 'Vous avez déjà une sous-tâche en progrès',
'Which parts of the project do you want to duplicate?' => 'Quelles parties du projet voulez-vous dupliquer ?',
- 'Disable login form' => 'Désactiver le formulaire d\'authentification',
- 'Show/hide calendar' => 'Afficher/cacher le calendrier',
+ 'Disallow login form' => 'Interdir le formulaire d\'authentification',
'Bitbucket commit received' => 'Commit reçu via Bitbucket',
'Bitbucket webhooks' => 'Webhook Bitbucket',
'Help on Bitbucket webhooks' => 'Aide sur les webhooks Bitbucket',
@@ -899,7 +891,7 @@ return array(
'This report contains all subtasks information for the given date range.' => 'Ce rapport contient les informations de toutes les sous-tâches pour la période selectionnée.',
'This report contains all tasks information for the given date range.' => 'Ce rapport contient les informations de toutes les tâches pour la période selectionnée.',
'Project activities for %s' => 'Activité des projets pour « %s »',
- 'view the board on Kanboard' => 'voir la tableau sur Kanboard',
+ 'view the board on Kanboard' => 'voir le tableau sur Kanboard',
'The task have been moved to the first swimlane' => 'La tâche a été déplacée dans la première swimlane',
'The task have been moved to another swimlane:' => 'La tâche a été déplacée dans une autre swimlane :',
'Overdue tasks for the project "%s"' => 'Tâches en retard pour le projet « %s »',
@@ -966,11 +958,46 @@ return array(
'Filter' => 'Filtre',
'Advanced search' => 'Recherche avancée',
'Example of query: ' => 'Exemple de requête : ',
- 'Search by project: ' => 'Rechercher par project : ',
+ 'Search by project: ' => 'Rechercher par projet : ',
'Search by column: ' => 'Rechercher par colonne : ',
'Search by assignee: ' => 'Rechercher par assigné : ',
'Search by color: ' => 'Rechercher par couleur : ',
'Search by category: ' => 'Rechercher par catégorie : ',
'Search by description: ' => 'Rechercher par description : ',
'Search by due date: ' => 'Rechercher par date d\'échéance : ',
+ 'Lead and Cycle time for "%s"' => 'Lead et cycle time pour « %s »',
+ 'Average time spent into each column for "%s"' => 'Temps passé moyen dans chaque colonne pour « %s »',
+ 'Average time spent into each column' => 'Temps moyen passé dans chaque colonne',
+ 'Average time spent' => 'Temps moyen passé',
+ 'This chart show the average time spent into each column for the last %d tasks.' => 'Ce graphique montre le temps passé moyen dans chaque colonne pour les %d dernières tâches.',
+ 'Average Lead and Cycle time' => 'Durée moyenne du lead et cycle time',
+ 'Average lead time: ' => 'Lead time moyen : ',
+ 'Average cycle time: ' => 'Cycle time moyen : ',
+ 'Cycle Time' => 'Cycle time',
+ 'Lead Time' => 'Lead time',
+ 'This chart show the average lead and cycle time for the last %d tasks over the time.' => 'Ce graphique montre la durée moyenne du lead et cycle time pour les %d dernières tâches.',
+ 'Average time into each column' => 'Temps moyen dans chaque colonne',
+ 'Lead and cycle time' => 'Lead et cycle time',
+ 'Google Authentication' => 'Authentification Google',
+ 'Help on Google authentication' => 'Aide sur l\'authentification Google',
+ 'Github Authentication' => 'Authentification Github',
+ 'Help on Github authentication' => 'Aide sur l\'authentification Github',
+ 'Channel/Group/User (Optional)' => 'Cannal/Groupe/Utilisateur (Optionnel)',
+ 'Lead time: ' => 'Lead time : ',
+ 'Cycle time: ' => 'Temps de cycle : ',
+ 'Time spent into each column' => 'Temps passé dans chaque colonne',
+ 'The lead time is the duration between the task creation and the completion.' => 'Le lead time est la durée entre la création de la tâche et sa complétion.',
+ 'The cycle time is the duration between the start date and the completion.' => 'Le cycle time est la durée entre la date de début et la complétion.',
+ 'If the task is not closed the current time is used instead of the completion date.' => 'Si la tâche n\'est pas fermée, l\'heure courante est utilisée à la place de la date de complétion.',
+ 'Set automatically the start date' => 'Définir automatiquement la date de début',
+ 'Edit Authentication' => 'Modifier l\'authentification',
+ 'Google Id' => 'Identifiant Google',
+ 'Github Id' => 'Identifiant Github',
+ 'Remote user' => 'Utilisateur distant',
+ 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => 'Les utilisateurs distants ne stockent pas leur mot de passe dans la base de données de Kanboard, exemples : comptes LDAP, Github ou Google.',
+ 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => 'Si vous cochez la case « Interdir le formulaire d\'authentification », les identifiants entrés dans le formulaire d\'authentification seront ignorés.',
+ 'By @%s on Gitlab' => 'Par @%s sur Gitlab',
+ 'Gitlab issue comment created' => 'Commentaire créé sur un ticket Gitlab',
+ 'New remote user' => 'Créer un utilisateur distant',
+ 'New local user' => 'Créer un utilisateur local',
);
diff --git a/app/Locale/hu_HU/translations.php b/app/Locale/hu_HU/translations.php
index 73215f89..f1bd1453 100644
--- a/app/Locale/hu_HU/translations.php
+++ b/app/Locale/hu_HU/translations.php
@@ -126,7 +126,6 @@ return array(
'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',
- '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.' => 'A beállítások mentése sikertelen.',
'Database optimization done.' => 'Adatbázis optimalizálás kész.',
@@ -264,11 +263,10 @@ return array(
'%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.' => 'A Google profilhoz kapcsolás sikertelen.',
- 'Your Google Account is linked to your profile successfully.' => 'Google fiókkal sikeresen összekapcsolva.',
+ // 'Your external account is not linked anymore to your profile.' => '',
+ // 'Unable to unlink your external account.' => '',
+ // 'External authentication failed' => '',
+ // 'Your external account is linked to your profile successfully.' => '',
'Email' => 'E-mail',
'Link my Google Account' => 'Kapcsold össze a Google fiókkal',
'Unlink my Google Account' => 'Válaszd le a Google fiókomat',
@@ -338,14 +336,9 @@ return array(
'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',
+ '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',
@@ -403,7 +396,7 @@ return array(
'Enabled' => 'Engedélyezve',
'Disabled' => 'Letiltva',
'Google account linked' => 'Google fiók összekapcsolva',
- 'Github account linked' => 'GitHub fiók összekapcsolva',
+ 'Github account linked' => 'Github fiók összekapcsolva',
'Username:' => 'Felhasználónév:',
'Name:' => 'Név:',
'Email:' => 'E-mail:',
@@ -458,12 +451,12 @@ return array(
'%s changed the assignee of the task %s to %s' => '%s a felelőst %s módosította: %s',
'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 nyitás',
- 'Github issue closed' => 'GitHub issue zárás',
- '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',
+ 'Github commit received' => 'Github commit érkezett',
+ 'Github issue opened' => 'Github issue nyitás',
+ 'Github issue closed' => 'Github issue zárás',
+ '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',
@@ -615,8 +608,7 @@ return array(
'Time Tracking' => 'Idő követés',
'You already have one subtask in progress' => 'Már van egy folyamatban levő részfeladata',
'Which parts of the project do you want to duplicate?' => 'A projekt mely részeit szeretné másolni?',
- 'Disable login form' => 'Bejelentkező képernyő tiltása',
- 'Show/hide calendar' => 'Naptár megjelenítés/elrejtés',
+ // 'Disallow login form' => '',
'Bitbucket commit received' => 'Bitbucket commit érkezett',
'Bitbucket webhooks' => 'Bitbucket webhooks',
'Help on Bitbucket webhooks' => 'Bitbucket webhooks súgó',
@@ -971,4 +963,39 @@ return array(
// 'Search by category: ' => '',
// 'Search by description: ' => '',
// 'Search by due date: ' => '',
+ // 'Lead and Cycle time for "%s"' => '',
+ // 'Average time spent into each column for "%s"' => '',
+ // 'Average time spent into each column' => '',
+ // 'Average time spent' => '',
+ // 'This chart show the average time spent into each column for the last %d tasks.' => '',
+ // 'Average Lead and Cycle time' => '',
+ // 'Average lead time: ' => '',
+ // 'Average cycle time: ' => '',
+ // 'Cycle Time' => '',
+ // 'Lead Time' => '',
+ // 'This chart show the average lead and cycle time for the last %d tasks over the time.' => '',
+ // 'Average time into each column' => '',
+ // 'Lead and cycle time' => '',
+ // 'Google Authentication' => '',
+ // 'Help on Google authentication' => '',
+ // 'Github Authentication' => '',
+ // 'Help on Github authentication' => '',
+ // 'Channel/Group/User (Optional)' => '',
+ // 'Lead time: ' => '',
+ // 'Cycle time: ' => '',
+ // 'Time spent into each column' => '',
+ // 'The lead time is the duration between the task creation and the completion.' => '',
+ // 'The cycle time is the duration between the start date and the completion.' => '',
+ // 'If the task is not closed the current time is used instead of the completion date.' => '',
+ // 'Set automatically the start date' => '',
+ // 'Edit Authentication' => '',
+ // 'Google Id' => '',
+ // 'Github Id' => '',
+ // 'Remote user' => '',
+ // 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '',
+ // 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '',
+ // 'By @%s on Gitlab' => '',
+ // 'Gitlab issue comment created' => '',
+ // 'New remote user' => '',
+ // 'New local user' => '',
);
diff --git a/app/Locale/it_IT/translations.php b/app/Locale/it_IT/translations.php
index 0fe5547b..6dd60c18 100644
--- a/app/Locale/it_IT/translations.php
+++ b/app/Locale/it_IT/translations.php
@@ -126,7 +126,6 @@ return array(
'The project name is required' => 'Si richiede il nome del progetto',
'This project must be unique' => 'Il nome del progetto deve essere unico',
'The title is required' => 'Si richiede un titolo',
- 'There is no active project, the first step is to create a new project.' => 'Non ci sono progetti attivi, il primo passo consiste in creare un nuovo progetto.',
'Settings saved successfully.' => 'Impostazioni salvate correttamente.',
'Unable to save your settings.' => 'Non si possono salvare le impostazioni.',
'Database optimization done.' => 'Ottimizzazione della base dati conclusa.',
@@ -264,11 +263,10 @@ return array(
'%d comments' => '%d commenti',
'%d comment' => '%d commento',
'Email address invalid' => 'Indirizzo e-mail sbagliato',
- 'Your Google Account is not linked anymore to your profile.' => 'Il suo account Google non è più collegato al suo profilo',
- 'Unable to unlink your Google Account.' => 'Non si può svincolare l\'account di Google.',
- 'Google authentication failed' => 'Autenticazione con Google non riuscita',
- 'Unable to link your Google Account.' => 'Non si può collegare il tuo account di Google.',
- 'Your Google Account is linked to your profile successfully.' => 'Il tuo account di Google è stato collegato correttamente al tuo profilo.',
+ // 'Your external account is not linked anymore to your profile.' => '',
+ // 'Unable to unlink your external account.' => '',
+ // 'External authentication failed' => '',
+ // 'Your external account is linked to your profile successfully.' => '',
'Email' => 'E-mail',
'Link my Google Account' => 'Collegare il mio Account di Google',
'Unlink my Google Account' => 'Scollegare il mio account di Google',
@@ -338,14 +336,9 @@ return array(
'Maximum size: ' => 'Dimensioni massime',
'Unable to upload the file.' => 'Non si può caricare il file.',
'Display another project' => 'Mostrare un altro progetto',
- 'Your GitHub account was successfully linked to your profile.' => 'Il suo account di Github è stato collegato correttamente col tuo profilo.',
- 'Unable to link your GitHub Account.' => 'Non si può collegarre il tuo account di Github.',
- 'GitHub authentication failed' => 'Autenticazione con GitHub non riuscita',
- 'Your GitHub account is no longer linked to your profile.' => 'Il tuo account di Github non è più collegato al tuo profilo.',
- 'Unable to unlink your GitHub Account.' => 'Non si può collegare il tuo account di Github.',
- 'Login with my GitHub Account' => 'Entrare col tuo account di Github',
- 'Link my GitHub Account' => 'Collegare il mio account Github',
- 'Unlink my GitHub Account' => 'Scollegare il mio account di Github',
+ 'Login with my Github Account' => 'Entrare col tuo account di Github',
+ 'Link my Github Account' => 'Collegare il mio account Github',
+ 'Unlink my Github Account' => 'Scollegare il mio account di Github',
'Created by %s' => 'Creato da %s',
'Last modified on %B %e, %Y at %k:%M %p' => 'Ultima modifica il %d/%m/%Y alle %H:%M',
'Tasks Export' => 'Esportazione di compiti',
@@ -615,8 +608,7 @@ return array(
'Time Tracking' => 'Gestione del tempo',
'You already have one subtask in progress' => 'Hai già un sotto-compito in progresso',
'Which parts of the project do you want to duplicate?' => 'Quali parti del progetto vuoi duplicare?',
- 'Disable login form' => 'Disabilita form di login',
- 'Show/hide calendar' => 'Mostra/nascondi calendario',
+ // 'Disallow login form' => '',
'Bitbucket commit received' => 'Commit ricevuto da Bitbucket',
'Bitbucket webhooks' => 'Webhooks di Bitbucket',
'Help on Bitbucket webhooks' => 'Guida ai Webhooks di Bitbucket',
@@ -971,4 +963,39 @@ return array(
// 'Search by category: ' => '',
// 'Search by description: ' => '',
// 'Search by due date: ' => '',
+ // 'Lead and Cycle time for "%s"' => '',
+ // 'Average time spent into each column for "%s"' => '',
+ // 'Average time spent into each column' => '',
+ // 'Average time spent' => '',
+ // 'This chart show the average time spent into each column for the last %d tasks.' => '',
+ // 'Average Lead and Cycle time' => '',
+ // 'Average lead time: ' => '',
+ // 'Average cycle time: ' => '',
+ // 'Cycle Time' => '',
+ // 'Lead Time' => '',
+ // 'This chart show the average lead and cycle time for the last %d tasks over the time.' => '',
+ // 'Average time into each column' => '',
+ // 'Lead and cycle time' => '',
+ // 'Google Authentication' => '',
+ // 'Help on Google authentication' => '',
+ // 'Github Authentication' => '',
+ // 'Help on Github authentication' => '',
+ // 'Channel/Group/User (Optional)' => '',
+ // 'Lead time: ' => '',
+ // 'Cycle time: ' => '',
+ // 'Time spent into each column' => '',
+ // 'The lead time is the duration between the task creation and the completion.' => '',
+ // 'The cycle time is the duration between the start date and the completion.' => '',
+ // 'If the task is not closed the current time is used instead of the completion date.' => '',
+ // 'Set automatically the start date' => '',
+ // 'Edit Authentication' => '',
+ // 'Google Id' => '',
+ // 'Github Id' => '',
+ // 'Remote user' => '',
+ // 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '',
+ // 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '',
+ // 'By @%s on Gitlab' => '',
+ // 'Gitlab issue comment created' => '',
+ // 'New remote user' => '',
+ // 'New local user' => '',
);
diff --git a/app/Locale/ja_JP/translations.php b/app/Locale/ja_JP/translations.php
index 6c9a205e..e52f82b6 100644
--- a/app/Locale/ja_JP/translations.php
+++ b/app/Locale/ja_JP/translations.php
@@ -126,7 +126,6 @@ return array(
'The project name is required' => 'プロジェクト名が必要です',
'This project must be unique' => 'プロジェクト名がすでに使われています',
'The title is required' => 'タイトルが必要です',
- 'There is no active project, the first step is to create a new project.' => '有効なプロジェクトがありません。まず新しいプロジェクトを作ります。',
'Settings saved successfully.' => '設定を保存しました。',
'Unable to save your settings.' => '設定の保存に失敗しました。',
'Database optimization done.' => 'データベースの最適化が終わりました。',
@@ -264,11 +263,10 @@ return array(
'%d comments' => '%d 個のコメント',
'%d comment' => '%d 個のコメント',
'Email address invalid' => 'メールアドレスが正しくありません',
- 'Your Google Account is not linked anymore to your profile.' => 'Google アカウントとのリンクが解除されました',
- 'Unable to unlink your Google Account.' => 'Google アカウントとのリンク解除に失敗しました',
- 'Google authentication failed' => 'Google の認証に失敗しました',
- 'Unable to link your Google Account.' => 'Google アカウントとのリンクに失敗しました。',
- 'Your Google Account is linked to your profile successfully.' => 'Google アカウントとリンクしました',
+ // 'Your external account is not linked anymore to your profile.' => '',
+ // 'Unable to unlink your external account.' => '',
+ // 'External authentication failed' => '',
+ // 'Your external account is linked to your profile successfully.' => '',
'Email' => 'Email',
'Link my Google Account' => 'Google アカウントをリンクする',
'Unlink my Google Account' => 'Google アカウントのリンクを解除する',
@@ -338,14 +336,9 @@ return array(
'Maximum size: ' => '最大: ',
'Unable to upload the file.' => 'ファイルのアップロードに失敗しました。',
'Display another project' => '別のプロジェクトを表示',
- 'Your GitHub account was successfully linked to your profile.' => 'GitHub アカウントとリンクしました。',
- 'Unable to link your GitHub Account.' => 'GitHub アカウントとリンクできませんでした。',
- 'GitHub authentication failed' => 'GitHub アカウントの認証に失敗しました。',
- 'Your GitHub account is no longer linked to your profile.' => 'GitHub アカウントへのリンクが解除されました。',
- 'Unable to unlink your GitHub Account.' => 'GitHub アカウントのリンク解除に失敗しました。',
- 'Login with my GitHub Account' => 'Github アカウントでログインする',
- 'Link my GitHub Account' => 'Github アカウントをリンクする',
- 'Unlink my GitHub Account' => 'Github アカウントとのリンクを解除する',
+ 'Login with my Github Account' => 'Github アカウントでログインする',
+ 'Link my Github Account' => 'Github アカウントをリンクする',
+ 'Unlink my Github Account' => 'Github アカウントとのリンクを解除する',
'Created by %s' => '%s が作成',
'Last modified on %B %e, %Y at %k:%M %p' => ' %Y/%m/%d %H:%M に変更',
'Tasks Export' => 'タスクの出力',
@@ -403,7 +396,7 @@ return array(
'Enabled' => '有効',
'Disabled' => '無効',
'Google account linked' => 'Google アカウントがリンク',
- 'Github account linked' => 'GitHub のアカウントがリンク',
+ 'Github account linked' => 'Github のアカウントがリンク',
'Username:' => 'ユーザ名:',
'Name:' => '名前:',
'Email:' => 'Email:',
@@ -417,7 +410,7 @@ return array(
'Password modification' => 'パスワードの変更',
'External authentications' => '外部認証',
'Google Account' => 'Google アカウント',
- 'Github Account' => 'GitHub アカウント',
+ 'Github Account' => 'Github アカウント',
'Never connected.' => '未接続。',
'No account linked.' => 'アカウントがリンクしていません。',
'Account linked.' => 'アカウントがリンクしました。',
@@ -615,8 +608,7 @@ return array(
'Time Tracking' => 'タイムトラッキング',
'You already have one subtask in progress' => 'すでに進行中のサブタスクがあります。',
'Which parts of the project do you want to duplicate?' => 'プロジェクトの何を複製しますか?',
- 'Disable login form' => 'ログインフォームの無効化',
- 'Show/hide calendar' => 'カレンダーの表示・非表示',
+ // 'Disallow login form' => '',
'Bitbucket commit received' => 'Bitbucket コミットを受信しました',
'Bitbucket webhooks' => 'Bitbucket Webhooks',
'Help on Bitbucket webhooks' => 'Bitbucket Webhooks のヘルプ',
@@ -971,4 +963,39 @@ return array(
// 'Search by category: ' => '',
// 'Search by description: ' => '',
// 'Search by due date: ' => '',
+ // 'Lead and Cycle time for "%s"' => '',
+ // 'Average time spent into each column for "%s"' => '',
+ // 'Average time spent into each column' => '',
+ // 'Average time spent' => '',
+ // 'This chart show the average time spent into each column for the last %d tasks.' => '',
+ // 'Average Lead and Cycle time' => '',
+ // 'Average lead time: ' => '',
+ // 'Average cycle time: ' => '',
+ // 'Cycle Time' => '',
+ // 'Lead Time' => '',
+ // 'This chart show the average lead and cycle time for the last %d tasks over the time.' => '',
+ // 'Average time into each column' => '',
+ // 'Lead and cycle time' => '',
+ // 'Google Authentication' => '',
+ // 'Help on Google authentication' => '',
+ // 'Github Authentication' => '',
+ // 'Help on Github authentication' => '',
+ // 'Channel/Group/User (Optional)' => '',
+ // 'Lead time: ' => '',
+ // 'Cycle time: ' => '',
+ // 'Time spent into each column' => '',
+ // 'The lead time is the duration between the task creation and the completion.' => '',
+ // 'The cycle time is the duration between the start date and the completion.' => '',
+ // 'If the task is not closed the current time is used instead of the completion date.' => '',
+ // 'Set automatically the start date' => '',
+ // 'Edit Authentication' => '',
+ // 'Google Id' => '',
+ // 'Github Id' => '',
+ // 'Remote user' => '',
+ // 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '',
+ // 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '',
+ // 'By @%s on Gitlab' => '',
+ // 'Gitlab issue comment created' => '',
+ // 'New remote user' => '',
+ // 'New local user' => '',
);
diff --git a/app/Locale/nl_NL/translations.php b/app/Locale/nl_NL/translations.php
index 7a31b975..ed8be05b 100644
--- a/app/Locale/nl_NL/translations.php
+++ b/app/Locale/nl_NL/translations.php
@@ -126,7 +126,6 @@ return array(
'The project name is required' => 'De projectnaam is verplicht',
'This project must be unique' => 'Dit project moet uniek zijn',
'The title is required' => 'De titel is verplicht',
- 'There is no active project, the first step is to create a new project.' => 'Er is geen actief project, de eerste stap is een nieuw project aanmaken.',
'Settings saved successfully.' => 'Instellingen succesvol opgeslagen.',
'Unable to save your settings.' => 'Instellingen opslaan niet gelukt.',
'Database optimization done.' => 'Database optimaliseren voltooid.',
@@ -264,11 +263,10 @@ return array(
'%d comments' => '%d commentaren',
'%d comment' => '%d commentaar',
'Email address invalid' => 'Ongeldig emailadres',
- 'Your Google Account is not linked anymore to your profile.' => 'Uw Google Account is niet meer aan uw profiel gelinkt.',
- 'Unable to unlink your Google Account.' => 'Verwijderen link met Google Account niet gelukt.',
- 'Google authentication failed' => 'Google authenticatie niet gelukt',
- 'Unable to link your Google Account.' => 'Linken met Google Account niet gelukt',
- 'Your Google Account is linked to your profile successfully.' => 'Linken met Google Account succesvol.',
+ // 'Your external account is not linked anymore to your profile.' => '',
+ // 'Unable to unlink your external account.' => '',
+ // 'External authentication failed' => '',
+ // 'Your external account is linked to your profile successfully.' => '',
'Email' => 'Email',
'Link my Google Account' => 'Link mijn Google Account',
'Unlink my Google Account' => 'Link met Google Account verwijderen',
@@ -338,14 +336,9 @@ return array(
'Maximum size: ' => 'Maximale grootte : ',
'Unable to upload the file.' => 'Uploaden van bestand niet gelukt.',
'Display another project' => 'Een ander project weergeven',
- 'Your GitHub account was successfully linked to your profile.' => 'Uw Github Account is succesvol gelinkt aan uw profiel.',
- 'Unable to link your GitHub Account.' => 'Linken van uw Github Account niet gelukt.',
- 'GitHub authentication failed' => 'Github Authenticatie niet gelukt',
- 'Your GitHub account is no longer linked to your profile.' => 'Uw Github Account is niet langer gelinkt aan uw profiel.',
- 'Unable to unlink your GitHub Account.' => 'Verwijdern van de link met uw Github Account niet gelukt.',
- 'Login with my GitHub Account' => 'Login met mijn Github Account',
- 'Link my GitHub Account' => 'Link met mijn Github',
- 'Unlink my GitHub Account' => 'Link met mijn Github verwijderen',
+ 'Login with my Github Account' => 'Login met mijn Github Account',
+ 'Link my Github Account' => 'Link met mijn Github',
+ 'Unlink my Github Account' => 'Link met mijn Github verwijderen',
'Created by %s' => 'Aangemaakt door %s',
'Last modified on %B %e, %Y at %k:%M %p' => 'Laatst gewijzigd op %d/%m/%Y à %H:%M',
'Tasks Export' => 'Taken exporteren',
@@ -615,8 +608,7 @@ return array(
'Time Tracking' => 'Tijdschrijven',
'You already have one subtask in progress' => 'U heeft al een subtaak in behandeling',
'Which parts of the project do you want to duplicate?' => 'Welke onderdelen van het project wilt u dupliceren?',
- 'Disable login form' => 'Schakel login scherm uit',
- 'Show/hide calendar' => 'Toon/verberg agenda',
+ // 'Disallow login form' => '',
'Bitbucket commit received' => 'Bitbucket commit ontvangen',
'Bitbucket webhooks' => 'Bitbucket webhooks',
'Help on Bitbucket webhooks' => 'Help bij Bitbucket webhooks',
@@ -971,4 +963,39 @@ return array(
// 'Search by category: ' => '',
// 'Search by description: ' => '',
// 'Search by due date: ' => '',
+ // 'Lead and Cycle time for "%s"' => '',
+ // 'Average time spent into each column for "%s"' => '',
+ // 'Average time spent into each column' => '',
+ // 'Average time spent' => '',
+ // 'This chart show the average time spent into each column for the last %d tasks.' => '',
+ // 'Average Lead and Cycle time' => '',
+ // 'Average lead time: ' => '',
+ // 'Average cycle time: ' => '',
+ // 'Cycle Time' => '',
+ // 'Lead Time' => '',
+ // 'This chart show the average lead and cycle time for the last %d tasks over the time.' => '',
+ // 'Average time into each column' => '',
+ // 'Lead and cycle time' => '',
+ // 'Google Authentication' => '',
+ // 'Help on Google authentication' => '',
+ // 'Github Authentication' => '',
+ // 'Help on Github authentication' => '',
+ // 'Channel/Group/User (Optional)' => '',
+ // 'Lead time: ' => '',
+ // 'Cycle time: ' => '',
+ // 'Time spent into each column' => '',
+ // 'The lead time is the duration between the task creation and the completion.' => '',
+ // 'The cycle time is the duration between the start date and the completion.' => '',
+ // 'If the task is not closed the current time is used instead of the completion date.' => '',
+ // 'Set automatically the start date' => '',
+ // 'Edit Authentication' => '',
+ // 'Google Id' => '',
+ // 'Github Id' => '',
+ // 'Remote user' => '',
+ // 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '',
+ // 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '',
+ // 'By @%s on Gitlab' => '',
+ // 'Gitlab issue comment created' => '',
+ // 'New remote user' => '',
+ // 'New local user' => '',
);
diff --git a/app/Locale/pl_PL/translations.php b/app/Locale/pl_PL/translations.php
index 637eefb4..9f8641a0 100644
--- a/app/Locale/pl_PL/translations.php
+++ b/app/Locale/pl_PL/translations.php
@@ -126,7 +126,6 @@ return array(
'The project name is required' => 'Nazwa projektu jest wymagana',
'This project must be unique' => 'Projekt musi być unikalny',
'The title is required' => 'Tutył jest wymagany',
- 'There is no active project, the first step is to create a new project.' => 'Brak aktywnych projektów. Pierwszym krokiem jest utworzenie nowego projektu.',
'Settings saved successfully.' => 'Ustawienia zapisane.',
'Unable to save your settings.' => 'Nie udało się zapisać ustawień.',
'Database optimization done.' => 'Optymalizacja bazy danych zakończona.',
@@ -264,11 +263,10 @@ return array(
'%d comments' => '%d Komentarzy',
'%d comment' => '%d Komentarz',
'Email address invalid' => 'Błędny adres email',
- 'Your Google Account is not linked anymore to your profile.' => 'Twoje konto Google nie jest już połączone',
- 'Unable to unlink your Google Account.' => 'Nie można odłączyć konta Google',
- 'Google authentication failed' => 'Autentykacja Google nieudana',
- 'Unable to link your Google Account.' => 'Nie można podłączyć konta Google',
- 'Your Google Account is linked to your profile successfully.' => 'Podłączanie konta Google ukończone pomyślnie',
+ // 'Your external account is not linked anymore to your profile.' => '',
+ // 'Unable to unlink your external account.' => '',
+ // 'External authentication failed' => '',
+ // 'Your external account is linked to your profile successfully.' => '',
'Email' => 'Email',
'Link my Google Account' => 'Połącz z kontem Google',
'Unlink my Google Account' => 'Rozłącz z kontem Google',
@@ -338,14 +336,9 @@ return array(
'Maximum size: ' => 'Maksymalny rozmiar: ',
'Unable to upload the file.' => 'Nie można wczytać pliku.',
'Display another project' => 'Wyświetl inny projekt',
- 'Your GitHub account was successfully linked to your profile.' => 'Konto Github podłączone pomyślnie.',
- 'Unable to link your GitHub Account.' => 'Nie można połączyć z kontem Github.',
- 'GitHub authentication failed' => 'Autentykacja Github nieudana',
- 'Your GitHub account is no longer linked to your profile.' => 'Konto Github nie jest już podłączone do twojego profilu.',
- 'Unable to unlink your GitHub Account.' => 'Nie można odłączyć konta Github.',
- 'Login with my GitHub Account' => 'Zaloguj przy użyciu konta Github',
- 'Link my GitHub Account' => 'Podłącz konto Github',
- 'Unlink my GitHub Account' => 'Odłącz konto Github',
+ 'Login with my Github Account' => 'Zaloguj przy użyciu konta Github',
+ 'Link my Github Account' => 'Podłącz konto Github',
+ 'Unlink my Github Account' => 'Odłącz konto Github',
'Created by %s' => 'Utworzone przez %s',
'Last modified on %B %e, %Y at %k:%M %p' => 'Ostatnio zmienione %e %B %Y o %k:%M',
'Tasks Export' => 'Eksport zadań',
@@ -615,8 +608,7 @@ return array(
'Time Tracking' => 'Śledzenie czasu',
'You already have one subtask in progress' => 'Masz już zadanie o statusie "w trakcie"',
'Which parts of the project do you want to duplicate?' => 'Które elementy projektu chcesz zduplikować?',
- 'Disable login form' => 'Wyłącz formularz logowania',
- 'Show/hide calendar' => 'Pokaż/Ukryj kalendarz',
+ // 'Disallow login form' => '',
// 'Bitbucket commit received' => '',
// 'Bitbucket webhooks' => '',
// 'Help on Bitbucket webhooks' => '',
@@ -971,4 +963,39 @@ return array(
// 'Search by category: ' => '',
// 'Search by description: ' => '',
// 'Search by due date: ' => '',
+ // 'Lead and Cycle time for "%s"' => '',
+ // 'Average time spent into each column for "%s"' => '',
+ // 'Average time spent into each column' => '',
+ // 'Average time spent' => '',
+ // 'This chart show the average time spent into each column for the last %d tasks.' => '',
+ // 'Average Lead and Cycle time' => '',
+ // 'Average lead time: ' => '',
+ // 'Average cycle time: ' => '',
+ // 'Cycle Time' => '',
+ // 'Lead Time' => '',
+ // 'This chart show the average lead and cycle time for the last %d tasks over the time.' => '',
+ // 'Average time into each column' => '',
+ // 'Lead and cycle time' => '',
+ // 'Google Authentication' => '',
+ // 'Help on Google authentication' => '',
+ // 'Github Authentication' => '',
+ // 'Help on Github authentication' => '',
+ // 'Channel/Group/User (Optional)' => '',
+ // 'Lead time: ' => '',
+ // 'Cycle time: ' => '',
+ // 'Time spent into each column' => '',
+ // 'The lead time is the duration between the task creation and the completion.' => '',
+ // 'The cycle time is the duration between the start date and the completion.' => '',
+ // 'If the task is not closed the current time is used instead of the completion date.' => '',
+ // 'Set automatically the start date' => '',
+ // 'Edit Authentication' => '',
+ // 'Google Id' => '',
+ // 'Github Id' => '',
+ // 'Remote user' => '',
+ // 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '',
+ // 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '',
+ // 'By @%s on Gitlab' => '',
+ // 'Gitlab issue comment created' => '',
+ // 'New remote user' => '',
+ // 'New local user' => '',
);
diff --git a/app/Locale/pt_BR/translations.php b/app/Locale/pt_BR/translations.php
index 1031f1e2..68de0368 100644
--- a/app/Locale/pt_BR/translations.php
+++ b/app/Locale/pt_BR/translations.php
@@ -20,15 +20,15 @@ return array(
'Red' => 'Vermelho',
'Orange' => 'Laranja',
'Grey' => 'Cinza',
- // 'Brown' => '',
- // 'Deep Orange' => '',
- // 'Dark Grey' => '',
- // 'Pink' => '',
- // 'Teal' => '',
- // 'Cyan' => '',
- // 'Lime' => '',
- // 'Light Green' => '',
- // 'Amber' => '',
+ 'Brown' => 'Marrom',
+ 'Deep Orange' => 'Laranja escuro',
+ 'Dark Grey' => 'Cinza escuro',
+ 'Pink' => 'Roza',
+ 'Teal' => 'Turquesa',
+ 'Cyan' => 'Azul intenso',
+ 'Lime' => 'Verde limão',
+ 'Light Green' => 'Verde claro',
+ 'Amber' => 'Âmbar',
'Save' => 'Salvar',
'Login' => 'Login',
'Official website:' => 'Site oficial:',
@@ -126,7 +126,6 @@ return array(
'The project name is required' => 'O nome do projeto é obrigatório',
'This project must be unique' => 'Este projeto deve ser único',
'The title is required' => 'O título é 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.',
'Settings saved successfully.' => 'Configurações salvas com sucesso.',
'Unable to save your settings.' => 'Não é possível salvar suas configurações.',
'Database optimization done.' => 'Otimização do banco de dados finalizada.',
@@ -264,11 +263,10 @@ return array(
'%d comments' => '%d comentários',
'%d comment' => '%d comentário',
'Email address invalid' => 'Endereço de e-mail inválido',
- '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.' => 'Não foi possível desassociar a sua Conta do Google.',
- 'Google authentication failed' => 'Autenticação do Google falhou.',
- '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 foi associada ao seu perfil com sucesso.',
+ // 'Your external account is not linked anymore to your profile.' => '',
+ // 'Unable to unlink your external account.' => '',
+ // 'External authentication failed' => '',
+ // 'Your external account is linked to your profile successfully.' => '',
'Email' => 'E-mail',
'Link my Google Account' => 'Vincular minha Conta do Google',
'Unlink my Google Account' => 'Desvincular minha Conta do Google',
@@ -338,14 +336,9 @@ return array(
'Maximum size: ' => 'Tamanho máximo:',
'Unable to upload the file.' => 'Não foi possível carregar o arquivo.',
'Display another project' => 'Exibir outro projeto',
- '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 associar sua Conta do GitHub.',
- 'GitHub authentication failed' => 'Autenticação do GitHub falhou',
- '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 desassociar a sua Conta do GitHub.',
- 'Login with my GitHub Account' => 'Entrar com minha Conta do GitHub',
- 'Link my GitHub Account' => 'Associar à minha Conta do GitHub',
- 'Unlink my GitHub Account' => 'Desassociar a minha Conta do GitHub',
+ 'Login with my Github Account' => 'Entrar com minha Conta do Github',
+ 'Link my Github Account' => 'Associar à minha Conta do Github',
+ 'Unlink my Github Account' => 'Desassociar a minha Conta do Github',
'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',
'Tasks Export' => 'Exportar Tarefas',
@@ -615,8 +608,7 @@ return array(
'Time Tracking' => 'Gestão de tempo',
'You already have one subtask in progress' => 'Você já tem um subtarefa em andamento',
'Which parts of the project do you want to duplicate?' => 'Quais as partes do projeto você deseja duplicar?',
- 'Disable login form' => 'Desativar o formulário de login',
- 'Show/hide calendar' => 'Mostrar / ocultar calendário',
+ // 'Disallow login form' => '',
'Bitbucket commit received' => '"Commit" recebido via Bitbucket',
'Bitbucket webhooks' => 'Webhook Bitbucket',
'Help on Bitbucket webhooks' => 'Ajuda sobre os webhooks Bitbucket',
@@ -858,117 +850,152 @@ return array(
'Two factor authentication disabled' => 'Autenticação à fator duplo desativado',
'Two factor authentication enabled' => 'Autenticação à fator duplo activado',
'Unable to update this user.' => 'Impossível de atualizar esse usuário.',
- // 'There is no user management for private projects.' => '',
- // 'User that will receive the email' => '',
- // 'Email subject' => '',
- // 'Date' => '',
- // 'By @%s on Bitbucket' => '',
- // 'Bitbucket Issue' => '',
- // 'Commit made by @%s on Bitbucket' => '',
- // 'Commit made by @%s on Github' => '',
- // 'By @%s on Github' => '',
- // 'Commit made by @%s on Gitlab' => '',
- // 'Add a comment log when moving the task between columns' => '',
- // 'Move the task to another column when the category is changed' => '',
- // 'Send a task by email to someone' => '',
- // 'Reopen a task' => '',
- // 'Bitbucket issue opened' => '',
- // 'Bitbucket issue closed' => '',
- // 'Bitbucket issue reopened' => '',
- // 'Bitbucket issue assignee change' => '',
- // 'Bitbucket issue comment created' => '',
- // 'Column change' => '',
- // 'Position change' => '',
- // 'Swimlane change' => '',
- // 'Assignee change' => '',
- // '[%s] Overdue tasks' => '',
- // 'Notification' => '',
- // '%s moved the task #%d to the first swimlane' => '',
- // '%s moved the task #%d to the swimlane "%s"' => '',
- // 'Swimlane' => '',
- // 'Budget overview' => '',
- // 'Type' => '',
- // 'There is not enough data to show something.' => '',
- // 'Gravatar' => '',
- // 'Hipchat' => '',
- // 'Slack' => '',
- // '%s moved the task %s to the first swimlane' => '',
- // '%s moved the task %s to the swimlane "%s"' => '',
- // 'This report contains all subtasks information for the given date range.' => '',
- // 'This report contains all tasks information for the given date range.' => '',
- // 'Project activities for %s' => '',
- // 'view the board on Kanboard' => '',
- // 'The task have been moved to the first swimlane' => '',
- // 'The task have been moved to another swimlane:' => '',
- // 'Overdue tasks for the project "%s"' => '',
- // 'New title: %s' => '',
- // 'The task is not assigned anymore' => '',
- // 'New assignee: %s' => '',
- // 'There is no category now' => '',
- // 'New category: %s' => '',
- // 'New color: %s' => '',
- // 'New complexity: %d' => '',
- // 'The due date have been removed' => '',
- // 'There is no description anymore' => '',
- // 'Recurrence settings have been modified' => '',
- // 'Time spent changed: %sh' => '',
- // 'Time estimated changed: %sh' => '',
- // 'The field "%s" have been updated' => '',
- // 'The description have been modified' => '',
- // 'Do you really want to close the task "%s" as well as all subtasks?' => '',
- // 'Swimlane: %s' => '',
- // 'I want to receive notifications for:' => '',
- // 'All tasks' => '',
- // 'Only for tasks assigned to me' => '',
- // 'Only for tasks created by me' => '',
- // 'Only for tasks created by me and assigned to me' => '',
- // '%A' => '',
- // '%b %e, %Y, %k:%M %p' => '',
- // 'New due date: %B %e, %Y' => '',
- // 'Start date changed: %B %e, %Y' => '',
- // '%k:%M %p' => '',
- // '%%Y-%%m-%%d' => '',
- // 'Total for all columns' => '',
- // 'You need at least 2 days of data to show the chart.' => '',
- // '<15m' => '',
- // '<30m' => '',
- // 'Stop timer' => '',
- // 'Start timer' => '',
- // 'Add project member' => '',
- // 'Enable notifications' => '',
- // 'My activity stream' => '',
- // 'My calendar' => '',
- // 'Search tasks' => '',
- // 'Back to the calendar' => '',
- // 'Filters' => '',
- // 'Reset filters' => '',
- // 'My tasks due tomorrow' => '',
- // 'Tasks due today' => '',
- // 'Tasks due tomorrow' => '',
- // 'Tasks due yesterday' => '',
- // 'Closed tasks' => '',
- // 'Open tasks' => '',
- // 'Not assigned' => '',
- // 'View advanced search syntax' => '',
- // 'Overview' => '',
- // '%b %e %Y' => '',
- // 'Board/Calendar/List view' => '',
- // 'Switch to the board view' => '',
- // 'Switch to the calendar view' => '',
- // 'Switch to the list view' => '',
- // 'Go to the search/filter box' => '',
- // 'There is no activity yet.' => '',
- // 'No tasks found.' => '',
- // 'Keyboard shortcut: "%s"' => '',
- // 'List' => '',
- // 'Filter' => '',
- // 'Advanced search' => '',
- // 'Example of query: ' => '',
- // 'Search by project: ' => '',
- // 'Search by column: ' => '',
- // 'Search by assignee: ' => '',
- // 'Search by color: ' => '',
- // 'Search by category: ' => '',
- // 'Search by description: ' => '',
- // 'Search by due date: ' => '',
+ 'There is no user management for private projects.' => 'Não há gerenciamento de usuários para projetos privados.',
+ 'User that will receive the email' => 'O usuário que vai receber o e-mail',
+ 'Email subject' => 'Assunto do e-mail',
+ 'Date' => 'Data',
+ 'By @%s on Bitbucket' => 'Por @%s no Bitbucket',
+ 'Bitbucket Issue' => 'Bitbucket Issue',
+ 'Commit made by @%s on Bitbucket' => 'Commit feito por @%s no Bitbucket',
+ 'Commit made by @%s on Github' => 'Commit feito por @%s no Github',
+ 'By @%s on Github' => 'Por @%s no Github',
+ 'Commit made by @%s on Gitlab' => 'Commit feito por @%s no Gitlab',
+ 'Add a comment log when moving the task between columns' => 'Adicionar um comentário de log quando uma tarefa é movida para uma outra coluna',
+ 'Move the task to another column when the category is changed' => 'Mover uma tarefa para outra coluna quando a categoria mudou',
+ 'Send a task by email to someone' => 'Enviar uma tarefa por e-mail a alguém',
+ 'Reopen a task' => 'Reabrir uma tarefa',
+ 'Bitbucket issue opened' => 'Bitbucket issue opened',
+ 'Bitbucket issue closed' => 'Bitbucket issue closed',
+ 'Bitbucket issue reopened' => 'Bitbucket issue reopened',
+ 'Bitbucket issue assignee change' => 'Bitbucket issue assignee change',
+ 'Bitbucket issue comment created' => 'Bitbucket issue comment created',
+ 'Column change' => 'Mudança de coluna',
+ 'Position change' => 'Mudança de posição',
+ 'Swimlane change' => 'Mudança de swimlane',
+ 'Assignee change' => 'Mudança do designado',
+ '[%s] Overdue tasks' => '[%s] Tarefas atrasadas',
+ 'Notification' => 'Notificação',
+ '%s moved the task #%d to the first swimlane' => '%s moveu a tarefa n° %d no primeiro swimlane',
+ '%s moved the task #%d to the swimlane "%s"' => '%s moveu a tarefa n° %d no swimlane "%s"',
+ 'Swimlane' => 'Swimlane',
+ 'Budget overview' => 'Visão geral do orçamento',
+ 'Type' => 'Tipo',
+ 'There is not enough data to show something.' => 'Não há dados suficientes para mostrar alguma coisa.',
+ 'Gravatar' => 'Gravatar',
+ 'Hipchat' => 'Hipchat',
+ 'Slack' => 'Slack',
+ '%s moved the task %s to the first swimlane' => '%s moveu a tarefa %s no primeiro swimlane',
+ '%s moved the task %s to the swimlane "%s"' => '%s moveu a tarefa %s no swimlane "%s"',
+ 'This report contains all subtasks information for the given date range.' => 'Este relatório contém informações de todas as sub-tarefas para o período selecionado.',
+ 'This report contains all tasks information for the given date range.' => 'Este relatório contém informações de todas as tarefas para o período selecionado.',
+ 'Project activities for %s' => 'Atividade do projeto "%s"',
+ 'view the board on Kanboard' => 'ver o painel no Kanboard',
+ 'The task have been moved to the first swimlane' => 'A tarefa foi movida para o primeiro Swimlane',
+ 'The task have been moved to another swimlane:' => 'A tarefa foi movida para outro Swimlane',
+ 'Overdue tasks for the project "%s"' => 'Tarefas atrasadas para o projeto "%s"',
+ 'New title: %s' => 'Novo título: %s',
+ 'The task is not assigned anymore' => 'Agora a tarefa não está mais atribuída',
+ 'New assignee: %s' => 'Novo designado: %s',
+ 'There is no category now' => 'Agora não tem mais categoria',
+ 'New category: %s' => 'Nova categoria: %s',
+ 'New color: %s' => 'Nova cor: %s',
+ 'New complexity: %d' => 'Nova complexidade: %d',
+ 'The due date have been removed' => 'A data limite foi retirada',
+ 'There is no description anymore' => 'Agora não tem mais descrição',
+ 'Recurrence settings have been modified' => 'As configurações da recorrência foram modificadas',
+ 'Time spent changed: %sh' => 'O tempo despendido foi mudado: %sh',
+ 'Time estimated changed: %sh' => 'O tempo estimado foi mudado/ %sh',
+ 'The field "%s" have been updated' => 'O campo "%s" foi atualizada',
+ 'The description have been modified' => 'A descrição foi modificada',
+ 'Do you really want to close the task "%s" as well as all subtasks?' => 'Você realmente quer fechar a tarefa "%s" e todas as suas sub-tarefas?',
+ 'Swimlane: %s' => 'Swimlane: %s',
+ 'I want to receive notifications for:' => 'Eu quero receber as notificações para:',
+ 'All tasks' => 'Todas as tarefas',
+ 'Only for tasks assigned to me' => 'Somente as tarefas atribuídas a mim',
+ 'Only for tasks created by me' => 'Apenas as tarefas que eu criei',
+ 'Only for tasks created by me and assigned to me' => 'Apenas as tarefas que eu criei e aquelas atribuídas a mim',
+ '%A' => '%A',
+ '%b %e, %Y, %k:%M %p' => '%d/%m/%Y %H:%M',
+ 'New due date: %B %e, %Y' => 'Nova data limite: %d/%m/%Y',
+ 'Start date changed: %B %e, %Y' => 'Data de início alterada: %d/%m/%Y',
+ '%k:%M %p' => '%H:%M',
+ '%%Y-%%m-%%d' => '%%d/%%m/%%Y',
+ 'Total for all columns' => 'Total para todas as colunas',
+ 'You need at least 2 days of data to show the chart.' => 'Você precisa de pelo menos 2 dias de dados para visualizar o gráfico.',
+ '<15m' => '<15m',
+ '<30m' => '<30m',
+ 'Stop timer' => 'Stop timer',
+ 'Start timer' => 'Start timer',
+ 'Add project member' => 'Adicionar um membro ao projeto',
+ 'Enable notifications' => 'Ativar as notificações',
+ 'My activity stream' => 'Meu feed de atividade',
+ 'My calendar' => 'Minha agenda',
+ 'Search tasks' => 'Pesquisar tarefas',
+ 'Back to the calendar' => 'Voltar ao calendário',
+ 'Filters' => 'Filtros',
+ 'Reset filters' => 'Redefinir os filtros',
+ 'My tasks due tomorrow' => 'Minhas tarefas que expiram amanhã',
+ 'Tasks due today' => 'Tarefas que expiram hoje',
+ 'Tasks due tomorrow' => 'Tarefas que expiram amanhã',
+ 'Tasks due yesterday' => 'Tarefas que expiraram ontem',
+ 'Closed tasks' => 'Tarefas fechadas',
+ 'Open tasks' => 'Tarefas abertas',
+ 'Not assigned' => 'Não designada',
+ 'View advanced search syntax' => 'Ver a sintaxe para pesquisa avançada',
+ 'Overview' => 'Visão global',
+ '%b %e %Y' => '%b %e %Y',
+ 'Board/Calendar/List view' => 'Vista Painel/Calendário/Lista',
+ 'Switch to the board view' => 'Mudar para o modo Painel',
+ 'Switch to the calendar view' => 'Mudar par o modo Calendário',
+ 'Switch to the list view' => 'Mudar par o modo Lista',
+ 'Go to the search/filter box' => 'Ir para o campo de pesquisa',
+ 'There is no activity yet.' => 'Não há nenhuma atividade ainda.',
+ 'No tasks found.' => 'Nenhuma tarefa encontrada',
+ 'Keyboard shortcut: "%s"' => 'Tecla de atalho: "%s"',
+ 'List' => 'Lista',
+ 'Filter' => 'Filtro',
+ 'Advanced search' => 'Pesquisa avançada',
+ 'Example of query: ' => 'Exemplo de consulta: ',
+ 'Search by project: ' => 'Pesquisar por projet: ',
+ 'Search by column: ' => 'Pesquisar por coluna: ',
+ 'Search by assignee: ' => 'Pesquisar por designado: ',
+ 'Search by color: ' => 'Pesquisar por cor: ',
+ 'Search by category: ' => 'Pesquisar por categoria: ',
+ 'Search by description: ' => 'Pesquisar por descrição: ',
+ 'Search by due date: ' => 'Pesquisar por data de expiração: ',
+ // 'Lead and Cycle time for "%s"' => '',
+ // 'Average time spent into each column for "%s"' => '',
+ // 'Average time spent into each column' => '',
+ // 'Average time spent' => '',
+ // 'This chart show the average time spent into each column for the last %d tasks.' => '',
+ // 'Average Lead and Cycle time' => '',
+ // 'Average lead time: ' => '',
+ // 'Average cycle time: ' => '',
+ // 'Cycle Time' => '',
+ // 'Lead Time' => '',
+ // 'This chart show the average lead and cycle time for the last %d tasks over the time.' => '',
+ // 'Average time into each column' => '',
+ // 'Lead and cycle time' => '',
+ // 'Google Authentication' => '',
+ // 'Help on Google authentication' => '',
+ // 'Github Authentication' => '',
+ // 'Help on Github authentication' => '',
+ // 'Channel/Group/User (Optional)' => '',
+ // 'Lead time: ' => '',
+ // 'Cycle time: ' => '',
+ // 'Time spent into each column' => '',
+ // 'The lead time is the duration between the task creation and the completion.' => '',
+ // 'The cycle time is the duration between the start date and the completion.' => '',
+ // 'If the task is not closed the current time is used instead of the completion date.' => '',
+ // 'Set automatically the start date' => '',
+ // 'Edit Authentication' => '',
+ // 'Google Id' => '',
+ // 'Github Id' => '',
+ // 'Remote user' => '',
+ // 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '',
+ // 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '',
+ // 'By @%s on Gitlab' => '',
+ // 'Gitlab issue comment created' => '',
+ // 'New remote user' => '',
+ // 'New local user' => '',
);
diff --git a/app/Locale/ru_RU/translations.php b/app/Locale/ru_RU/translations.php
index 9b8b3e4f..3b7d678c 100644
--- a/app/Locale/ru_RU/translations.php
+++ b/app/Locale/ru_RU/translations.php
@@ -126,7 +126,6 @@ return array(
'The project name is required' => 'Требуется имя проекта',
'This project must be unique' => 'Проект должен быть уникальным',
'The title is required' => 'Требуется заголовок',
- 'There is no active project, the first step is to create a new project.' => 'Нет активного проекта, сначала создайте новый проект.',
'Settings saved successfully.' => 'Параметры успешно сохранены.',
'Unable to save your settings.' => 'Невозможно сохранить параметры.',
'Database optimization done.' => 'База данных оптимизирована.',
@@ -264,11 +263,10 @@ return array(
'%d comments' => '%d комментариев',
'%d comment' => '%d комментарий',
'Email address invalid' => 'Некорректный e-mail адрес',
- 'Your Google Account is not linked anymore to your profile.' => 'Ваш аккаунт в Google больше не привязан к вашему профилю.',
- 'Unable to unlink your Google Account.' => 'Не удалось отвязать ваш профиль от Google.',
- 'Google authentication failed' => 'Аутентификация Google не удалась',
- 'Unable to link your Google Account.' => 'Не удалось привязать ваш профиль к Google.',
- 'Your Google Account is linked to your profile successfully.' => 'Ваш профиль успешно привязан к Google.',
+ // 'Your external account is not linked anymore to your profile.' => '',
+ // 'Unable to unlink your external account.' => '',
+ // 'External authentication failed' => '',
+ // 'Your external account is linked to your profile successfully.' => '',
'Email' => 'E-mail',
'Link my Google Account' => 'Привязать мой профиль к Google',
'Unlink my Google Account' => 'Отвязать мой профиль от Google',
@@ -338,14 +336,9 @@ return array(
'Maximum size: ' => 'Максимальный размер: ',
'Unable to upload the file.' => 'Не удалось загрузить файл.',
'Display another project' => 'Показать другой проект',
- 'Your GitHub account was successfully linked to your profile.' => 'Ваш GitHub привязан к вашему профилю.',
- 'Unable to link your GitHub Account.' => 'Не удалось привязать ваш профиль к GitHub.',
- 'GitHub authentication failed' => 'Аутентификация в GitHub не удалась',
- 'Your GitHub account is no longer linked to your profile.' => 'Ваш GitHub отвязан от вашего профиля.',
- 'Unable to unlink your GitHub Account.' => 'Не удалось отвязать ваш профиль от GitHub.',
- 'Login with my GitHub Account' => 'Аутентификация через GitHub',
- 'Link my GitHub Account' => 'Привязать мой профиль к GitHub',
- 'Unlink my GitHub Account' => 'Отвязать мой профиль от GitHub',
+ 'Login with my Github Account' => 'Аутентификация через Github',
+ 'Link my Github Account' => 'Привязать мой профиль к Github',
+ 'Unlink my Github Account' => 'Отвязать мой профиль от Github',
'Created by %s' => 'Создано %s',
'Last modified on %B %e, %Y at %k:%M %p' => 'Последнее изменение %d/%m/%Y в %H:%M',
'Tasks Export' => 'Экспорт задач',
@@ -403,7 +396,7 @@ return array(
'Enabled' => 'Включен',
'Disabled' => 'Выключены',
'Google account linked' => 'Профиль Google связан',
- 'Github account linked' => 'Профиль GitHub связан',
+ 'Github account linked' => 'Профиль Github связан',
'Username:' => 'Имя пользователя:',
'Name:' => 'Имя:',
'Email:' => 'E-mail:',
@@ -417,7 +410,7 @@ return array(
'Password modification' => 'Изменение пароля',
'External authentications' => 'Внешняя аутентификация',
'Google Account' => 'Профиль Google',
- 'Github Account' => 'Профиль GitHub',
+ 'Github Account' => 'Профиль Github',
'Never connected.' => 'Ранее не соединялось.',
'No account linked.' => 'Нет связанных профилей.',
'Account linked.' => 'Профиль связан.',
@@ -458,12 +451,12 @@ return array(
'%s changed the assignee of the task %s to %s' => '%s сменил назначенного для задачи %s на %s',
'New password for the user "%s"' => 'Новый пароль для пользователя "%s"',
'Choose an event' => 'Выберите событие',
- 'Github commit received' => 'GitHub: коммит получен',
- 'Github issue opened' => 'GitHub: новая проблема',
- 'Github issue closed' => 'GitHub: проблема закрыта',
- 'Github issue reopened' => 'GitHub: проблема переоткрыта',
- 'Github issue assignee change' => 'GitHub: сменить ответственного за проблему',
- 'Github issue label change' => 'GitHub: ярлык проблемы изменен',
+ 'Github commit received' => 'Github: коммит получен',
+ 'Github issue opened' => 'Github: новая проблема',
+ 'Github issue closed' => 'Github: проблема закрыта',
+ 'Github issue reopened' => 'Github: проблема переоткрыта',
+ 'Github issue assignee change' => 'Github: сменить ответственного за проблему',
+ 'Github issue label change' => 'Github: ярлык проблемы изменен',
'Create a task from an external provider' => 'Создать задачу из внешнего источника',
'Change the assignee based on an external username' => 'Изменить назначенного основываясь на внешнем имени пользователя',
'Change the category based on an external label' => 'Изменить категорию основываясь на внешнем ярлыке',
@@ -508,8 +501,8 @@ return array(
'Everybody have access to this project.' => 'Любой может получить доступ к этому проекту.',
'Webhooks' => 'Webhooks',
'API' => 'API',
- 'Github webhooks' => 'GitHub webhooks',
- 'Help on Github webhooks' => 'Помощь по GitHub webhooks',
+ 'Github webhooks' => 'Github webhooks',
+ 'Help on Github webhooks' => 'Помощь по Github webhooks',
'Create a comment from an external provider' => 'Создать комментарий из внешнего источника',
'Github issue comment created' => 'Github issue комментарий создан',
'Project management' => 'Управление проектом',
@@ -615,8 +608,7 @@ return array(
'Time Tracking' => 'Учет времени',
'You already have one subtask in progress' => 'У вас уже есть одна задача в разработке',
'Which parts of the project do you want to duplicate?' => 'Какие части проекта должны быть дублированы?',
- 'Disable login form' => 'Выключить форму авторизации',
- 'Show/hide calendar' => 'Показать/скрыть календарь',
+ // 'Disallow login form' => '',
// 'Bitbucket commit received' => '',
'Bitbucket webhooks' => 'BitBucket webhooks',
'Help on Bitbucket webhooks' => 'Помощь по BitBucket webhooks',
@@ -971,4 +963,39 @@ return array(
// 'Search by category: ' => '',
// 'Search by description: ' => '',
// 'Search by due date: ' => '',
+ // 'Lead and Cycle time for "%s"' => '',
+ // 'Average time spent into each column for "%s"' => '',
+ // 'Average time spent into each column' => '',
+ // 'Average time spent' => '',
+ // 'This chart show the average time spent into each column for the last %d tasks.' => '',
+ // 'Average Lead and Cycle time' => '',
+ // 'Average lead time: ' => '',
+ // 'Average cycle time: ' => '',
+ // 'Cycle Time' => '',
+ // 'Lead Time' => '',
+ // 'This chart show the average lead and cycle time for the last %d tasks over the time.' => '',
+ // 'Average time into each column' => '',
+ // 'Lead and cycle time' => '',
+ // 'Google Authentication' => '',
+ // 'Help on Google authentication' => '',
+ // 'Github Authentication' => '',
+ // 'Help on Github authentication' => '',
+ // 'Channel/Group/User (Optional)' => '',
+ // 'Lead time: ' => '',
+ // 'Cycle time: ' => '',
+ // 'Time spent into each column' => '',
+ // 'The lead time is the duration between the task creation and the completion.' => '',
+ // 'The cycle time is the duration between the start date and the completion.' => '',
+ // 'If the task is not closed the current time is used instead of the completion date.' => '',
+ // 'Set automatically the start date' => '',
+ // 'Edit Authentication' => '',
+ // 'Google Id' => '',
+ // 'Github Id' => '',
+ // 'Remote user' => '',
+ // 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '',
+ // 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '',
+ // 'By @%s on Gitlab' => '',
+ // 'Gitlab issue comment created' => '',
+ // 'New remote user' => '',
+ // 'New local user' => '',
);
diff --git a/app/Locale/sr_Latn_RS/translations.php b/app/Locale/sr_Latn_RS/translations.php
index 758689c4..f3369341 100644
--- a/app/Locale/sr_Latn_RS/translations.php
+++ b/app/Locale/sr_Latn_RS/translations.php
@@ -126,7 +126,6 @@ return array(
'The project name is required' => 'Naziv projekta je obavezan',
'This project must be unique' => 'Projekat mora biti jedinstven',
'The title is required' => 'Naslov je obavezan',
- 'There is no active project, the first step is to create a new project.' => 'Nema aktivnih projekata. Potrebno je prvo napraviti novi projekat.',
'Settings saved successfully.' => 'Podešavanja uspešno snimljena.',
'Unable to save your settings.' => 'Nemoguće snimanje podešavanja.',
'Database optimization done.' => 'Optimizacija baze je završena.',
@@ -264,11 +263,10 @@ return array(
'%d comments' => '%d Komentara',
'%d comment' => '%d Komentar',
'Email address invalid' => 'Pogrešan e-mail',
- 'Your Google Account is not linked anymore to your profile.' => 'Tvoj google nalog više nije povezan sa profilom',
- 'Unable to unlink your Google Account.' => 'Neuspešno ukidanje veze od Google naloga',
- 'Google authentication failed' => 'Neuspešna Google autentikacija',
- 'Unable to link your Google Account.' => 'Neuspešno povezivanje sa Google nalogom',
- 'Your Google Account is linked to your profile successfully.' => 'Vaš Google nalog je uspešno povezan sa vašim profilom',
+ // 'Your external account is not linked anymore to your profile.' => '',
+ // 'Unable to unlink your external account.' => '',
+ // 'External authentication failed' => '',
+ // 'Your external account is linked to your profile successfully.' => '',
'Email' => 'E-mail',
'Link my Google Account' => 'Poveži sa Google nalogom',
'Unlink my Google Account' => 'Ukini vezu sa Google nalogom',
@@ -338,14 +336,9 @@ return array(
'Maximum size: ' => 'Maksimalna veličina: ',
'Unable to upload the file.' => 'Nije moguće snimiti fajl.',
'Display another project' => 'Prikaži drugi projekat',
- 'Your GitHub account was successfully linked to your profile.' => 'Konto Github podłączone pomyślnie.',
- 'Unable to link your GitHub Account.' => 'Nie można połączyć z kontem Github.',
- 'GitHub authentication failed' => 'Autentykacja Github nieudana',
- 'Your GitHub account is no longer linked to your profile.' => 'Konto Github nie jest już podłączone do twojego profilu.',
- 'Unable to unlink your GitHub Account.' => 'Nie można odłączyć konta Github.',
- 'Login with my GitHub Account' => 'Zaloguj przy użyciu konta Github',
- 'Link my GitHub Account' => 'Podłącz konto Github',
- 'Unlink my GitHub Account' => 'Odłącz konto Github',
+ 'Login with my Github Account' => 'Zaloguj przy użyciu konta Github',
+ 'Link my Github Account' => 'Podłącz konto Github',
+ 'Unlink my Github Account' => 'Odłącz konto Github',
'Created by %s' => 'Kreirao %s',
'Last modified on %B %e, %Y at %k:%M %p' => 'Poslednja izmena %e %B %Y o %k:%M',
'Tasks Export' => 'Izvoz zadataka',
@@ -615,8 +608,7 @@ return array(
'Time Tracking' => 'Praćenje vremena',
// 'You already have one subtask in progress' => '',
'Which parts of the project do you want to duplicate?' => 'Koje delove projekta želite da kopirate',
- // 'Disable login form' => '',
- // 'Show/hide calendar' => '',
+ // 'Disallow login form' => '',
// 'Bitbucket commit received' => '',
// 'Bitbucket webhooks' => '',
// 'Help on Bitbucket webhooks' => '',
@@ -971,4 +963,39 @@ return array(
// 'Search by category: ' => '',
// 'Search by description: ' => '',
// 'Search by due date: ' => '',
+ // 'Lead and Cycle time for "%s"' => '',
+ // 'Average time spent into each column for "%s"' => '',
+ // 'Average time spent into each column' => '',
+ // 'Average time spent' => '',
+ // 'This chart show the average time spent into each column for the last %d tasks.' => '',
+ // 'Average Lead and Cycle time' => '',
+ // 'Average lead time: ' => '',
+ // 'Average cycle time: ' => '',
+ // 'Cycle Time' => '',
+ // 'Lead Time' => '',
+ // 'This chart show the average lead and cycle time for the last %d tasks over the time.' => '',
+ // 'Average time into each column' => '',
+ // 'Lead and cycle time' => '',
+ // 'Google Authentication' => '',
+ // 'Help on Google authentication' => '',
+ // 'Github Authentication' => '',
+ // 'Help on Github authentication' => '',
+ // 'Channel/Group/User (Optional)' => '',
+ // 'Lead time: ' => '',
+ // 'Cycle time: ' => '',
+ // 'Time spent into each column' => '',
+ // 'The lead time is the duration between the task creation and the completion.' => '',
+ // 'The cycle time is the duration between the start date and the completion.' => '',
+ // 'If the task is not closed the current time is used instead of the completion date.' => '',
+ // 'Set automatically the start date' => '',
+ // 'Edit Authentication' => '',
+ // 'Google Id' => '',
+ // 'Github Id' => '',
+ // 'Remote user' => '',
+ // 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '',
+ // 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '',
+ // 'By @%s on Gitlab' => '',
+ // 'Gitlab issue comment created' => '',
+ // 'New remote user' => '',
+ // 'New local user' => '',
);
diff --git a/app/Locale/sv_SE/translations.php b/app/Locale/sv_SE/translations.php
index 4690edea..db552359 100644
--- a/app/Locale/sv_SE/translations.php
+++ b/app/Locale/sv_SE/translations.php
@@ -126,7 +126,6 @@ return array(
'The project name is required' => 'Ett projektnamn måste anges',
'This project must be unique' => 'Detta projekt måste vara unikt',
'The title is required' => 'En titel måste anges.',
- 'There is no active project, the first step is to create a new project.' => 'Inget projekt är aktiverat, första steget är att skapa ett nytt projekt',
'Settings saved successfully.' => 'Inställningarna har sparats.',
'Unable to save your settings.' => 'Kunde inte spara dina ändringar',
'Database optimization done.' => 'Databasen har optimerats.',
@@ -264,11 +263,10 @@ return array(
'%d comments' => '%d kommentarer',
'%d comment' => '%d kommentar',
'Email address invalid' => 'Epost-adressen ogiltig',
- 'Your Google Account is not linked anymore to your profile.' => 'Ditt Google-konto är inte längre länkat till din profil',
- 'Unable to unlink your Google Account.' => 'Kunde inte ta bort länken till ditt Google-konto.',
- 'Google authentication failed' => 'Autentiseringen för Google misslyckades',
- 'Unable to link your Google Account.' => 'Kunde inte länka till ditt Google-konto',
- 'Your Google Account is linked to your profile successfully.' => 'Ditt Google-konto har kopplats till din profil.',
+ // 'Your external account is not linked anymore to your profile.' => '',
+ // 'Unable to unlink your external account.' => '',
+ // 'External authentication failed' => '',
+ // 'Your external account is linked to your profile successfully.' => '',
'Email' => 'Epost',
'Link my Google Account' => 'Länka till mitt Google-konto',
'Unlink my Google Account' => 'Ta bort länken till mitt Google-konto',
@@ -338,14 +336,9 @@ return array(
'Maximum size: ' => 'Maxstorlek: ',
'Unable to upload the file.' => 'Kunde inte ladda upp filen.',
'Display another project' => 'Visa ett annat projekt',
- 'Your GitHub account was successfully linked to your profile.' => 'Ditt GitHub-konto har anslutits till din profil.',
- 'Unable to link your GitHub Account.' => 'Kunde inte ansluta ditt GitHub-konto.',
- 'GitHub authentication failed' => 'GitHub-verifiering misslyckades',
- 'Your GitHub account is no longer linked to your profile.' => 'Ditt GitHub-konto är inte längre anslutet till din profil.',
- 'Unable to unlink your GitHub Account.' => 'Kunde inte koppla ifrån ditt GitHub-konto.',
- 'Login with my GitHub Account' => 'Logga in med mitt GitHub-konto',
- 'Link my GitHub Account' => 'Anslut mitt GitHub-konto',
- 'Unlink my GitHub Account' => 'Koppla ifrån mitt GitHub-konto',
+ 'Login with my Github Account' => 'Logga in med mitt Github-konto',
+ 'Link my Github Account' => 'Anslut mitt Github-konto',
+ 'Unlink my Github Account' => 'Koppla ifrån mitt Github-konto',
'Created by %s' => 'Skapad av %s',
'Last modified on %B %e, %Y at %k:%M %p' => 'Senaste ändring %Y-%m-%d kl %H:%M',
'Tasks Export' => 'Exportera uppgifter',
@@ -615,8 +608,7 @@ return array(
'Time Tracking' => 'Tidsbevakning',
'You already have one subtask in progress' => 'Du har redan en deluppgift igång',
'Which parts of the project do you want to duplicate?' => 'Vilka delar av projektet vill du duplicera?',
- 'Disable login form' => 'Inaktivera loginformuläret',
- 'Show/hide calendar' => 'Visa/dölj kalender',
+ // 'Disallow login form' => '',
'Bitbucket commit received' => 'Bitbucket bidrag mottaget',
'Bitbucket webhooks' => 'Bitbucket webhooks',
'Help on Bitbucket webhooks' => 'Hjälp för Bitbucket webhooks',
@@ -865,8 +857,8 @@ return array(
'By @%s on Bitbucket' => 'Av @%s på Bitbucket',
'Bitbucket Issue' => 'Bitbucket fråga',
'Commit made by @%s on Bitbucket' => 'Bidrag gjort av @%s på Bitbucket',
- 'Commit made by @%s on Github' => 'Bidrag gjort av @%s på GitHub',
- 'By @%s on Github' => 'Av @%s på GitHub',
+ 'Commit made by @%s on Github' => 'Bidrag gjort av @%s på Github',
+ 'By @%s on Github' => 'Av @%s på Github',
'Commit made by @%s on Gitlab' => 'Bidrag gjort av @%s på Gitlab',
'Add a comment log when moving the task between columns' => 'Lägg till en kommentarslogg när en uppgift flyttas mellan kolumner',
'Move the task to another column when the category is changed' => 'Flyttas uppgiften till en annan kolumn när kategorin ändras',
@@ -971,4 +963,39 @@ return array(
'Search by category: ' => 'Sök efter kategori:',
'Search by description: ' => 'Sök efter beskrivning',
'Search by due date: ' => 'Sök efter förfallodatum',
+ // 'Lead and Cycle time for "%s"' => '',
+ // 'Average time spent into each column for "%s"' => '',
+ // 'Average time spent into each column' => '',
+ // 'Average time spent' => '',
+ // 'This chart show the average time spent into each column for the last %d tasks.' => '',
+ // 'Average Lead and Cycle time' => '',
+ // 'Average lead time: ' => '',
+ // 'Average cycle time: ' => '',
+ // 'Cycle Time' => '',
+ // 'Lead Time' => '',
+ // 'This chart show the average lead and cycle time for the last %d tasks over the time.' => '',
+ // 'Average time into each column' => '',
+ // 'Lead and cycle time' => '',
+ // 'Google Authentication' => '',
+ // 'Help on Google authentication' => '',
+ // 'Github Authentication' => '',
+ // 'Help on Github authentication' => '',
+ // 'Channel/Group/User (Optional)' => '',
+ // 'Lead time: ' => '',
+ // 'Cycle time: ' => '',
+ // 'Time spent into each column' => '',
+ // 'The lead time is the duration between the task creation and the completion.' => '',
+ // 'The cycle time is the duration between the start date and the completion.' => '',
+ // 'If the task is not closed the current time is used instead of the completion date.' => '',
+ // 'Set automatically the start date' => '',
+ // 'Edit Authentication' => '',
+ // 'Google Id' => '',
+ // 'Github Id' => '',
+ // 'Remote user' => '',
+ // 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '',
+ // 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '',
+ // 'By @%s on Gitlab' => '',
+ // 'Gitlab issue comment created' => '',
+ // 'New remote user' => '',
+ // 'New local user' => '',
);
diff --git a/app/Locale/th_TH/translations.php b/app/Locale/th_TH/translations.php
index c1eb3183..c4d608bd 100644
--- a/app/Locale/th_TH/translations.php
+++ b/app/Locale/th_TH/translations.php
@@ -126,7 +126,6 @@ return array(
'The project name is required' => 'ต้องการชื่อโปรเจค',
'This project must be unique' => 'ชื่อโปรเจคต้องไม่ซ้ำ',
'The title is required' => 'ต้องการหัวเรื่อง',
- 'There is no active project, the first step is to create a new project.' => 'ไม่มีโปรเจคที่ทำงานอยู่, ต้องการสร้างโปรเจคใหม่',
'Settings saved successfully.' => 'บันทึกการตั้งค่าเรียบร้อยแล้ว',
'Unable to save your settings.' => 'ไม่สามารถบันทึกการตั้งค่าได้',
'Database optimization done.' => 'ปรับปรุงฐานข้อมูลเรียบร้อยแล้ว',
@@ -264,11 +263,10 @@ return array(
'%d comments' => '%d ความคิดเห็น',
'%d comment' => '%d ความคิดเห็น',
'Email address invalid' => 'อีเมลผิด',
- 'Your Google Account is not linked anymore to your profile.' => 'กูเกิลแอคเคาท์ไม่ได้เชื่อมต่อกับประวัติของคุณ',
- 'Unable to unlink your Google Account.' => 'ไม่สามารถยกเลิกการเชื่อมต่อกับกูเกิลแอคเคาท์',
- 'Google authentication failed' => 'การยืนยันกับกูเกิลผิดพลาด',
- 'Unable to link your Google Account.' => 'ไม่สามารถเชื่อมต่อกับกูเกิลแอคเคาท์',
- 'Your Google Account is linked to your profile successfully.' => 'กูเกลิแอคเคาท์เชื่อมต่อกับประวัติของคุณเรียบร้อยแล้ว',
+ // 'Your external account is not linked anymore to your profile.' => '',
+ // 'Unable to unlink your external account.' => '',
+ // 'External authentication failed' => '',
+ // 'Your external account is linked to your profile successfully.' => '',
'Email' => 'อีเมล',
'Link my Google Account' => 'เชื่อมต่อกับกูเกิลแอคเคาท์',
'Unlink my Google Account' => 'ไม่เชื่อมต่อกับกูเกิลแอคเคาท์',
@@ -338,14 +336,9 @@ return array(
'Maximum size: ' => 'ขนาดสูงสุด:',
'Unable to upload the file.' => 'ไม่สามารถอัพโหลดไฟล์ได้',
'Display another project' => 'แสดงโปรเจคอื่น',
- 'Your GitHub account was successfully linked to your profile.' => 'กิทฮับแอคเคาท์เชื่อมต่อกับประวัติเรียบร้อยแล้ว',
- 'Unable to link your GitHub Account.' => 'ไม่สามารถเชื่อมต่อกับกิทฮับแอคเคาท์ได้',
- 'GitHub authentication failed' => 'การยืนยันกิทฮับผิดพลาด',
- 'Your GitHub account is no longer linked to your profile.' => 'กิทฮับแอคเคาท์ไม่ได้มีการเชื่อมโยงไปยังโปรไฟล์ของคุณ',
- 'Unable to unlink your GitHub Account.' => 'ไม่สามารถยกเลิกการเชื่อมต่อกิทฮับแอคเคาท์ได้',
- 'Login with my GitHub Account' => 'เข้าใช้ด้วยกิทฮับแอคเคาท์',
- 'Link my GitHub Account' => 'เชื่อมกับกิทฮับแอคเคาท์',
- 'Unlink my GitHub Account' => 'ยกเลิกการเชื่อมกับกิทอับแอคเคาท์',
+ 'Login with my Github Account' => 'เข้าใช้ด้วยกิทฮับแอคเคาท์',
+ 'Link my Github Account' => 'เชื่อมกับกิทฮับแอคเคาท์',
+ 'Unlink my Github Account' => 'ยกเลิกการเชื่อมกับกิทอับแอคเคาท์',
'Created by %s' => 'สร้างโดย %s',
'Last modified on %B %e, %Y at %k:%M %p' => 'แก้ไขล่าสุดวันที่ %B %e, %Y เวลา %k:%M %p',
'Tasks Export' => 'ส่งออกงาน',
@@ -615,8 +608,7 @@ return array(
'Time Tracking' => 'ติดตามเวลา',
'You already have one subtask in progress' => 'คุณมีหนึ่งงานย่อยที่กำลังทำงาน',
// 'Which parts of the project do you want to duplicate?' => '',
- // 'Disable login form' => '',
- 'Show/hide calendar' => 'แสดง/ซ่อน ปฎิทิน',
+ // 'Disallow login form' => '',
// 'Bitbucket commit received' => '',
// 'Bitbucket webhooks' => '',
// 'Help on Bitbucket webhooks' => '',
@@ -971,4 +963,39 @@ return array(
// 'Search by category: ' => '',
// 'Search by description: ' => '',
// 'Search by due date: ' => '',
+ // 'Lead and Cycle time for "%s"' => '',
+ // 'Average time spent into each column for "%s"' => '',
+ // 'Average time spent into each column' => '',
+ // 'Average time spent' => '',
+ // 'This chart show the average time spent into each column for the last %d tasks.' => '',
+ // 'Average Lead and Cycle time' => '',
+ // 'Average lead time: ' => '',
+ // 'Average cycle time: ' => '',
+ // 'Cycle Time' => '',
+ // 'Lead Time' => '',
+ // 'This chart show the average lead and cycle time for the last %d tasks over the time.' => '',
+ // 'Average time into each column' => '',
+ // 'Lead and cycle time' => '',
+ // 'Google Authentication' => '',
+ // 'Help on Google authentication' => '',
+ // 'Github Authentication' => '',
+ // 'Help on Github authentication' => '',
+ // 'Channel/Group/User (Optional)' => '',
+ // 'Lead time: ' => '',
+ // 'Cycle time: ' => '',
+ // 'Time spent into each column' => '',
+ // 'The lead time is the duration between the task creation and the completion.' => '',
+ // 'The cycle time is the duration between the start date and the completion.' => '',
+ // 'If the task is not closed the current time is used instead of the completion date.' => '',
+ // 'Set automatically the start date' => '',
+ // 'Edit Authentication' => '',
+ // 'Google Id' => '',
+ // 'Github Id' => '',
+ // 'Remote user' => '',
+ // 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '',
+ // 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '',
+ // 'By @%s on Gitlab' => '',
+ // 'Gitlab issue comment created' => '',
+ // 'New remote user' => '',
+ // 'New local user' => '',
);
diff --git a/app/Locale/tr_TR/translations.php b/app/Locale/tr_TR/translations.php
index 9335c201..afb88744 100644
--- a/app/Locale/tr_TR/translations.php
+++ b/app/Locale/tr_TR/translations.php
@@ -126,7 +126,6 @@ return array(
'The project name is required' => 'Proje adı gerekli',
'This project must be unique' => 'Bu projenin tekil olması gerekli',
'The title is required' => 'Başlık gerekli',
- 'There is no active project, the first step is to create a new project.' => 'Aktif bir proje yok. İlk aşama yeni bir proje oluşturmak olmalı.',
'Settings saved successfully.' => 'Ayarlar başarıyla kaydedildi.',
'Unable to save your settings.' => 'Ayarlarınız kaydedilemedi.',
'Database optimization done.' => 'Veritabanı optimizasyonu tamamlandı.',
@@ -264,11 +263,10 @@ return array(
'%d comments' => '%d yorumlar',
'%d comment' => '%d yorum',
'Email address invalid' => 'E-Posta adresi geçersiz',
- 'Your Google Account is not linked anymore to your profile.' => 'Google hesabınız artık profilinize bağlı değil',
- 'Unable to unlink your Google Account.' => 'Google hesabınızla bağ koparılamadı',
- 'Google authentication failed' => 'Google hesap doğrulaması başarısız',
- 'Unable to link your Google Account.' => 'Google hesabınızla bağ oluşturulamadı',
- 'Your Google Account is linked to your profile successfully.' => 'Google hesabınız profilinize başarıyla bağlandı',
+ // 'Your external account is not linked anymore to your profile.' => '',
+ // 'Unable to unlink your external account.' => '',
+ // 'External authentication failed' => '',
+ // 'Your external account is linked to your profile successfully.' => '',
'Email' => 'E-Posta',
'Link my Google Account' => 'Google hesabımla bağ oluştur',
'Unlink my Google Account' => 'Google hesabımla bağı kaldır',
@@ -338,14 +336,9 @@ return array(
'Maximum size: ' => 'Maksimum boyutu',
'Unable to upload the file.' => 'Karşıya yükleme başarısız',
'Display another project' => 'Başka bir proje göster',
- 'Your GitHub account was successfully linked to your profile.' => 'GitHub Hesabınız Profilinize bağlandı.',
- 'Unable to link your GitHub Account.' => 'GitHub hesabınızla bağ oluşturulamadı.',
- // 'GitHub authentication failed' => '',
- // 'Your GitHub account is no longer linked to your profile.' => '',
- // 'Unable to unlink your GitHub Account.' => '',
- // 'Login with my GitHub Account' => '',
- // 'Link my GitHub Account' => '',
- // 'Unlink my GitHub Account' => '',
+ // 'Login with my Github Account' => '',
+ // 'Link my Github Account' => '',
+ // 'Unlink my Github Account' => '',
'Created by %s' => '%s tarafından oluşturuldu',
'Last modified on %B %e, %Y at %k:%M %p' => 'Son değişiklik tarihi %d.%m.%Y, saati %H:%M',
'Tasks Export' => 'Görevleri dışa aktar',
@@ -615,8 +608,7 @@ return array(
'Time Tracking' => 'Zaman takibi',
'You already have one subtask in progress' => 'Zaten işlemde olan bir alt görev var',
'Which parts of the project do you want to duplicate?' => 'Projenin hangi kısımlarının kopyasını oluşturmak istiyorsunuz?',
- 'Disable login form' => 'Giriş formunu devre dışı bırak',
- 'Show/hide calendar' => 'Takvimi göster/gizle',
+ // 'Disallow login form' => '',
'Bitbucket commit received' => 'Bitbucket commit alındı',
'Bitbucket webhooks' => 'Bitbucket webhooks',
'Help on Bitbucket webhooks' => 'Bitbucket webhooks için yardım',
@@ -971,4 +963,39 @@ return array(
// 'Search by category: ' => '',
// 'Search by description: ' => '',
// 'Search by due date: ' => '',
+ // 'Lead and Cycle time for "%s"' => '',
+ // 'Average time spent into each column for "%s"' => '',
+ // 'Average time spent into each column' => '',
+ // 'Average time spent' => '',
+ // 'This chart show the average time spent into each column for the last %d tasks.' => '',
+ // 'Average Lead and Cycle time' => '',
+ // 'Average lead time: ' => '',
+ // 'Average cycle time: ' => '',
+ // 'Cycle Time' => '',
+ // 'Lead Time' => '',
+ // 'This chart show the average lead and cycle time for the last %d tasks over the time.' => '',
+ // 'Average time into each column' => '',
+ // 'Lead and cycle time' => '',
+ // 'Google Authentication' => '',
+ // 'Help on Google authentication' => '',
+ // 'Github Authentication' => '',
+ // 'Help on Github authentication' => '',
+ // 'Channel/Group/User (Optional)' => '',
+ // 'Lead time: ' => '',
+ // 'Cycle time: ' => '',
+ // 'Time spent into each column' => '',
+ // 'The lead time is the duration between the task creation and the completion.' => '',
+ // 'The cycle time is the duration between the start date and the completion.' => '',
+ // 'If the task is not closed the current time is used instead of the completion date.' => '',
+ // 'Set automatically the start date' => '',
+ // 'Edit Authentication' => '',
+ // 'Google Id' => '',
+ // 'Github Id' => '',
+ // 'Remote user' => '',
+ // 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '',
+ // 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '',
+ // 'By @%s on Gitlab' => '',
+ // 'Gitlab issue comment created' => '',
+ // 'New remote user' => '',
+ // 'New local user' => '',
);
diff --git a/app/Locale/zh_CN/translations.php b/app/Locale/zh_CN/translations.php
index 155628dc..cd2518fd 100644
--- a/app/Locale/zh_CN/translations.php
+++ b/app/Locale/zh_CN/translations.php
@@ -126,7 +126,6 @@ return array(
'The project name is required' => '需要指定项目名称',
'This project must be unique' => '项目名称必须唯一',
'The title is required' => '需要指定标题',
- 'There is no active project, the first step is to create a new project.' => '尚无活跃项目,请首先创建一个新项目。',
'Settings saved successfully.' => '设置成功保存。',
'Unable to save your settings.' => '无法保存你的设置。',
'Database optimization done.' => '数据库优化完成。',
@@ -264,11 +263,10 @@ return array(
'%d comments' => '%d个评论',
'%d comment' => '%d个评论',
'Email address invalid' => '电子邮件地址无效',
- 'Your Google Account is not linked anymore to your profile.' => '您的google帐号不再与您的账户配置关联。',
- 'Unable to unlink your Google Account.' => '无法去除您google帐号的关联',
- 'Google authentication failed' => 'google验证失败',
- 'Unable to link your Google Account.' => '无法关联您的google帐号。',
- 'Your Google Account is linked to your profile successfully.' => '您的google帐号已成功与账户配置关联。',
+ // 'Your external account is not linked anymore to your profile.' => '',
+ // 'Unable to unlink your external account.' => '',
+ // 'External authentication failed' => '',
+ // 'Your external account is linked to your profile successfully.' => '',
'Email' => '电子邮件',
'Link my Google Account' => '关联我的google帐号',
'Unlink my Google Account' => '去除我的google帐号关联',
@@ -338,14 +336,9 @@ return array(
'Maximum size: ' => '大小上限:',
'Unable to upload the file.' => '无法上传文件',
'Display another project' => '显示其它项目',
- 'Your GitHub account was successfully linked to your profile.' => 'GitHub账号已经成功链接到您的用户',
- 'Unable to link your GitHub Account.' => '无法链接到GitHub账户',
- 'GitHub authentication failed' => 'GitHub认证失败',
- 'Your GitHub account is no longer linked to your profile.' => 'Github账号已经不再链接到您的用户',
- 'Unable to unlink your GitHub Account.' => '无法链接GitHub账号',
- 'Login with my GitHub Account' => '用Github账号登录',
- 'Link my GitHub Account' => '链接GitHub账号',
- 'Unlink my GitHub Account' => '取消GitHub账号链接',
+ 'Login with my Github Account' => '用Github账号登录',
+ 'Link my Github Account' => '链接Github账号',
+ 'Unlink my Github Account' => '取消Github账号链接',
'Created by %s' => '创建者:%s',
'Last modified on %B %e, %Y at %k:%M %p' => '最后修改:%Y/%m/%d/ %H:%M',
'Tasks Export' => '任务导出',
@@ -615,8 +608,7 @@ return array(
'Time Tracking' => '时间记录',
'You already have one subtask in progress' => '你已经有了一个进行中的子任务',
'Which parts of the project do you want to duplicate?' => '要复制项目的哪些内容?',
- 'Disable login form' => '禁用登录界面',
- 'Show/hide calendar' => '显示/隐藏日程表',
+ // 'Disallow login form' => '',
'Bitbucket commit received' => '收到Bitbucket提交',
'Bitbucket webhooks' => 'Bitbucket网络钩子',
'Help on Bitbucket webhooks' => 'Bitbucket网络钩子帮助',
@@ -971,4 +963,39 @@ return array(
// 'Search by category: ' => '',
// 'Search by description: ' => '',
// 'Search by due date: ' => '',
+ // 'Lead and Cycle time for "%s"' => '',
+ // 'Average time spent into each column for "%s"' => '',
+ // 'Average time spent into each column' => '',
+ // 'Average time spent' => '',
+ // 'This chart show the average time spent into each column for the last %d tasks.' => '',
+ // 'Average Lead and Cycle time' => '',
+ // 'Average lead time: ' => '',
+ // 'Average cycle time: ' => '',
+ // 'Cycle Time' => '',
+ // 'Lead Time' => '',
+ // 'This chart show the average lead and cycle time for the last %d tasks over the time.' => '',
+ // 'Average time into each column' => '',
+ // 'Lead and cycle time' => '',
+ // 'Google Authentication' => '',
+ // 'Help on Google authentication' => '',
+ // 'Github Authentication' => '',
+ // 'Help on Github authentication' => '',
+ // 'Channel/Group/User (Optional)' => '',
+ // 'Lead time: ' => '',
+ // 'Cycle time: ' => '',
+ // 'Time spent into each column' => '',
+ // 'The lead time is the duration between the task creation and the completion.' => '',
+ // 'The cycle time is the duration between the start date and the completion.' => '',
+ // 'If the task is not closed the current time is used instead of the completion date.' => '',
+ // 'Set automatically the start date' => '',
+ // 'Edit Authentication' => '',
+ // 'Google Id' => '',
+ // 'Github Id' => '',
+ // 'Remote user' => '',
+ // 'Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.' => '',
+ // 'If you check the box "Disallow login form", credentials entered in the login form will be ignored.' => '',
+ // 'By @%s on Gitlab' => '',
+ // 'Gitlab issue comment created' => '',
+ // 'New remote user' => '',
+ // 'New local user' => '',
);
diff --git a/app/Model/Acl.php b/app/Model/Acl.php
index 09638302..b9c06e98 100644
--- a/app/Model/Acl.php
+++ b/app/Model/Acl.php
@@ -18,12 +18,12 @@ class Acl extends Base
*/
private $public_acl = array(
'auth' => array('login', 'check'),
- 'user' => array('google', 'github'),
'task' => array('readonly'),
'board' => array('readonly'),
'webhook' => '*',
'ical' => '*',
'feed' => '*',
+ 'oauth' => array('google', 'github'),
);
/**
@@ -70,7 +70,7 @@ class Acl extends Base
* @var array
*/
private $admin_acl = array(
- 'user' => array('index', 'create', 'save', 'remove'),
+ 'user' => array('index', 'create', 'save', 'remove', 'authentication'),
'config' => '*',
'link' => '*',
'project' => array('remove'),
diff --git a/app/Model/Action.php b/app/Model/Action.php
index d0607794..5e994c99 100644
--- a/app/Model/Action.php
+++ b/app/Model/Action.php
@@ -92,6 +92,7 @@ class Action extends Base
GitlabWebhook::EVENT_COMMIT => t('Gitlab commit received'),
GitlabWebhook::EVENT_ISSUE_OPENED => t('Gitlab issue opened'),
GitlabWebhook::EVENT_ISSUE_CLOSED => t('Gitlab issue closed'),
+ GitlabWebhook::EVENT_ISSUE_COMMENT => t('Gitlab issue comment created'),
BitbucketWebhook::EVENT_COMMIT => t('Bitbucket commit received'),
BitbucketWebhook::EVENT_ISSUE_OPENED => t('Bitbucket issue opened'),
BitbucketWebhook::EVENT_ISSUE_CLOSED => t('Bitbucket issue closed'),
diff --git a/app/Model/TaskFilter.php b/app/Model/TaskFilter.php
index 8d7bdb44..d7d5148b 100644
--- a/app/Model/TaskFilter.php
+++ b/app/Model/TaskFilter.php
@@ -71,6 +71,9 @@ class TaskFilter extends Base
case 'T_REFERENCE':
$this->filterByReference($value);
break;
+ case 'T_SWIMLANE':
+ $this->filterBySwimlaneName($value);
+ break;
}
}
@@ -247,6 +250,30 @@ class TaskFilter extends Base
}
/**
+ * Filter by swimlane name
+ *
+ * @access public
+ * @param array $values List of swimlane name
+ * @return TaskFilter
+ */
+ public function filterBySwimlaneName(array $values)
+ {
+ $this->query->beginOr();
+
+ foreach ($values as $swimlane) {
+ if ($swimlane === 'default') {
+ $this->query->eq(Task::TABLE.'.swimlane_id', 0);
+ }
+ else {
+ $this->query->ilike(Swimlane::TABLE.'.name', $swimlane);
+ $this->query->addCondition(Task::TABLE.'.swimlane_id=0 AND '.Project::TABLE.'.default_swimlane '.$this->db->getDriver()->getOperator('ILIKE')." '$swimlane'");
+ }
+ }
+
+ $this->query->closeOr();
+ }
+
+ /**
* Filter by category id
*
* @access public
diff --git a/app/Model/TaskFinder.php b/app/Model/TaskFinder.php
index 2b0453a5..47a67a35 100644
--- a/app/Model/TaskFinder.php
+++ b/app/Model/TaskFinder.php
@@ -88,11 +88,14 @@ class TaskFinder extends Base
Category::TABLE.'.name AS category_name',
Category::TABLE.'.description AS category_description',
Board::TABLE.'.title AS column_name',
+ Swimlane::TABLE.'.name AS swimlane_name',
+ Project::TABLE.'.default_swimlane',
Project::TABLE.'.name AS project_name'
)
->join(User::TABLE, 'id', 'owner_id', Task::TABLE)
->join(Category::TABLE, 'id', 'category_id', Task::TABLE)
->join(Board::TABLE, 'id', 'column_id', Task::TABLE)
+ ->join(Swimlane::TABLE, 'id', 'swimlane_id', Task::TABLE)
->join(Project::TABLE, 'id', 'project_id', Task::TABLE);
}
diff --git a/app/Model/User.php b/app/Model/User.php
index 4c32942c..b6804abc 100644
--- a/app/Model/User.php
+++ b/app/Model/User.php
@@ -122,13 +122,13 @@ class User extends Base
}
/**
- * Get a specific user by the GitHub id
+ * Get a specific user by the Github id
*
* @access public
- * @param string $github_id GitHub user id
+ * @param string $github_id Github user id
* @return array|boolean
*/
- public function getByGitHubId($github_id)
+ public function getByGithubId($github_id)
{
if (empty($github_id)) {
return false;
@@ -377,6 +377,7 @@ class User extends Base
new Validators\Unique('username', t('The username must be unique'), $this->db->getConnection(), self::TABLE, 'id'),
new Validators\Email('email', t('Email address invalid')),
new Validators\Integer('is_admin', t('This value must be an integer')),
+ new Validators\Integer('is_ldap_user', t('This value must be an integer')),
);
}
@@ -409,7 +410,12 @@ class User extends Base
new Validators\Required('username', t('The username is required')),
);
- $v = new Validator($values, array_merge($rules, $this->commonValidationRules(), $this->commonPasswordValidationRules()));
+ if (isset($values['is_ldap_user']) && $values['is_ldap_user'] == 1) {
+ $v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
+ }
+ else {
+ $v = new Validator($values, array_merge($rules, $this->commonValidationRules(), $this->commonPasswordValidationRules()));
+ }
return array(
$v->execute(),
diff --git a/app/ServiceProvider/ClassProvider.php b/app/ServiceProvider/ClassProvider.php
index 8c55457d..ef7aa575 100644
--- a/app/ServiceProvider/ClassProvider.php
+++ b/app/ServiceProvider/ClassProvider.php
@@ -3,6 +3,7 @@
namespace ServiceProvider;
use Core\Paginator;
+use Core\OAuth2;
use Model\Config;
use Model\Project;
use Model\Webhook;
@@ -72,6 +73,7 @@ class ClassProvider implements ServiceProviderInterface
'Lexer',
'MemoryCache',
'Request',
+ 'Router',
'Session',
'Template',
),
@@ -106,5 +108,9 @@ class ClassProvider implements ServiceProviderInterface
$container['paginator'] = $container->factory(function ($c) {
return new Paginator($c);
});
+
+ $container['oauth'] = $container->factory(function ($c) {
+ return new OAuth2($c);
+ });
}
}
diff --git a/app/Template/app/overview.php b/app/Template/app/overview.php
index fa7866af..1b160496 100644
--- a/app/Template/app/overview.php
+++ b/app/Template/app/overview.php
@@ -1,7 +1,7 @@
<div class="search">
- <form method="get" action="?" class="search">
+ <form method="get" action="<?= $this->url->dir() ?>" class="search">
<?= $this->form->hidden('controller', array('controller' => 'search')) ?>
- <?= $this->form->hidden('action', array('controller' => 'index')) ?>
+ <?= $this->form->hidden('action', array('action' => 'index')) ?>
<?= $this->form->text('search', array(), array(), array('placeholder="'.t('Search').'"'), 'form-input-large') ?>
</form>
diff --git a/app/Template/auth/index.php b/app/Template/auth/index.php
index 39d007f5..ca303df9 100644
--- a/app/Template/auth/index.php
+++ b/app/Template/auth/index.php
@@ -4,7 +4,8 @@
<p class="alert alert-error"><?= $this->e($errors['login']) ?></p>
<?php endif ?>
- <form method="post" action="<?= $this->url->href('auth', 'check', array('redirect_query' => $redirect_query)) ?>">
+ <?php if (! HIDE_LOGIN_FORM): ?>
+ <form method="post" action="<?= $this->url->href('auth', 'check') ?>">
<?= $this->form->csrf() ?>
@@ -16,17 +17,22 @@
<?= $this->form->checkbox('remember_me', t('Remember Me'), 1, true) ?><br/>
+ <div class="form-actions">
+ <input type="submit" value="<?= t('Sign in') ?>" class="btn btn-blue"/>
+ </div>
+ </form>
+ <?php endif ?>
+
+ <?php if (GOOGLE_AUTH || GITHUB_AUTH): ?>
+ <ul class="no-bullet">
<?php if (GOOGLE_AUTH): ?>
- <?= $this->url->link(t('Login with my Google Account'), 'user', 'google') ?>
+ <li><?= $this->url->link(t('Login with my Google Account'), 'oauth', 'google') ?></li>
<?php endif ?>
<?php if (GITHUB_AUTH): ?>
- <?= $this->url->link(t('Login with my GitHub Account'), 'user', 'gitHub') ?>
+ <li><?= $this->url->link(t('Login with my Github Account'), 'oauth', 'gitHub') ?></li>
<?php endif ?>
-
- <div class="form-actions">
- <input type="submit" value="<?= t('Sign in') ?>" class="btn btn-blue"/>
- </div>
- </form>
+ </ul>
+ <?php endif ?>
</div> \ No newline at end of file
diff --git a/app/Template/board/task_menu.php b/app/Template/board/task_menu.php
index 97c0f8dc..a84b972d 100644
--- a/app/Template/board/task_menu.php
+++ b/app/Template/board/task_menu.php
@@ -9,7 +9,6 @@
<li><i class="fa fa-comment-o"></i> <?= $this->url->link(t('Add a comment'), 'comment', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li>
<li><i class="fa fa-code-fork"></i> <?= $this->url->link(t('Add a link'), 'tasklink', 'create', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li>
<li><i class="fa fa-camera"></i> <?= $this->url->link(t('Add a screenshot'), 'board', 'screenshot', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li>
- <li><i class="fa fa-refresh fa-rotate-90"></i> <?= $this->url->link(t('Edit recurrence'), 'task', 'recurrence', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, 'task-board-popover') ?></li>
<li><i class="fa fa-close"></i> <?= $this->url->link(t('Close this task'), 'task', 'close', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'redirect' => 'board'), false, 'task-board-popover') ?></li>
</ul>
</span>
diff --git a/app/Template/config/integrations.php b/app/Template/config/integrations.php
index 9c80b499..47b45149 100644
--- a/app/Template/config/integrations.php
+++ b/app/Template/config/integrations.php
@@ -6,30 +6,42 @@
<?= $this->form->csrf() ?>
- <h3><img src="assets/img/mailgun-icon.png"/>&nbsp;<?= t('Mailgun (incoming emails)') ?></h3>
+ <h3><i class="fa fa-google"></i> <?= t('Google Authentication') ?></h3>
<div class="listing">
- <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->base().$this->url->href('webhook', 'mailgun', array('token' => $values['webhook_token'])) ?>"/><br/>
+ <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('oauth', 'google', array(), false, '', true) ?>"/><br/>
+ <p class="form-help"><a href="http://kanboard.net/documentation/google-authentication" target="_blank"><?= t('Help on Google authentication') ?></a></p>
+ </div>
+
+ <h3><i class="fa fa-github"></i> <?= t('Github Authentication') ?></h3>
+ <div class="listing">
+ <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('oauth', 'github', array(), false, '', true) ?>"/><br/>
+ <p class="form-help"><a href="http://kanboard.net/documentation/github-authentication" target="_blank"><?= t('Help on Github authentication') ?></a></p>
+ </div>
+
+ <h3><img src="<?= $this->url->dir() ?>assets/img/mailgun-icon.png"/>&nbsp;<?= t('Mailgun (incoming emails)') ?></h3>
+ <div class="listing">
+ <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('webhook', 'mailgun', array('token' => $values['webhook_token']), false, '', true) ?>"/><br/>
<p class="form-help"><a href="http://kanboard.net/documentation/mailgun" target="_blank"><?= t('Help on Mailgun integration') ?></a></p>
</div>
- <h3><img src="assets/img/sendgrid-icon.png"/>&nbsp;<?= t('Sendgrid (incoming emails)') ?></h3>
+ <h3><img src="<?= $this->url->dir() ?>assets/img/sendgrid-icon.png"/>&nbsp;<?= t('Sendgrid (incoming emails)') ?></h3>
<div class="listing">
- <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->base().$this->url->href('webhook', 'sendgrid', array('token' => $values['webhook_token'])) ?>"/><br/>
+ <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('webhook', 'sendgrid', array('token' => $values['webhook_token']), false, '', true) ?>"/><br/>
<p class="form-help"><a href="http://kanboard.net/documentation/sendgrid" target="_blank"><?= t('Help on Sendgrid integration') ?></a></p>
</div>
- <h3><img src="assets/img/postmark-icon.png"/>&nbsp;<?= t('Postmark (incoming emails)') ?></h3>
+ <h3><img src="<?= $this->url->dir() ?>assets/img/postmark-icon.png"/>&nbsp;<?= t('Postmark (incoming emails)') ?></h3>
<div class="listing">
- <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->base().$this->url->href('webhook', 'postmark', array('token' => $values['webhook_token'])) ?>"/><br/>
+ <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('webhook', 'postmark', array('token' => $values['webhook_token']), false, '', true) ?>"/><br/>
<p class="form-help"><a href="http://kanboard.net/documentation/postmark" target="_blank"><?= t('Help on Postmark integration') ?></a></p>
</div>
- <h3><img src="assets/img/gravatar-icon.png"/>&nbsp;<?= t('Gravatar') ?></h3>
+ <h3><img src="<?= $this->url->dir() ?>assets/img/gravatar-icon.png"/>&nbsp;<?= t('Gravatar') ?></h3>
<div class="listing">
<?= $this->form->checkbox('integration_gravatar', t('Enable Gravatar images'), 1, $values['integration_gravatar'] == 1) ?>
</div>
- <h3><img src="assets/img/jabber-icon.png"/> <?= t('Jabber (XMPP)') ?></h3>
+ <h3><img src="<?= $this->url->dir() ?>assets/img/jabber-icon.png"/> <?= t('Jabber (XMPP)') ?></h3>
<div class="listing">
<?= $this->form->checkbox('integration_jabber', t('Send notifications to Jabber'), 1, $values['integration_jabber'] == 1) ?>
@@ -55,7 +67,7 @@
<p class="form-help"><a href="http://kanboard.net/documentation/jabber" target="_blank"><?= t('Help on Jabber integration') ?></a></p>
</div>
- <h3><img src="assets/img/hipchat-icon.png"/> <?= t('Hipchat') ?></h3>
+ <h3><img src="<?= $this->url->dir() ?>assets/img/hipchat-icon.png"/> <?= t('Hipchat') ?></h3>
<div class="listing">
<?= $this->form->checkbox('integration_hipchat', t('Send notifications to Hipchat'), 1, $values['integration_hipchat'] == 1) ?>
diff --git a/app/Template/config/webhook.php b/app/Template/config/webhook.php
index 73ca3598..f1a98f8b 100644
--- a/app/Template/config/webhook.php
+++ b/app/Template/config/webhook.php
@@ -26,7 +26,7 @@
</li>
<li>
<?= t('URL for task creation:') ?>
- <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->base().$this->url->href('webhook', 'task', array('token' => $values['webhook_token'])) ?>">
+ <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('webhook', 'task', array('token' => $values['webhook_token']), false, '', true) ?>">
</li>
<li>
<?= $this->url->link(t('Reset token'), 'config', 'token', array('type' => 'webhook'), true) ?>
diff --git a/app/Template/feed/project.php b/app/Template/feed/project.php
index 60b7ee96..76cf6cf0 100644
--- a/app/Template/feed/project.php
+++ b/app/Template/feed/project.php
@@ -2,15 +2,15 @@
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
<title><?= t('%s\'s activity', $project['name']) ?></title>
<link rel="alternate" type="text/html" href="<?= $this->url->base() ?>"/>
- <link rel="self" type="application/atom+xml" href="<?= $this->url->base().$this->url->href('feed', 'project', array('token' => $project['token'])) ?>"/>
+ <link rel="self" type="application/atom+xml" href="<?= $this->url->href('feed', 'project', array('token' => $project['token']), false, '', true) ?>"/>
<updated><?= date(DATE_ATOM) ?></updated>
- <id><?= $this->url->base().$this->url->href('feed', 'project', array('token' => $project['token'])) ?></id>
+ <id><?= $this->url->href('feed', 'project', array('token' => $project['token']), false, '', true) ?></id>
<icon><?= $this->url->base() ?>assets/img/favicon.png</icon>
<?php foreach ($events as $e): ?>
<entry>
<title type="text"><?= $e['event_title'] ?></title>
- <link rel="alternate" href="<?= $this->url->base().$this->url->href('task', 'show', array('task_id' => $e['task_id'])) ?>"/>
+ <link rel="alternate" href="<?= $this->url->href('task', 'show', array('task_id' => $e['task_id']), false, '', true) ?>"/>
<id><?= $e['id'].'-'.$e['event_name'].'-'.$e['task_id'].'-'.$e['date_creation'] ?></id>
<published><?= date(DATE_ATOM, $e['date_creation']) ?></published>
<updated><?= date(DATE_ATOM, $e['date_creation']) ?></updated>
diff --git a/app/Template/feed/user.php b/app/Template/feed/user.php
index b3279a0c..3e9606c6 100644
--- a/app/Template/feed/user.php
+++ b/app/Template/feed/user.php
@@ -2,15 +2,15 @@
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
<title><?= t('Project activities for %s', $user['name'] ?: $user['username']) ?></title>
<link rel="alternate" type="text/html" href="<?= $this->url->base() ?>"/>
- <link rel="self" type="application/atom+xml" href="<?= $this->url->base().$this->url->href('feed', 'user', array('token' => $user['token'])) ?>"/>
+ <link rel="self" type="application/atom+xml" href="<?= $this->url->href('feed', 'user', array('token' => $user['token']), false, '', true) ?>"/>
<updated><?= date(DATE_ATOM) ?></updated>
- <id><?= $this->url->base().$this->url->href('feed', 'user', array('token' => $user['token'])) ?></id>
+ <id><?= $this->url->href('feed', 'user', array('token' => $user['token']), false, '', true) ?></id>
<icon><?= $this->url->base() ?>assets/img/favicon.png</icon>
<?php foreach ($events as $e): ?>
<entry>
<title type="text"><?= $e['event_title'] ?></title>
- <link rel="alternate" href="<?= $this->url->base().$this->url->href('task', 'show', array('task_id' => $e['task_id'])) ?>"/>
+ <link rel="alternate" href="<?= $this->url->href('task', 'show', array('task_id' => $e['task_id']), false, '', true) ?>"/>
<id><?= $e['id'].'-'.$e['event_name'].'-'.$e['task_id'].'-'.$e['date_creation'] ?></id>
<published><?= date(DATE_ATOM, $e['date_creation']) ?></published>
<updated><?= date(DATE_ATOM, $e['date_creation']) ?></updated>
diff --git a/app/Template/layout.php b/app/Template/layout.php
index a9f1cbc3..d02ba08d 100644
--- a/app/Template/layout.php
+++ b/app/Template/layout.php
@@ -20,11 +20,11 @@
<?= $this->asset->css('assets/css/print.css', true, 'print') ?>
<?= $this->asset->customCss() ?>
- <link rel="icon" type="image/png" href="assets/img/favicon.png">
- <link rel="apple-touch-icon" href="assets/img/touch-icon-iphone.png">
- <link rel="apple-touch-icon" sizes="72x72" href="assets/img/touch-icon-ipad.png">
- <link rel="apple-touch-icon" sizes="114x114" href="assets/img/touch-icon-iphone-retina.png">
- <link rel="apple-touch-icon" sizes="144x144" href="assets/img/touch-icon-ipad-retina.png">
+ <link rel="icon" type="image/png" href="<?= $this->url->dir() ?>assets/img/favicon.png">
+ <link rel="apple-touch-icon" href="<?= $this->url->dir() ?>assets/img/touch-icon-iphone.png">
+ <link rel="apple-touch-icon" sizes="72x72" href="<?= $this->url->dir() ?>assets/img/touch-icon-ipad.png">
+ <link rel="apple-touch-icon" sizes="114x114" href="<?= $this->url->dir() ?>assets/img/touch-icon-iphone-retina.png">
+ <link rel="apple-touch-icon" sizes="144x144" href="<?= $this->url->dir() ?>assets/img/touch-icon-ipad-retina.png">
<title><?= isset($title) ? $this->e($title) : 'Kanboard' ?></title>
</head>
diff --git a/app/Template/listing/show.php b/app/Template/listing/show.php
index 06940678..fc8a607b 100644
--- a/app/Template/listing/show.php
+++ b/app/Template/listing/show.php
@@ -10,13 +10,12 @@
<table class="table-fixed table-small">
<tr>
<th class="column-5"><?= $paginator->order(t('Id'), 'tasks.id') ?></th>
- <th class="column-8"><?= $paginator->order(t('Column'), 'tasks.column_id') ?></th>
- <th class="column-8"><?= $paginator->order(t('Category'), 'tasks.category_id') ?></th>
+ <th class="column-10"><?= $paginator->order(t('Swimlane'), 'tasks.swimlane_id') ?></th>
+ <th class="column-10"><?= $paginator->order(t('Column'), 'tasks.column_id') ?></th>
+ <th class="column-10"><?= $paginator->order(t('Category'), 'tasks.category_id') ?></th>
<th><?= $paginator->order(t('Title'), 'tasks.title') ?></th>
<th class="column-10"><?= $paginator->order(t('Assignee'), 'users.username') ?></th>
<th class="column-10"><?= $paginator->order(t('Due date'), 'tasks.date_due') ?></th>
- <th class="column-10"><?= $paginator->order(t('Date created'), 'tasks.date_creation') ?></th>
- <th class="column-10"><?= $paginator->order(t('Date completed'), 'tasks.date_completed') ?></th>
<th class="column-5"><?= $paginator->order(t('Status'), 'tasks.is_active') ?></th>
</tr>
<?php foreach ($paginator->getCollection() as $task): ?>
@@ -25,6 +24,9 @@
<?= $this->url->link('#'.$this->e($task['id']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, '', t('View this task')) ?>
</td>
<td>
+ <?= $this->e($task['swimlane_name'] ?: $task['default_swimlane']) ?>
+ </td>
+ <td>
<?= $this->e($task['column_name']) ?>
</td>
<td>
@@ -44,14 +46,6 @@
<?= dt('%B %e, %Y', $task['date_due']) ?>
</td>
<td>
- <?= dt('%B %e, %Y', $task['date_creation']) ?>
- </td>
- <td>
- <?php if ($task['date_completed']): ?>
- <?= dt('%B %e, %Y', $task['date_completed']) ?>
- <?php endif ?>
- </td>
- <td>
<?php if ($task['is_active'] == \Model\Task::STATUS_OPEN): ?>
<?= t('Open') ?>
<?php else: ?>
diff --git a/app/Template/notification/footer.php b/app/Template/notification/footer.php
index 69d2cf82..c3b37884 100644
--- a/app/Template/notification/footer.php
+++ b/app/Template/notification/footer.php
@@ -2,6 +2,6 @@
Kanboard
<?php if (isset($application_url) && ! empty($application_url)): ?>
- - <a href="<?= $application_url.$this->url->href('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><?= t('view the task on Kanboard') ?></a>
- - <a href="<?= $application_url.$this->url->href('board', 'show', array('project_id' => $task['project_id'])) ?>"><?= t('view the board on Kanboard') ?></a>
+ - <a href="<?= $this->url->href('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, '', true) ?>"><?= t('view the task on Kanboard') ?></a>
+ - <a href="<?= $this->url->href('board', 'show', array('project_id' => $task['project_id']), false, '', true) ?>"><?= t('view the board on Kanboard') ?></a>
<?php endif ?>
diff --git a/app/Template/notification/task_overdue.php b/app/Template/notification/task_overdue.php
index dc2659dc..a231937b 100644
--- a/app/Template/notification/task_overdue.php
+++ b/app/Template/notification/task_overdue.php
@@ -5,7 +5,7 @@
<li>
(<strong>#<?= $task['id'] ?></strong>)
<?php if ($application_url): ?>
- <a href="<?= $application_url.$this->url->href('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>"><?= $this->e($task['title']) ?></a>
+ <a href="<?= $this->url->href('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, '', true) ?>"><?= $this->e($task['title']) ?></a>
<?php else: ?>
<?= $this->e($task['title']) ?>
<?php endif ?>
diff --git a/app/Template/project/filters.php b/app/Template/project/filters.php
index 3beb2f44..e2fdc751 100644
--- a/app/Template/project/filters.php
+++ b/app/Template/project/filters.php
@@ -5,13 +5,14 @@
<ul>
<?php if (isset($is_board)): ?>
<li>
- <?php if ($this->board->isCollapsed($project['id'])): ?>
+ <span class="filter-display-mode" <?= $this->board->isCollapsed($project['id']) ? '' : 'style="display: none;"' ?>>
<i class="fa fa-expand fa-fw"></i>
<?= $this->url->link(t('Expand tasks'), 'board', 'expand', array('project_id' => $project['id']), false, 'board-display-mode', t('Keyboard shortcut: "%s"', 's')) ?>
- <?php else: ?>
+ </span>
+ <span class="filter-display-mode" <?= $this->board->isCollapsed($project['id']) ? 'style="display: none;"' : '' ?>>
<i class="fa fa-compress fa-fw"></i>
<?= $this->url->link(t('Collapse tasks'), 'board', 'collapse', array('project_id' => $project['id']), false, 'board-display-mode', t('Keyboard shortcut: "%s"', 's')) ?>
- <?php endif ?>
+ </span>
</li>
<li>
<span class="filter-compact">
@@ -40,10 +41,10 @@
<?= $this->url->link(t('List'), 'listing', 'show', array('project_id' => $project['id'], 'search' => $filters['search']), false, 'view-listing', t('Keyboard shortcut: "%s"', 'v l')) ?>
</li>
</ul>
- <form method="get" action="?" class="search">
- <?= $this->form->hidden('project_id', $filters) ?>
+ <form method="get" action="<?= $this->url->dir() ?>" class="search">
<?= $this->form->hidden('controller', $filters) ?>
<?= $this->form->hidden('action', $filters) ?>
+ <?= $this->form->hidden('project_id', $filters) ?>
<?= $this->form->text('search', $filters, array(), array('placeholder="'.t('Filter').'"'), 'form-input-large') ?>
</form>
<?= $this->render('app/filters_helper', array('reset' => 'status:open')) ?>
diff --git a/app/Template/project/integrations.php b/app/Template/project/integrations.php
index 445e7bfb..12a7ee4e 100644
--- a/app/Template/project/integrations.php
+++ b/app/Template/project/integrations.php
@@ -8,26 +8,26 @@
<h3><i class="fa fa-github fa-fw"></i>&nbsp;<?= t('Github webhooks') ?></h3>
<div class="listing">
- <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->base().$this->url->href('webhook', 'github', array('token' => $webhook_token, 'project_id' => $project['id'])) ?>"/><br/>
+ <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('webhook', 'github', array('token' => $webhook_token, 'project_id' => $project['id']), false, '', true) ?>"/><br/>
<p class="form-help"><a href="http://kanboard.net/documentation/github-webhooks" target="_blank"><?= t('Help on Github webhooks') ?></a></p>
</div>
- <h3><img src="assets/img/gitlab-icon.png"/>&nbsp;<?= t('Gitlab webhooks') ?></h3>
+ <h3><img src="<?= $this->url->dir() ?>assets/img/gitlab-icon.png"/>&nbsp;<?= t('Gitlab webhooks') ?></h3>
<div class="listing">
- <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->base().$this->url->href('webhook', 'gitlab', array('token' => $webhook_token, 'project_id' => $project['id'])) ?>"/><br/>
+ <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('webhook', 'gitlab', array('token' => $webhook_token, 'project_id' => $project['id']), false, '', true) ?>"/><br/>
<p class="form-help"><a href="http://kanboard.net/documentation/gitlab-webhooks" target="_blank"><?= t('Help on Gitlab webhooks') ?></a></p>
</div>
<h3><i class="fa fa-bitbucket fa-fw"></i>&nbsp;<?= t('Bitbucket webhooks') ?></h3>
<div class="listing">
- <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->base().$this->url->href('webhook', 'bitbucket', array('token' => $webhook_token, 'project_id' => $project['id'])) ?>"/><br/>
+ <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('webhook', 'bitbucket', array('token' => $webhook_token, 'project_id' => $project['id']), false, '', true) ?>"/><br/>
<p class="form-help"><a href="http://kanboard.net/documentation/bitbucket-webhooks" target="_blank"><?= t('Help on Bitbucket webhooks') ?></a></p>
</div>
- <h3><img src="assets/img/jabber-icon.png"/> <?= t('Jabber (XMPP)') ?></h3>
+ <h3><img src="<?= $this->url->dir() ?>assets/img/jabber-icon.png"/> <?= t('Jabber (XMPP)') ?></h3>
<div class="listing">
<?= $this->form->checkbox('jabber', t('Send notifications to Jabber'), 1, isset($values['jabber']) && $values['jabber'] == 1) ?>
@@ -58,7 +58,7 @@
</div>
- <h3><img src="assets/img/hipchat-icon.png"/> <?= t('Hipchat') ?></h3>
+ <h3><img src="<?= $this->url->dir() ?>assets/img/hipchat-icon.png"/> <?= t('Hipchat') ?></h3>
<div class="listing">
<?= $this->form->checkbox('hipchat', t('Send notifications to Hipchat'), 1, isset($values['hipchat']) && $values['hipchat'] == 1) ?>
diff --git a/app/Template/search/index.php b/app/Template/search/index.php
index 3d0d6ff9..8940a24e 100644
--- a/app/Template/search/index.php
+++ b/app/Template/search/index.php
@@ -9,7 +9,7 @@
</div>
<div class="search">
- <form method="get" action="?" class="search">
+ <form method="get" action="<?= $this->url->dir() ?>" class="search">
<?= $this->form->hidden('controller', $values) ?>
<?= $this->form->hidden('action', $values) ?>
<?= $this->form->text('search', $values, array(), array(empty($values['search']) ? 'autofocus' : '', 'placeholder="'.t('Search').'"'), 'form-input-large') ?>
diff --git a/app/Template/search/results.php b/app/Template/search/results.php
index 1d8cc6e2..04cb6a19 100644
--- a/app/Template/search/results.php
+++ b/app/Template/search/results.php
@@ -1,14 +1,13 @@
<table class="table-fixed table-small">
<tr>
<th class="column-8"><?= $paginator->order(t('Project'), 'tasks.project_id') ?></th>
- <th class="column-8"><?= $paginator->order(t('Id'), 'tasks.id') ?></th>
- <th class="column-8"><?= $paginator->order(t('Column'), 'tasks.column_id') ?></th>
- <th class="column-8"><?= $paginator->order(t('Category'), 'tasks.category_id') ?></th>
+ <th class="column-5"><?= $paginator->order(t('Id'), 'tasks.id') ?></th>
+ <th class="column-10"><?= $paginator->order(t('Swimlane'), 'tasks.swimlane_id') ?></th>
+ <th class="column-10"><?= $paginator->order(t('Column'), 'tasks.column_id') ?></th>
+ <th class="column-10"><?= $paginator->order(t('Category'), 'tasks.category_id') ?></th>
<th><?= $paginator->order(t('Title'), 'tasks.title') ?></th>
<th class="column-10"><?= $paginator->order(t('Assignee'), 'users.username') ?></th>
<th class="column-10"><?= $paginator->order(t('Due date'), 'tasks.date_due') ?></th>
- <th class="column-10"><?= $paginator->order(t('Date created'), 'tasks.date_creation') ?></th>
- <th class="column-10"><?= $paginator->order(t('Date completed'), 'tasks.date_completed') ?></th>
<th class="column-5"><?= $paginator->order(t('Status'), 'tasks.is_active') ?></th>
</tr>
<?php foreach ($paginator->getCollection() as $task): ?>
@@ -20,6 +19,9 @@
<?= $this->url->link('#'.$this->e($task['id']), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), false, '', t('View this task')) ?>
</td>
<td>
+ <?= $this->e($task['swimlane_name'] ?: $task['default_swimlane']) ?>
+ </td>
+ <td>
<?= $this->e($task['column_name']) ?>
</td>
<td>
@@ -39,14 +41,6 @@
<?= dt('%B %e, %Y', $task['date_due']) ?>
</td>
<td>
- <?= dt('%B %e, %Y', $task['date_creation']) ?>
- </td>
- <td>
- <?php if ($task['date_completed']): ?>
- <?= dt('%B %e, %Y', $task['date_completed']) ?>
- <?php endif ?>
- </td>
- <td>
<?php if ($task['is_active'] == \Model\Task::STATUS_OPEN): ?>
<?= t('Open') ?>
<?php else: ?>
diff --git a/app/Template/task/edit_recurrence.php b/app/Template/task/edit_recurrence.php
index c261e368..e7c4c8f8 100644
--- a/app/Template/task/edit_recurrence.php
+++ b/app/Template/task/edit_recurrence.php
@@ -15,7 +15,7 @@
<?php if ($task['recurrence_status'] != \Model\Task::RECURRING_STATUS_PROCESSED): ?>
- <form method="post" action="<?= $this->url->href('task', 'recurrence', array('task_id' => $task['id'], 'project_id' => $task['project_id'], 'ajax' => $ajax)) ?>" autocomplete="off">
+ <form method="post" action="<?= $this->url->href('task', 'recurrence', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>" autocomplete="off">
<?= $this->form->csrf() ?>
@@ -40,12 +40,7 @@
<div class="form-actions">
<input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
<?= t('or') ?>
-
- <?php if ($ajax): ?>
- <?= $this->url->link(t('cancel'), 'board', 'show', array('project_id' => $task['project_id'])) ?>
- <?php else: ?>
- <?= $this->url->link(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
- <?php endif ?>
+ <?= $this->url->link(t('cancel'), 'task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
</div>
</form>
diff --git a/app/Template/user/authentication.php b/app/Template/user/authentication.php
new file mode 100644
index 00000000..a62c8f93
--- /dev/null
+++ b/app/Template/user/authentication.php
@@ -0,0 +1,32 @@
+<div class="page-header">
+ <h2><?= t('Edit Authentication') ?></h2>
+</div>
+<form method="post" action="<?= $this->url->href('user', 'authentication', array('user_id' => $user['id'])) ?>" autocomplete="off">
+
+ <?= $this->form->csrf() ?>
+
+ <?= $this->form->hidden('id', $values) ?>
+ <?= $this->form->hidden('username', $values) ?>
+
+ <?= $this->form->label(t('Google Id'), 'google_id') ?>
+ <?= $this->form->text('google_id', $values, $errors) ?>
+
+ <?= $this->form->label(t('Github Id'), 'github_id') ?>
+ <?= $this->form->text('github_id', $values, $errors) ?>
+
+ <?= $this->form->checkbox('is_ldap_user', t('Remote user'), 1, isset($values['is_ldap_user']) && $values['is_ldap_user'] == 1) ?>
+ <?= $this->form->checkbox('disable_login_form', t('Disallow login form'), 1, isset($values['disable_login_form']) && $values['disable_login_form'] == 1) ?>
+
+ <div class="form-actions">
+ <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
+ <?= t('or') ?>
+ <?= $this->url->link(t('cancel'), 'user', 'show', array('user_id' => $user['id'])) ?>
+ </div>
+
+ <div class="alert alert-info">
+ <ul>
+ <li><?= t('Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.') ?></li>
+ <li><?= t('If you check the box "Disallow login form", credentials entered in the login form will be ignored.') ?></li>
+ </ul>
+ </div>
+</form> \ No newline at end of file
diff --git a/app/Template/user/new.php b/app/Template/user/create_local.php
index 0db1e824..aeec300f 100644
--- a/app/Template/user/new.php
+++ b/app/Template/user/create_local.php
@@ -2,6 +2,7 @@
<div class="page-header">
<ul>
<li><i class="fa fa-user fa-fw"></i><?= $this->url->link(t('All users'), 'user', 'index') ?></li>
+ <li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('New remote user'), 'user', 'create', array('remote' => 1)) ?></li>
</ul>
</div>
<section>
diff --git a/app/Template/user/create_remote.php b/app/Template/user/create_remote.php
new file mode 100644
index 00000000..52661585
--- /dev/null
+++ b/app/Template/user/create_remote.php
@@ -0,0 +1,57 @@
+<section id="main">
+ <div class="page-header">
+ <ul>
+ <li><i class="fa fa-user fa-fw"></i><?= $this->url->link(t('All users'), 'user', 'index') ?></li>
+ <li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('New local user'), 'user', 'create') ?></li>
+ </ul>
+ </div>
+ <form method="post" action="<?= $this->url->href('user', 'save') ?>" autocomplete="off">
+
+ <?= $this->form->csrf() ?>
+ <?= $this->form->hidden('is_ldap_user', array('is_ldap_user' => 1)) ?>
+
+ <div class="form-column">
+ <?= $this->form->label(t('Username'), 'username') ?>
+ <?= $this->form->text('username', $values, $errors, array('autofocus', 'required', 'maxlength="50"')) ?><br/>
+
+ <?= $this->form->label(t('Name'), 'name') ?>
+ <?= $this->form->text('name', $values, $errors) ?><br/>
+
+ <?= $this->form->label(t('Email'), 'email') ?>
+ <?= $this->form->email('email', $values, $errors) ?><br/>
+
+ <?= $this->form->label(t('Google Id'), 'google_id') ?>
+ <?= $this->form->password('google_id', $values, $errors) ?><br/>
+
+ <?= $this->form->label(t('Github Id'), 'github_id') ?>
+ <?= $this->form->password('github_id', $values, $errors) ?><br/>
+ </div>
+
+ <div class="form-column">
+ <?= $this->form->label(t('Add project member'), 'project_id') ?>
+ <?= $this->form->select('project_id', $projects, $values, $errors) ?><br/>
+
+ <?= $this->form->label(t('Timezone'), 'timezone') ?>
+ <?= $this->form->select('timezone', $timezones, $values, $errors) ?><br/>
+
+ <?= $this->form->label(t('Language'), 'language') ?>
+ <?= $this->form->select('language', $languages, $values, $errors) ?><br/>
+
+ <?= $this->form->checkbox('notifications_enabled', t('Enable notifications'), 1, isset($values['notifications_enabled']) && $values['notifications_enabled'] == 1 ? true : false) ?>
+ <?= $this->form->checkbox('is_admin', t('Administrator'), 1, isset($values['is_admin']) && $values['is_admin'] == 1 ? true : false) ?>
+ <?= $this->form->checkbox('disable_login_form', t('Disallow login form'), 1, isset($values['disable_login_form']) && $values['disable_login_form'] == 1) ?>
+ </div>
+
+ <div class="form-actions">
+ <input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
+ <?= t('or') ?>
+ <?= $this->url->link(t('cancel'), 'user', 'index') ?>
+ </div>
+ </form>
+ <div class="alert alert-info">
+ <ul>
+ <li><?= t('Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.') ?></li>
+ <li><?= t('If you check the box "Disallow login form", credentials entered in the login form will be ignored.') ?></li>
+ </ul>
+ </div>
+</section> \ No newline at end of file
diff --git a/app/Template/user/edit.php b/app/Template/user/edit.php
index 2462308f..ea7e3875 100644
--- a/app/Template/user/edit.php
+++ b/app/Template/user/edit.php
@@ -6,7 +6,6 @@
<?= $this->form->csrf() ?>
<?= $this->form->hidden('id', $values) ?>
- <?= $this->form->hidden('is_ldap_user', $values) ?>
<?= $this->form->label(t('Username'), 'username') ?>
<?= $this->form->text('username', $values, $errors, array('required', $values['is_ldap_user'] == 1 ? 'readonly' : '', 'maxlength="50"')) ?><br/>
@@ -23,13 +22,9 @@
<?= $this->form->label(t('Language'), 'language') ?>
<?= $this->form->select('language', $languages, $values, $errors) ?><br/>
- <div class="alert alert-error">
- <?= $this->form->checkbox('disable_login_form', t('Disable login form'), 1, isset($values['disable_login_form']) && $values['disable_login_form'] == 1) ?><br/>
-
- <?php if ($this->user->isAdmin()): ?>
- <?= $this->form->checkbox('is_admin', t('Administrator'), 1, isset($values['is_admin']) && $values['is_admin'] == 1) ?><br/>
- <?php endif ?>
- </div>
+ <?php if ($this->user->isAdmin()): ?>
+ <?= $this->form->checkbox('is_admin', t('Administrator'), 1, isset($values['is_admin']) && $values['is_admin'] == 1) ?><br/>
+ <?php endif ?>
<div class="form-actions">
<input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
diff --git a/app/Template/user/external.php b/app/Template/user/external.php
index df85ace7..3b872e85 100644
--- a/app/Template/user/external.php
+++ b/app/Template/user/external.php
@@ -8,9 +8,9 @@
<p class="listing">
<?php if ($this->user->isCurrentUser($user['id'])): ?>
<?php if (empty($user['google_id'])): ?>
- <?= $this->url->link(t('Link my Google Account'), 'user', 'google', array(), true) ?>
+ <?= $this->url->link(t('Link my Google Account'), 'oauth', 'google', array(), true) ?>
<?php else: ?>
- <?= $this->url->link(t('Unlink my Google Account'), 'user', 'unlinkGoogle', array(), true) ?>
+ <?= $this->url->link(t('Unlink my Google Account'), 'oauth', 'unlink', array('backend' => 'google'), true) ?>
<?php endif ?>
<?php else: ?>
<?= empty($user['google_id']) ? t('No account linked.') : t('Account linked.') ?>
@@ -24,9 +24,9 @@
<p class="listing">
<?php if ($this->user->isCurrentUser($user['id'])): ?>
<?php if (empty($user['github_id'])): ?>
- <?= $this->url->link(t('Link my GitHub Account'), 'user', 'github', array(), true) ?>
+ <?= $this->url->link(t('Link my Github Account'), 'oauth', 'github', array(), true) ?>
<?php else: ?>
- <?= $this->url->link(t('Unlink my GitHub Account'), 'user', 'unlinkGitHub', array(), true) ?>
+ <?= $this->url->link(t('Unlink my Github Account'), 'oauth', 'unlink', array('backend' => 'github'), true) ?>
<?php endif ?>
<?php else: ?>
<?= empty($user['github_id']) ? t('No account linked.') : t('Account linked.') ?>
diff --git a/app/Template/user/index.php b/app/Template/user/index.php
index fc575466..edf043a6 100644
--- a/app/Template/user/index.php
+++ b/app/Template/user/index.php
@@ -2,7 +2,8 @@
<div class="page-header">
<?php if ($this->user->isAdmin()): ?>
<ul>
- <li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('New user'), 'user', 'create') ?></li>
+ <li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('New local user'), 'user', 'create') ?></li>
+ <li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('New remote user'), 'user', 'create', array('remote' => 1)) ?></li>
</ul>
<?php endif ?>
</div>
diff --git a/app/Template/user/layout.php b/app/Template/user/layout.php
index e60ab77d..a27f359b 100644
--- a/app/Template/user/layout.php
+++ b/app/Template/user/layout.php
@@ -3,7 +3,8 @@
<?php if ($this->user->isAdmin()): ?>
<ul>
<li><i class="fa fa-user fa-fw"></i><?= $this->url->link(t('All users'), 'user', 'index') ?></li>
- <li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('New user'), 'user', 'create') ?></li>
+ <li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('New local user'), 'user', 'create') ?></li>
+ <li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('New remote user'), 'user', 'create', array('remote' => 1)) ?></li>
</ul>
<?php endif ?>
</div>
diff --git a/app/Template/user/sidebar.php b/app/Template/user/sidebar.php
index e61a43bf..3e79fda3 100644
--- a/app/Template/user/sidebar.php
+++ b/app/Template/user/sidebar.php
@@ -58,6 +58,9 @@
<?php if ($this->user->isAdmin()): ?>
<li>
+ <?= $this->url->link(t('Edit Authentication'), 'user', 'authentication', array('user_id' => $user['id'])) ?>
+ </li>
+ <li>
<?= $this->url->link(t('Hourly rates'), 'hourlyrate', 'index', array('user_id' => $user['id'])) ?>
</li>
<li>
diff --git a/app/common.php b/app/common.php
index b5871673..734f094b 100644
--- a/app/common.php
+++ b/app/common.php
@@ -12,7 +12,7 @@ if (getenv('DATABASE_URL')) {
define('DB_PASSWORD', $dbopts["pass"]);
define('DB_HOSTNAME', $dbopts["host"]);
define('DB_PORT', isset($dbopts["port"]) ? $dbopts["port"] : null);
- define('DB_NAME', ltrim($dbopts["path"],'/'));
+ define('DB_NAME', ltrim($dbopts["path"], '/'));
}
// Include custom config file
@@ -28,3 +28,97 @@ $container->register(new ServiceProvider\LoggingProvider);
$container->register(new ServiceProvider\DatabaseProvider);
$container->register(new ServiceProvider\ClassProvider);
$container->register(new ServiceProvider\EventDispatcherProvider);
+
+if (ENABLE_URL_REWRITE) {
+
+ // Dashboard
+ $container['router']->addRoute('dashboard', 'app', 'index');
+ $container['router']->addRoute('dashboard/:user_id', 'app', 'index', array('user_id'));
+ $container['router']->addRoute('dashboard/:user_id/projects', 'app', 'projects', array('user_id'));
+ $container['router']->addRoute('dashboard/:user_id/tasks', 'app', 'tasks', array('user_id'));
+ $container['router']->addRoute('dashboard/:user_id/subtasks', 'app', 'subtasks', array('user_id'));
+ $container['router']->addRoute('dashboard/:user_id/calendar', 'app', 'calendar', array('user_id'));
+ $container['router']->addRoute('dashboard/:user_id/activity', 'app', 'activity', array('user_id'));
+
+ // Search routes
+ $container['router']->addRoute('search', 'search', 'index');
+ $container['router']->addRoute('search/:search', 'search', 'index', array('search'));
+
+ // Project routes
+ $container['router']->addRoute('projects', 'project', 'index');
+ $container['router']->addRoute('project/create', 'project', 'create');
+ $container['router']->addRoute('project/create/:private', 'project', 'create', array('private'));
+ $container['router']->addRoute('project/:project_id', 'project', 'show', array('project_id'));
+ $container['router']->addRoute('p/:project_id', 'project', 'show', array('project_id'));
+ $container['router']->addRoute('project/:project_id/share', 'project', 'share', array('project_id'));
+ $container['router']->addRoute('project/:project_id/edit', 'project', 'edit', array('project_id'));
+ $container['router']->addRoute('project/:project_id/integration', 'project', 'integration', array('project_id'));
+ $container['router']->addRoute('project/:project_id/users', 'project', 'users', array('project_id'));
+ $container['router']->addRoute('project/:project_id/duplicate', 'project', 'duplicate', array('project_id'));
+ $container['router']->addRoute('project/:project_id/remove', 'project', 'remove', array('project_id'));
+ $container['router']->addRoute('project/:project_id/disable', 'project', 'disable', array('project_id'));
+ $container['router']->addRoute('project/:project_id/enable', 'project', 'enable', array('project_id'));
+
+ // Action routes
+ $container['router']->addRoute('project/:project_id/actions', 'action', 'index', array('project_id'));
+ $container['router']->addRoute('project/:project_id/action/:action_id/confirm', 'action', 'confirm', array('project_id', 'action_id'));
+
+ // Column routes
+ $container['router']->addRoute('project/:project_id/columns', 'column', 'index', array('project_id'));
+ $container['router']->addRoute('project/:project_id/column/:column_id/edit', 'column', 'edit', array('project_id', 'column_id'));
+ $container['router']->addRoute('project/:project_id/column/:column_id/confirm', 'column', 'confirm', array('project_id', 'column_id'));
+ $container['router']->addRoute('project/:project_id/column/:column_id/move/:direction', 'column', 'move', array('project_id', 'column_id', 'direction'));
+
+ // Swimlane routes
+ $container['router']->addRoute('project/:project_id/swimlanes', 'swimlane', 'index', array('project_id'));
+ $container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/edit', 'swimlane', 'edit', array('project_id', 'swimlane_id'));
+ $container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/confirm', 'swimlane', 'confirm', array('project_id', 'swimlane_id'));
+ $container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/disable', 'swimlane', 'disable', array('project_id', 'swimlane_id'));
+ $container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/enable', 'swimlane', 'enable', array('project_id', 'swimlane_id'));
+ $container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/up', 'swimlane', 'moveup', array('project_id', 'swimlane_id'));
+ $container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/down', 'swimlane', 'movedown', array('project_id', 'swimlane_id'));
+
+ // Category routes
+ $container['router']->addRoute('project/:project_id/categories', 'category', 'index', array('project_id'));
+ $container['router']->addRoute('project/:project_id/category/:category_id/edit', 'category', 'edit', array('project_id', 'category_id'));
+ $container['router']->addRoute('project/:project_id/category/:category_id/confirm', 'category', 'confirm', array('project_id', 'category_id'));
+
+ // Task routes
+ $container['router']->addRoute('project/:project_id/task/:task_id', 'task', 'show', array('project_id', 'task_id'));
+ $container['router']->addRoute('t/:task_id', 'task', 'show', array('task_id'));
+ $container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/column/:column_id', 'task', 'create', array('project_id', 'swimlane_id', 'column_id'));
+ $container['router']->addRoute('public/task/:task_id/:token', 'task', 'readonly', array('task_id', 'token'));
+
+ // Board routes
+ $container['router']->addRoute('board/:project_id', 'board', 'show', array('project_id'));
+ $container['router']->addRoute('b/:project_id', 'board', 'show', array('project_id'));
+ $container['router']->addRoute('board/:project_id/filter/:search', 'board', 'show', array('project_id', 'search'));
+ $container['router']->addRoute('public/board/:token', 'board', 'readonly', array('token'));
+
+ // Calendar routes
+ $container['router']->addRoute('calendar/:project_id', 'calendar', 'show', array('project_id'));
+ $container['router']->addRoute('c/:project_id', 'calendar', 'show', array('project_id'));
+ $container['router']->addRoute('calendar/:project_id/:search', 'calendar', 'show', array('project_id', 'search'));
+
+ // Listing routes
+ $container['router']->addRoute('list/:project_id', 'listing', 'show', array('project_id'));
+ $container['router']->addRoute('l/:project_id', 'listing', 'show', array('project_id'));
+ $container['router']->addRoute('list/:project_id/:search', 'listing', 'show', array('project_id', 'search'));
+
+ // Subtask routes
+ $container['router']->addRoute('project/:project_id/task/:task_id/subtask/:subtask_id', 'subtask', 'remove', array('project_id', 'task_id', 'subtask_id'));
+
+ // Feed routes
+ $container['router']->addRoute('feed/project/:token', 'feed', 'project', array('token'));
+ $container['router']->addRoute('feed/user/:token', 'feed', 'user', array('token'));
+
+ // Ical routes
+ $container['router']->addRoute('ical/project/:token', 'ical', 'project', array('token'));
+ $container['router']->addRoute('ical/user/:token', 'ical', 'user', array('token'));
+
+ // Auth routes
+ $container['router']->addRoute('oauth/google', 'oauth', 'google');
+ $container['router']->addRoute('oauth/github', 'oauth', 'github');
+ $container['router']->addRoute('login', 'auth', 'login');
+ $container['router']->addRoute('logout', 'auth', 'logout');
+}
diff --git a/app/constants.php b/app/constants.php
index 9b66b746..83fba468 100644
--- a/app/constants.php
+++ b/app/constants.php
@@ -7,9 +7,6 @@ defined('DEBUG_FILE') or define('DEBUG_FILE', __DIR__.'/../data/debug.log');
// Application version
defined('APP_VERSION') or define('APP_VERSION', 'master');
-// Base directory
-define('BASE_URL_DIRECTORY', dirname($_SERVER['PHP_SELF']));
-
// Database driver: sqlite, mysql or postgres
defined('DB_DRIVER') or define('DB_DRIVER', 'sqlite');
@@ -38,13 +35,14 @@ defined('LDAP_ACCOUNT_FULLNAME') or define('LDAP_ACCOUNT_FULLNAME', 'displayname
defined('LDAP_ACCOUNT_EMAIL') or define('LDAP_ACCOUNT_EMAIL', 'mail');
defined('LDAP_ACCOUNT_ID') or define('LDAP_ACCOUNT_ID', '');
defined('LDAP_USERNAME_CASE_SENSITIVE') or define('LDAP_USERNAME_CASE_SENSITIVE', false);
+defined('LDAP_ACCOUNT_CREATION') or define('LDAP_ACCOUNT_CREATION', true);
// Google authentication
defined('GOOGLE_AUTH') or define('GOOGLE_AUTH', false);
defined('GOOGLE_CLIENT_ID') or define('GOOGLE_CLIENT_ID', '');
defined('GOOGLE_CLIENT_SECRET') or define('GOOGLE_CLIENT_SECRET', '');
-// GitHub authentication
+// Github authentication
defined('GITHUB_AUTH') or define('GITHUB_AUTH', false);
defined('GITHUB_CLIENT_ID') or define('GITHUB_CLIENT_ID', '');
defined('GITHUB_CLIENT_SECRET') or define('GITHUB_CLIENT_SECRET', '');
@@ -84,3 +82,9 @@ defined('MARKDOWN_ESCAPE_HTML') or define('MARKDOWN_ESCAPE_HTML', true);
// API alternative authentication header, the default is HTTP Basic Authentication defined in RFC2617
defined('API_AUTHENTICATION_HEADER') or define('API_AUTHENTICATION_HEADER', '');
+
+// Enable/disable url rewrite
+defined('ENABLE_URL_REWRITE') or define('ENABLE_URL_REWRITE', isset($_SERVER['HTTP_MOD_REWRITE']));
+
+// Hide login form
+defined('HIDE_LOGIN_FORM') or define('HIDE_LOGIN_FORM', false);