mirror of
https://github.com/YunoHost-Apps/kanboard_ynh.git
synced 2024-09-03 19:36:17 +02:00
Update kanboard v1.0.9
This commit is contained in:
parent
edc1a3fb31
commit
400ba25516
319 changed files with 10599 additions and 15353 deletions
57
sources/.gitignore
vendored
57
sources/.gitignore
vendored
|
@ -1,57 +0,0 @@
|
||||||
# Compiled source #
|
|
||||||
###################
|
|
||||||
*.com
|
|
||||||
*.class
|
|
||||||
*.dll
|
|
||||||
*.exe
|
|
||||||
*.o
|
|
||||||
*.so
|
|
||||||
*.pyc
|
|
||||||
|
|
||||||
# Packages #
|
|
||||||
############
|
|
||||||
# it's better to unpack these files and commit the raw source
|
|
||||||
# git has its own built in compression methods
|
|
||||||
*.7z
|
|
||||||
*.dmg
|
|
||||||
*.gz
|
|
||||||
*.iso
|
|
||||||
*.jar
|
|
||||||
*.rar
|
|
||||||
*.tar
|
|
||||||
*.zip
|
|
||||||
|
|
||||||
# Logs and databases #
|
|
||||||
######################
|
|
||||||
*.log
|
|
||||||
*.sql
|
|
||||||
*.sqlite
|
|
||||||
*.sqlite-journal
|
|
||||||
|
|
||||||
# IDE generated files #
|
|
||||||
######################
|
|
||||||
.buildpath
|
|
||||||
.project
|
|
||||||
/.settings/
|
|
||||||
.idea
|
|
||||||
|
|
||||||
# OS generated files #
|
|
||||||
######################
|
|
||||||
.DS_Store
|
|
||||||
ehthumbs.db
|
|
||||||
Icon?
|
|
||||||
Thumbs.db
|
|
||||||
*.swp
|
|
||||||
.*.swp
|
|
||||||
*~
|
|
||||||
*.lock
|
|
||||||
*.out
|
|
||||||
|
|
||||||
# Vagrant #
|
|
||||||
###########
|
|
||||||
.vagrant
|
|
||||||
|
|
||||||
# App specific #
|
|
||||||
################
|
|
||||||
#config.php
|
|
||||||
#data/files
|
|
|
@ -1,53 +0,0 @@
|
||||||
filter:
|
|
||||||
excluded_paths:
|
|
||||||
- 'vendor/*'
|
|
||||||
- 'tests/*'
|
|
||||||
- 'app/Templates/*'
|
|
||||||
paths: { }
|
|
||||||
tools:
|
|
||||||
php_sim:
|
|
||||||
enabled: true
|
|
||||||
min_mass: 16
|
|
||||||
filter:
|
|
||||||
excluded_paths:
|
|
||||||
- 'vendor/*'
|
|
||||||
- 'tests/*'
|
|
||||||
- 'app/Templates/*'
|
|
||||||
paths: { }
|
|
||||||
php_pdepend:
|
|
||||||
enabled: true
|
|
||||||
configuration_file: null
|
|
||||||
suffixes:
|
|
||||||
- php
|
|
||||||
excluded_dirs: { }
|
|
||||||
filter:
|
|
||||||
excluded_paths:
|
|
||||||
- 'vendor/*'
|
|
||||||
- 'tests/*'
|
|
||||||
- 'app/Templates/*'
|
|
||||||
paths: { }
|
|
||||||
php_analyzer:
|
|
||||||
enabled: true
|
|
||||||
extensions:
|
|
||||||
- php
|
|
||||||
dependency_paths: { }
|
|
||||||
filter:
|
|
||||||
excluded_paths:
|
|
||||||
- 'vendor/*'
|
|
||||||
- 'tests/*'
|
|
||||||
- 'app/Templates/*'
|
|
||||||
paths: { }
|
|
||||||
path_configs: { }
|
|
||||||
php_changetracking:
|
|
||||||
enabled: true
|
|
||||||
bug_patterns:
|
|
||||||
- '\bfix(?:es|ed)?\b'
|
|
||||||
feature_patterns:
|
|
||||||
- '\badd(?:s|ed)?\b'
|
|
||||||
- '\bimplement(?:s|ed)?\b'
|
|
||||||
filter:
|
|
||||||
excluded_paths:
|
|
||||||
- 'vendor/*'
|
|
||||||
- 'tests/*'
|
|
||||||
- 'app/Templates/*'
|
|
||||||
paths: { }
|
|
|
@ -1,10 +0,0 @@
|
||||||
language: php
|
|
||||||
|
|
||||||
php:
|
|
||||||
- "5.6"
|
|
||||||
- "5.5"
|
|
||||||
- "5.4"
|
|
||||||
- "5.3"
|
|
||||||
|
|
||||||
before_script: wget https://phar.phpunit.de/phpunit.phar
|
|
||||||
script: php phpunit.phar -c tests/units.sqlite.xml
|
|
|
@ -1,165 +0,0 @@
|
||||||
Kanboard
|
|
||||||
========
|
|
||||||
|
|
||||||
Kanboard is a simple visual task board web application.
|
|
||||||
|
|
||||||
Official website: <http://kanboard.net>
|
|
||||||
|
|
||||||
- Inspired by the [Kanban methodology](http://en.wikipedia.org/wiki/Kanban)
|
|
||||||
- Get a visual and clear overview of your project
|
|
||||||
- Multiple boards with the ability to drag and drop tasks
|
|
||||||
- Minimalist software, focus only on essential features (Less is more)
|
|
||||||
- Open source and self-hosted
|
|
||||||
- Super simple installation
|
|
||||||
|
|
||||||
[![Build Status](https://travis-ci.org/fguillot/kanboard.svg)](https://travis-ci.org/fguillot/kanboard)
|
|
||||||
|
|
||||||
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/fguillot/kanboard/badges/quality-score.png?s=2b6490781608657cc8c43d02285bfafb4f489528)](https://scrutinizer-ci.com/g/fguillot/kanboard/)
|
|
||||||
|
|
||||||
Features
|
|
||||||
--------
|
|
||||||
|
|
||||||
- Multiple boards/projects
|
|
||||||
- Boards customization, rename/add/remove columns
|
|
||||||
- Tasks with different colors, categories, sub-tasks, attachments, comments and Markdown support for the description
|
|
||||||
- Automatic actions based on events
|
|
||||||
- Users management with a basic privileges separation (administrator or regular user)
|
|
||||||
- Email notifications
|
|
||||||
- External authentication: Google, GitHub, LDAP/ActiveDirectory and Reverse-Proxy
|
|
||||||
- Webhooks to create tasks from an external software
|
|
||||||
- A basic command line interface
|
|
||||||
- Host anywhere (shared hosting, VPS, Raspberry Pi or localhost)
|
|
||||||
- No external dependencies
|
|
||||||
- **Super easy setup**, copy and paste files and you are done!
|
|
||||||
- Translations in English, French, Brazilian Portuguese, Spanish, German, Polish, Swedish, Finnish, Italian, Chinese, Russian...
|
|
||||||
|
|
||||||
Known bugs and feature requests
|
|
||||||
-------------------------------
|
|
||||||
|
|
||||||
See Issues: <https://github.com/fguillot/kanboard/issues>
|
|
||||||
|
|
||||||
License
|
|
||||||
-------
|
|
||||||
|
|
||||||
GNU Affero General Public License version 3: <http://www.gnu.org/licenses/agpl-3.0.txt>
|
|
||||||
|
|
||||||
Documentation
|
|
||||||
-------------
|
|
||||||
|
|
||||||
### Using Kanboard
|
|
||||||
|
|
||||||
#### Introduction
|
|
||||||
|
|
||||||
- [Usage examples](docs/usage-examples.markdown)
|
|
||||||
|
|
||||||
#### Working with projects
|
|
||||||
|
|
||||||
- [Creating projects](docs/creating-projects.markdown)
|
|
||||||
- [Editing projects](docs/editing-projects.markdown)
|
|
||||||
- [Sharing boards and tasks](docs/sharing-projects.markdown)
|
|
||||||
- [Automatic actions](docs/automatic-actions.markdown)
|
|
||||||
|
|
||||||
#### Working with tasks
|
|
||||||
|
|
||||||
- [Creating tasks](docs/creating-tasks.markdown)
|
|
||||||
|
|
||||||
#### Working with users
|
|
||||||
|
|
||||||
- [User management](docs/manage-users.markdown)
|
|
||||||
|
|
||||||
#### More
|
|
||||||
|
|
||||||
- [Syntax guide](docs/syntax-guide.markdown)
|
|
||||||
|
|
||||||
### Technical details
|
|
||||||
|
|
||||||
#### Installation
|
|
||||||
|
|
||||||
- [Installation instructions](docs/installation.markdown)
|
|
||||||
- [Upgrade Kanboard to a new version](docs/update.markdown)
|
|
||||||
- [Installation on Ubuntu](docs/ubuntu-installation.markdown)
|
|
||||||
- [Installation on Debian](docs/debian-installation.markdown)
|
|
||||||
- [Installation on Centos](docs/centos-installation.markdown)
|
|
||||||
- [Installation on Windows Server with IIS](docs/windows-iis-installation.markdown)
|
|
||||||
- [Example with Nginx + HTTPS + SPDY + PHP-FPM](docs/nginx-ssl-php-fpm.markdown)
|
|
||||||
|
|
||||||
#### Database
|
|
||||||
|
|
||||||
- [Sqlite database management](docs/sqlite-database.markdown)
|
|
||||||
- [How to use Mysql](docs/mysql-configuration.markdown)
|
|
||||||
- [How to use Postgresql](docs/postgresql-configuration.markdown)
|
|
||||||
|
|
||||||
#### Authentication
|
|
||||||
|
|
||||||
- [LDAP authentication](docs/ldap-authentication.markdown)
|
|
||||||
- [Google authentication](docs/google-authentication.markdown)
|
|
||||||
- [GitHub authentication](docs/github-authentication.markdown)
|
|
||||||
- [Reverse proxy authentication](docs/reverse-proxy-authentication.markdown)
|
|
||||||
|
|
||||||
#### Developers and sysadmins
|
|
||||||
|
|
||||||
- [Board configuration](docs/board-configuration.markdown)
|
|
||||||
- [Email configuration](docs/email-configuration.markdown)
|
|
||||||
- [Command line interface](docs/cli.markdown)
|
|
||||||
- [Json-RPC API](docs/api-json-rpc.markdown)
|
|
||||||
- [Webhooks](docs/webhooks.markdown)
|
|
||||||
- [How to use Kanboard with Vagrant](docs/vagrant.markdown)
|
|
||||||
|
|
||||||
### Contributors
|
|
||||||
|
|
||||||
- [Translations](docs/translations.markdown)
|
|
||||||
- [Coding standards](docs/coding-standards.markdown)
|
|
||||||
- [Running tests](docs/tests.markdown)
|
|
||||||
|
|
||||||
The documentation is written in [Markdown](http://en.wikipedia.org/wiki/Markdown).
|
|
||||||
If you want to improve the documentation, just send a pull-request.
|
|
||||||
|
|
||||||
FAQ
|
|
||||||
---
|
|
||||||
|
|
||||||
Go to the official website: <http://kanboard.net/faq>
|
|
||||||
|
|
||||||
Authors
|
|
||||||
-------
|
|
||||||
|
|
||||||
Original author: [Frédéric Guillot](http://fredericguillot.com/)
|
|
||||||
|
|
||||||
Contributors:
|
|
||||||
|
|
||||||
- Alex Butum
|
|
||||||
- Ashish Kulkarni: https://github.com/ashkulz
|
|
||||||
- Claudio Lobo
|
|
||||||
- Cmer: https://github.com/chncsu
|
|
||||||
- Floaltvater: https://github.com/floaltvater
|
|
||||||
- Gavlepeter: https://github.com/gavlepeter
|
|
||||||
- Janne Mäntyharju: https://github.com/JanneMantyharju
|
|
||||||
- Jesusaplsoft: https://github.com/jesusaplsoft
|
|
||||||
- Kiswa: https://github.com/kiswa
|
|
||||||
- Kralo: https://github.com/kralo
|
|
||||||
- Levlaz: https://github.com/levlaz
|
|
||||||
- Lim Yuen Hoe: https://github.com/jasonmoofang
|
|
||||||
- Mathgl67: https://github.com/mathgl67
|
|
||||||
- Matthieu Keller: https://github.com/maggick
|
|
||||||
- Mauro Mariño: https://github.com/moromarino
|
|
||||||
- Maxime: https://github.com/EpocDotFr
|
|
||||||
- Moraxy: https://github.com/moraxy
|
|
||||||
- Nala Ginrut: https://github.com/NalaGinrut
|
|
||||||
- Nekohayo: https://github.com/nekohayo
|
|
||||||
- Nramel: https://github.com/nramel
|
|
||||||
- Null-Kelvin: https://github.com/Null-Kelvin
|
|
||||||
- Olivier Maridat: https://github.com/oliviermaridat
|
|
||||||
- Poikilotherm: https://github.com/poikilotherm
|
|
||||||
- Rafaelrossa: https://github.com/rafaelrossa
|
|
||||||
- Raphaël Doursenaud: https://github.com/rdoursenaud
|
|
||||||
- Rzeka: https://github.com/rzeka
|
|
||||||
- Sebastien pacilly: https://github.com/spacilly
|
|
||||||
- Sylvain Veyrié: https://github.com/turb
|
|
||||||
- Toomyem: https://github.com/Toomyem
|
|
||||||
- Tony G. Bolaño: https://github.com/tonybolanyo
|
|
||||||
- Torsten: https://github.com/misterfu
|
|
||||||
- Troloo: https://github.com/troloo
|
|
||||||
- Typz: https://github.com/Typz
|
|
||||||
- Vedovator: https://github.com/vedovator
|
|
||||||
- Ybarc: https://github.com/ybarc
|
|
||||||
|
|
||||||
There is also many people who have reported bugs or proposed awesome ideas.
|
|
29
sources/Vagrantfile
vendored
29
sources/Vagrantfile
vendored
|
@ -1,29 +0,0 @@
|
||||||
# -*- mode: ruby -*-
|
|
||||||
# vi: set ft=ruby :
|
|
||||||
|
|
||||||
VAGRANTFILE_API_VERSION = "2"
|
|
||||||
|
|
||||||
$script = <<SCRIPT
|
|
||||||
# install packages
|
|
||||||
apt-get update
|
|
||||||
apt-get install -y apache2 php5 php5-sqlite php5-ldap php5-xdebug
|
|
||||||
service apache2 restart
|
|
||||||
rm -f /var/www/html/index.html
|
|
||||||
date > /etc/vagrant_provisioned_at
|
|
||||||
echo "Go to http://localhost:8080/ (admin/admin) !"
|
|
||||||
SCRIPT
|
|
||||||
|
|
||||||
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
|
||||||
|
|
||||||
# Image
|
|
||||||
config.vm.box = "ubuntu/trusty64"
|
|
||||||
config.vm.box_url = "http://cloud-images.ubuntu.com/vagrant/trusty/current/trusty-server-cloudimg-amd64-vagrant-disk1.box"
|
|
||||||
|
|
||||||
# Network
|
|
||||||
config.vm.network :forwarded_port, guest: 80, host: 8080
|
|
||||||
#config.vm.network "public_network", :bridge => "en0: Wi-Fi (AirPort)"
|
|
||||||
|
|
||||||
# Setup
|
|
||||||
config.vm.provision "shell", inline: $script
|
|
||||||
config.vm.synced_folder ".", "/var/www/html", owner: "www-data", group: "www-data"
|
|
||||||
end
|
|
|
@ -3,12 +3,19 @@
|
||||||
namespace Action;
|
namespace Action;
|
||||||
|
|
||||||
use Core\Listener;
|
use Core\Listener;
|
||||||
|
use Core\Registry;
|
||||||
|
use Core\Tool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for automatic actions
|
* Base class for automatic actions
|
||||||
*
|
*
|
||||||
* @package action
|
* @package action
|
||||||
* @author Frederic Guillot
|
* @author Frederic Guillot
|
||||||
|
*
|
||||||
|
* @property \Model\Acl $acl
|
||||||
|
* @property \Model\Comment $comment
|
||||||
|
* @property \Model\Task $task
|
||||||
|
* @property \Model\TaskFinder $taskFinder
|
||||||
*/
|
*/
|
||||||
abstract class Base implements Listener
|
abstract class Base implements Listener
|
||||||
{
|
{
|
||||||
|
@ -28,6 +35,22 @@ abstract class Base implements Listener
|
||||||
*/
|
*/
|
||||||
private $params = array();
|
private $params = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attached event name
|
||||||
|
*
|
||||||
|
* @access protected
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $event_name = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registry instance
|
||||||
|
*
|
||||||
|
* @access protected
|
||||||
|
* @var \Core\Registry
|
||||||
|
*/
|
||||||
|
protected $registry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the action
|
* Execute the action
|
||||||
*
|
*
|
||||||
|
@ -56,15 +79,60 @@ abstract class Base implements Listener
|
||||||
*/
|
*/
|
||||||
abstract public function getEventRequiredParameters();
|
abstract public function getEventRequiredParameters();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the compatible events
|
||||||
|
*
|
||||||
|
* @abstract
|
||||||
|
* @access public
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
abstract public function getCompatibleEvents();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the event data meet the action condition
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $data Event data dictionary
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
abstract public function hasRequiredCondition(array $data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
|
* @param \Core\Registry $registry Regsitry instance
|
||||||
* @param integer $project_id Project id
|
* @param integer $project_id Project id
|
||||||
|
* @param string $event_name Attached event name
|
||||||
*/
|
*/
|
||||||
public function __construct($project_id)
|
public function __construct(Registry $registry, $project_id, $event_name)
|
||||||
{
|
{
|
||||||
|
$this->registry = $registry;
|
||||||
$this->project_id = $project_id;
|
$this->project_id = $project_id;
|
||||||
|
$this->event_name = $event_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return class information
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
return get_called_class();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load automatically models
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param string $name Model name
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function __get($name)
|
||||||
|
{
|
||||||
|
return Tool::loadModel($this->registry, $name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -101,11 +169,34 @@ abstract class Base implements Listener
|
||||||
*/
|
*/
|
||||||
public function isExecutable(array $data)
|
public function isExecutable(array $data)
|
||||||
{
|
{
|
||||||
if (isset($data['project_id']) && $data['project_id'] == $this->project_id && $this->hasRequiredParameters($data)) {
|
return $this->hasCompatibleEvent() &&
|
||||||
return true;
|
$this->hasRequiredProject($data) &&
|
||||||
|
$this->hasRequiredParameters($data) &&
|
||||||
|
$this->hasRequiredCondition($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
/**
|
||||||
|
* Check if the event is compatible with the action
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $data Event data dictionary
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasCompatibleEvent()
|
||||||
|
{
|
||||||
|
return in_array($this->event_name, $this->getCompatibleEvents());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the event data has the required project
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $data Event data dictionary
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasRequiredProject(array $data)
|
||||||
|
{
|
||||||
|
return isset($data['project_id']) && $data['project_id'] == $this->project_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -118,7 +209,9 @@ abstract class Base implements Listener
|
||||||
public function hasRequiredParameters(array $data)
|
public function hasRequiredParameters(array $data)
|
||||||
{
|
{
|
||||||
foreach ($this->getEventRequiredParameters() as $parameter) {
|
foreach ($this->getEventRequiredParameters() as $parameter) {
|
||||||
if (! isset($data[$parameter])) return false;
|
if (! isset($data[$parameter])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -139,15 +232,4 @@ abstract class Base implements Listener
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return class information
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function __toString()
|
|
||||||
{
|
|
||||||
return get_called_class();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
83
sources/app/Action/CommentCreation.php
Normal file
83
sources/app/Action/CommentCreation.php
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Action;
|
||||||
|
|
||||||
|
use Model\GithubWebhook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create automatically a comment from a webhook
|
||||||
|
*
|
||||||
|
* @package action
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
class CommentCreation extends Base
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get the list of compatible events
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getCompatibleEvents()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
GithubWebhook::EVENT_ISSUE_COMMENT,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the required parameter for the action (defined by the user)
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getActionRequiredParameters()
|
||||||
|
{
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the required parameter for the event
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getEventRequiredParameters()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'reference',
|
||||||
|
'comment',
|
||||||
|
'user_id',
|
||||||
|
'task_id',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the action (create a new comment)
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $data Event data dictionary
|
||||||
|
* @return bool True if the action was executed or false when not executed
|
||||||
|
*/
|
||||||
|
public function doAction(array $data)
|
||||||
|
{
|
||||||
|
return $this->comment->create(array(
|
||||||
|
'reference' => $data['reference'],
|
||||||
|
'comment' => $data['comment'],
|
||||||
|
'task_id' => $data['task_id'],
|
||||||
|
'user_id' => $data['user_id'],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the event data meet the action condition
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $data Event data dictionary
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasRequiredCondition(array $data)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,24 +13,16 @@ use Model\Task;
|
||||||
class TaskAssignCategoryColor extends Base
|
class TaskAssignCategoryColor extends Base
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Task model
|
* Get the list of compatible events
|
||||||
*
|
|
||||||
* @accesss private
|
|
||||||
* @var \Model\Task
|
|
||||||
*/
|
|
||||||
private $task;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @param integer $project_id Project id
|
* @return array
|
||||||
* @param \Model\Task $task Task model instance
|
|
||||||
*/
|
*/
|
||||||
public function __construct($project_id, Task $task)
|
public function getCompatibleEvents()
|
||||||
{
|
{
|
||||||
parent::__construct($project_id);
|
return array(
|
||||||
$this->task = $task;
|
Task::EVENT_CREATE_UPDATE,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -62,7 +54,7 @@ class TaskAssignCategoryColor extends Base
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the action
|
* Execute the action (change the category)
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @param array $data Event data dictionary
|
* @param array $data Event data dictionary
|
||||||
|
@ -70,16 +62,23 @@ class TaskAssignCategoryColor extends Base
|
||||||
*/
|
*/
|
||||||
public function doAction(array $data)
|
public function doAction(array $data)
|
||||||
{
|
{
|
||||||
if ($data['color_id'] == $this->getParam('color_id')) {
|
$values = array(
|
||||||
|
|
||||||
$this->task->update(array(
|
|
||||||
'id' => $data['task_id'],
|
'id' => $data['task_id'],
|
||||||
'category_id' => $this->getParam('category_id'),
|
'category_id' => $this->getParam('category_id'),
|
||||||
), false);
|
);
|
||||||
|
|
||||||
return true;
|
return $this->task->update($values, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
/**
|
||||||
|
* Check if the event data meet the action condition
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $data Event data dictionary
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasRequiredCondition(array $data)
|
||||||
|
{
|
||||||
|
return $data['color_id'] == $this->getParam('color_id');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
84
sources/app/Action/TaskAssignCategoryLabel.php
Normal file
84
sources/app/Action/TaskAssignCategoryLabel.php
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Action;
|
||||||
|
|
||||||
|
use Model\GithubWebhook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a category automatically according to a label
|
||||||
|
*
|
||||||
|
* @package action
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
class TaskAssignCategoryLabel extends Base
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get the list of compatible events
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getCompatibleEvents()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
GithubWebhook::EVENT_ISSUE_LABEL_CHANGE,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the required parameter for the action (defined by the user)
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getActionRequiredParameters()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'label' => t('Label'),
|
||||||
|
'category_id' => t('Category'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the required parameter for the event
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getEventRequiredParameters()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'task_id',
|
||||||
|
'label',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the action (change the category)
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $data Event data dictionary
|
||||||
|
* @return bool True if the action was executed or false when not executed
|
||||||
|
*/
|
||||||
|
public function doAction(array $data)
|
||||||
|
{
|
||||||
|
$values = array(
|
||||||
|
'id' => $data['task_id'],
|
||||||
|
'category_id' => isset($data['category_id']) ? $data['category_id'] : $this->getParam('category_id'),
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->task->update($values, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the event data meet the action condition
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $data Event data dictionary
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasRequiredCondition(array $data)
|
||||||
|
{
|
||||||
|
return $data['label'] == $this->getParam('label');
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,24 +13,16 @@ use Model\Task;
|
||||||
class TaskAssignColorCategory extends Base
|
class TaskAssignColorCategory extends Base
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Task model
|
* Get the list of compatible events
|
||||||
*
|
|
||||||
* @accesss private
|
|
||||||
* @var \Model\Task
|
|
||||||
*/
|
|
||||||
private $task;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @param integer $project_id Project id
|
* @return array
|
||||||
* @param \Model\Task $task Task model instance
|
|
||||||
*/
|
*/
|
||||||
public function __construct($project_id, Task $task)
|
public function getCompatibleEvents()
|
||||||
{
|
{
|
||||||
parent::__construct($project_id);
|
return array(
|
||||||
$this->task = $task;
|
Task::EVENT_CREATE_UPDATE,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -62,7 +54,7 @@ class TaskAssignColorCategory extends Base
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the action
|
* Execute the action (change the task color)
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @param array $data Event data dictionary
|
* @param array $data Event data dictionary
|
||||||
|
@ -70,16 +62,23 @@ class TaskAssignColorCategory extends Base
|
||||||
*/
|
*/
|
||||||
public function doAction(array $data)
|
public function doAction(array $data)
|
||||||
{
|
{
|
||||||
if ($data['category_id'] == $this->getParam('category_id')) {
|
$values = array(
|
||||||
|
|
||||||
$this->task->update(array(
|
|
||||||
'id' => $data['task_id'],
|
'id' => $data['task_id'],
|
||||||
'color_id' => $this->getParam('color_id'),
|
'color_id' => $this->getParam('color_id'),
|
||||||
), false);
|
);
|
||||||
|
|
||||||
return true;
|
return $this->task->update($values, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
/**
|
||||||
|
* Check if the event data meet the action condition
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $data Event data dictionary
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasRequiredCondition(array $data)
|
||||||
|
{
|
||||||
|
return $data['category_id'] == $this->getParam('category_id');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,24 +13,17 @@ use Model\Task;
|
||||||
class TaskAssignColorUser extends Base
|
class TaskAssignColorUser extends Base
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Task model
|
* Get the list of compatible events
|
||||||
*
|
|
||||||
* @accesss private
|
|
||||||
* @var \Model\Task
|
|
||||||
*/
|
|
||||||
private $task;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @param integer $project_id Project id
|
* @return array
|
||||||
* @param \Model\Task $task Task model instance
|
|
||||||
*/
|
*/
|
||||||
public function __construct($project_id, Task $task)
|
public function getCompatibleEvents()
|
||||||
{
|
{
|
||||||
parent::__construct($project_id);
|
return array(
|
||||||
$this->task = $task;
|
Task::EVENT_CREATE,
|
||||||
|
Task::EVENT_ASSIGNEE_CHANGE,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -62,7 +55,7 @@ class TaskAssignColorUser extends Base
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the action
|
* Execute the action (change the task color)
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @param array $data Event data dictionary
|
* @param array $data Event data dictionary
|
||||||
|
@ -70,16 +63,23 @@ class TaskAssignColorUser extends Base
|
||||||
*/
|
*/
|
||||||
public function doAction(array $data)
|
public function doAction(array $data)
|
||||||
{
|
{
|
||||||
if ($data['owner_id'] == $this->getParam('user_id')) {
|
$values = array(
|
||||||
|
|
||||||
$this->task->update(array(
|
|
||||||
'id' => $data['task_id'],
|
'id' => $data['task_id'],
|
||||||
'color_id' => $this->getParam('color_id'),
|
'color_id' => $this->getParam('color_id'),
|
||||||
), false);
|
);
|
||||||
|
|
||||||
return true;
|
return $this->task->update($values, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
/**
|
||||||
|
* Check if the event data meet the action condition
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $data Event data dictionary
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasRequiredCondition(array $data)
|
||||||
|
{
|
||||||
|
return $data['owner_id'] == $this->getParam('user_id');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
namespace Action;
|
namespace Action;
|
||||||
|
|
||||||
use Model\Task;
|
use Model\Task;
|
||||||
use Model\Acl;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assign a task to the logged user
|
* Assign a task to the logged user
|
||||||
|
@ -14,34 +13,17 @@ use Model\Acl;
|
||||||
class TaskAssignCurrentUser extends Base
|
class TaskAssignCurrentUser extends Base
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Task model
|
* Get the list of compatible events
|
||||||
*
|
|
||||||
* @accesss private
|
|
||||||
* @var \Model\Task
|
|
||||||
*/
|
|
||||||
private $task;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Acl model
|
|
||||||
*
|
|
||||||
* @accesss private
|
|
||||||
* @var \Model\Acl
|
|
||||||
*/
|
|
||||||
private $acl;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @param integer $project_id Project id
|
* @return array
|
||||||
* @param \Model\Task $task Task model instance
|
|
||||||
* @param \Model\Acl $acl Acl model instance
|
|
||||||
*/
|
*/
|
||||||
public function __construct($project_id, Task $task, Acl $acl)
|
public function getCompatibleEvents()
|
||||||
{
|
{
|
||||||
parent::__construct($project_id);
|
return array(
|
||||||
$this->task = $task;
|
Task::EVENT_CREATE,
|
||||||
$this->acl = $acl;
|
Task::EVENT_MOVE_COLUMN,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -80,16 +62,23 @@ class TaskAssignCurrentUser extends Base
|
||||||
*/
|
*/
|
||||||
public function doAction(array $data)
|
public function doAction(array $data)
|
||||||
{
|
{
|
||||||
if ($data['column_id'] == $this->getParam('column_id')) {
|
$values = array(
|
||||||
|
|
||||||
$this->task->update(array(
|
|
||||||
'id' => $data['task_id'],
|
'id' => $data['task_id'],
|
||||||
'owner_id' => $this->acl->getUserId(),
|
'owner_id' => $this->acl->getUserId(),
|
||||||
), false);
|
);
|
||||||
|
|
||||||
return true;
|
return $this->task->update($values, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
/**
|
||||||
|
* Check if the event data meet the action condition
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $data Event data dictionary
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasRequiredCondition(array $data)
|
||||||
|
{
|
||||||
|
return $data['column_id'] == $this->getParam('column_id');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,24 +13,17 @@ use Model\Task;
|
||||||
class TaskAssignSpecificUser extends Base
|
class TaskAssignSpecificUser extends Base
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Task model
|
* Get the list of compatible events
|
||||||
*
|
|
||||||
* @accesss private
|
|
||||||
* @var \Model\Task
|
|
||||||
*/
|
|
||||||
private $task;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @param integer $project_id Project id
|
* @return array
|
||||||
* @param \Model\Task $task Task model instance
|
|
||||||
*/
|
*/
|
||||||
public function __construct($project_id, Task $task)
|
public function getCompatibleEvents()
|
||||||
{
|
{
|
||||||
parent::__construct($project_id);
|
return array(
|
||||||
$this->task = $task;
|
Task::EVENT_CREATE_UPDATE,
|
||||||
|
Task::EVENT_MOVE_COLUMN,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -62,7 +55,7 @@ class TaskAssignSpecificUser extends Base
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the action
|
* Execute the action (assign the given user)
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @param array $data Event data dictionary
|
* @param array $data Event data dictionary
|
||||||
|
@ -70,16 +63,23 @@ class TaskAssignSpecificUser extends Base
|
||||||
*/
|
*/
|
||||||
public function doAction(array $data)
|
public function doAction(array $data)
|
||||||
{
|
{
|
||||||
if ($data['column_id'] == $this->getParam('column_id')) {
|
$values = array(
|
||||||
|
|
||||||
$this->task->update(array(
|
|
||||||
'id' => $data['task_id'],
|
'id' => $data['task_id'],
|
||||||
'owner_id' => $this->getParam('user_id'),
|
'owner_id' => $this->getParam('user_id'),
|
||||||
), false);
|
);
|
||||||
|
|
||||||
return true;
|
return $this->task->update($values, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
/**
|
||||||
|
* Check if the event data meet the action condition
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $data Event data dictionary
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasRequiredCondition(array $data)
|
||||||
|
{
|
||||||
|
return $data['column_id'] == $this->getParam('column_id');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
81
sources/app/Action/TaskAssignUser.php
Normal file
81
sources/app/Action/TaskAssignUser.php
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Action;
|
||||||
|
|
||||||
|
use Model\GithubWebhook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assign a task to someone
|
||||||
|
*
|
||||||
|
* @package action
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
class TaskAssignUser extends Base
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get the list of compatible events
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getCompatibleEvents()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
GithubWebhook::EVENT_ISSUE_ASSIGNEE_CHANGE,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the required parameter for the action (defined by the user)
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getActionRequiredParameters()
|
||||||
|
{
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the required parameter for the event
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getEventRequiredParameters()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'task_id',
|
||||||
|
'owner_id',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the action (assign the given user)
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $data Event data dictionary
|
||||||
|
* @return bool True if the action was executed or false when not executed
|
||||||
|
*/
|
||||||
|
public function doAction(array $data)
|
||||||
|
{
|
||||||
|
$values = array(
|
||||||
|
'id' => $data['task_id'],
|
||||||
|
'owner_id' => $data['owner_id'],
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->task->update($values, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the event data meet the action condition
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $data Event data dictionary
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasRequiredCondition(array $data)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace Action;
|
namespace Action;
|
||||||
|
|
||||||
|
use Model\GithubWebhook;
|
||||||
use Model\Task;
|
use Model\Task;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -13,24 +14,18 @@ use Model\Task;
|
||||||
class TaskClose extends Base
|
class TaskClose extends Base
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Task model
|
* Get the list of compatible events
|
||||||
*
|
|
||||||
* @accesss private
|
|
||||||
* @var \Model\Task
|
|
||||||
*/
|
|
||||||
private $task;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @param integer $project_id Project id
|
* @return array
|
||||||
* @param \Model\Task $task Task model instance
|
|
||||||
*/
|
*/
|
||||||
public function __construct($project_id, Task $task)
|
public function getCompatibleEvents()
|
||||||
{
|
{
|
||||||
parent::__construct($project_id);
|
return array(
|
||||||
$this->task = $task;
|
Task::EVENT_MOVE_COLUMN,
|
||||||
|
GithubWebhook::EVENT_COMMIT,
|
||||||
|
GithubWebhook::EVENT_ISSUE_CLOSED,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -41,9 +36,13 @@ class TaskClose extends Base
|
||||||
*/
|
*/
|
||||||
public function getActionRequiredParameters()
|
public function getActionRequiredParameters()
|
||||||
{
|
{
|
||||||
return array(
|
switch ($this->event_name) {
|
||||||
'column_id' => t('Column'),
|
case GithubWebhook::EVENT_COMMIT:
|
||||||
);
|
case GithubWebhook::EVENT_ISSUE_CLOSED:
|
||||||
|
return array();
|
||||||
|
default:
|
||||||
|
return array('column_id' => t('Column'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -54,14 +53,17 @@ class TaskClose extends Base
|
||||||
*/
|
*/
|
||||||
public function getEventRequiredParameters()
|
public function getEventRequiredParameters()
|
||||||
{
|
{
|
||||||
return array(
|
switch ($this->event_name) {
|
||||||
'task_id',
|
case GithubWebhook::EVENT_COMMIT:
|
||||||
'column_id',
|
case GithubWebhook::EVENT_ISSUE_CLOSED:
|
||||||
);
|
return array('task_id');
|
||||||
|
default:
|
||||||
|
return array('task_id', 'column_id');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the action
|
* Execute the action (close the task)
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @param array $data Event data dictionary
|
* @param array $data Event data dictionary
|
||||||
|
@ -69,11 +71,24 @@ class TaskClose extends Base
|
||||||
*/
|
*/
|
||||||
public function doAction(array $data)
|
public function doAction(array $data)
|
||||||
{
|
{
|
||||||
if ($data['column_id'] == $this->getParam('column_id')) {
|
return $this->task->close($data['task_id']);
|
||||||
$this->task->close($data['task_id']);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
/**
|
||||||
|
* Check if the event data meet the action condition
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $data Event data dictionary
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasRequiredCondition(array $data)
|
||||||
|
{
|
||||||
|
switch ($this->event_name) {
|
||||||
|
case GithubWebhook::EVENT_COMMIT:
|
||||||
|
case GithubWebhook::EVENT_ISSUE_CLOSED:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return $data['column_id'] == $this->getParam('column_id');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
81
sources/app/Action/TaskCreation.php
Normal file
81
sources/app/Action/TaskCreation.php
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Action;
|
||||||
|
|
||||||
|
use Model\GithubWebhook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create automatically a task from a webhook
|
||||||
|
*
|
||||||
|
* @package action
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
class TaskCreation extends Base
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get the list of compatible events
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getCompatibleEvents()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
GithubWebhook::EVENT_ISSUE_OPENED,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the required parameter for the action (defined by the user)
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getActionRequiredParameters()
|
||||||
|
{
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the required parameter for the event
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getEventRequiredParameters()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'reference',
|
||||||
|
'title',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the action (create a new task)
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $data Event data dictionary
|
||||||
|
* @return bool True if the action was executed or false when not executed
|
||||||
|
*/
|
||||||
|
public function doAction(array $data)
|
||||||
|
{
|
||||||
|
return $this->task->create(array(
|
||||||
|
'project_id' => $data['project_id'],
|
||||||
|
'title' => $data['title'],
|
||||||
|
'reference' => $data['reference'],
|
||||||
|
'description' => $data['description'],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the event data meet the action condition
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $data Event data dictionary
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasRequiredCondition(array $data)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,24 +13,17 @@ use Model\Task;
|
||||||
class TaskDuplicateAnotherProject extends Base
|
class TaskDuplicateAnotherProject extends Base
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Task model
|
* Get the list of compatible events
|
||||||
*
|
|
||||||
* @accesss private
|
|
||||||
* @var \Model\Task
|
|
||||||
*/
|
|
||||||
private $task;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @param integer $project_id Project id
|
* @return array
|
||||||
* @param \Model\Task $task Task model instance
|
|
||||||
*/
|
*/
|
||||||
public function __construct($project_id, Task $task)
|
public function getCompatibleEvents()
|
||||||
{
|
{
|
||||||
parent::__construct($project_id);
|
return array(
|
||||||
$this->task = $task;
|
Task::EVENT_MOVE_COLUMN,
|
||||||
|
Task::EVENT_CLOSE,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -63,7 +56,7 @@ class TaskDuplicateAnotherProject extends Base
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the action
|
* Execute the action (duplicate the task to another project)
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @param array $data Event data dictionary
|
* @param array $data Event data dictionary
|
||||||
|
@ -71,14 +64,20 @@ class TaskDuplicateAnotherProject extends Base
|
||||||
*/
|
*/
|
||||||
public function doAction(array $data)
|
public function doAction(array $data)
|
||||||
{
|
{
|
||||||
if ($data['column_id'] == $this->getParam('column_id') && $data['project_id'] != $this->getParam('project_id')) {
|
$task = $this->taskFinder->getById($data['task_id']);
|
||||||
|
|
||||||
$task = $this->task->getById($data['task_id']);
|
|
||||||
$this->task->duplicateToAnotherProject($this->getParam('project_id'), $task);
|
$this->task->duplicateToAnotherProject($this->getParam('project_id'), $task);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
/**
|
||||||
|
* Check if the event data meet the action condition
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $data Event data dictionary
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasRequiredCondition(array $data)
|
||||||
|
{
|
||||||
|
return $data['column_id'] == $this->getParam('column_id') && $data['project_id'] != $this->getParam('project_id');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,24 +13,17 @@ use Model\Task;
|
||||||
class TaskMoveAnotherProject extends Base
|
class TaskMoveAnotherProject extends Base
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Task model
|
* Get the list of compatible events
|
||||||
*
|
|
||||||
* @accesss private
|
|
||||||
* @var \Model\Task
|
|
||||||
*/
|
|
||||||
private $task;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @param integer $project_id Project id
|
* @return array
|
||||||
* @param \Model\Task $task Task model instance
|
|
||||||
*/
|
*/
|
||||||
public function __construct($project_id, Task $task)
|
public function getCompatibleEvents()
|
||||||
{
|
{
|
||||||
parent::__construct($project_id);
|
return array(
|
||||||
$this->task = $task;
|
Task::EVENT_MOVE_COLUMN,
|
||||||
|
Task::EVENT_CLOSE,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -63,7 +56,7 @@ class TaskMoveAnotherProject extends Base
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the action
|
* Execute the action (move the task to another project)
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @param array $data Event data dictionary
|
* @param array $data Event data dictionary
|
||||||
|
@ -71,14 +64,20 @@ class TaskMoveAnotherProject extends Base
|
||||||
*/
|
*/
|
||||||
public function doAction(array $data)
|
public function doAction(array $data)
|
||||||
{
|
{
|
||||||
if ($data['column_id'] == $this->getParam('column_id') && $data['project_id'] != $this->getParam('project_id')) {
|
$task = $this->taskFinder->getById($data['task_id']);
|
||||||
|
|
||||||
$task = $this->task->getById($data['task_id']);
|
|
||||||
$this->task->moveToAnotherProject($this->getParam('project_id'), $task);
|
$this->task->moveToAnotherProject($this->getParam('project_id'), $task);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
/**
|
||||||
|
* Check if the event data meet the action condition
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $data Event data dictionary
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasRequiredCondition(array $data)
|
||||||
|
{
|
||||||
|
return $data['column_id'] == $this->getParam('column_id') && $data['project_id'] != $this->getParam('project_id');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
73
sources/app/Action/TaskOpen.php
Normal file
73
sources/app/Action/TaskOpen.php
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Action;
|
||||||
|
|
||||||
|
use Model\GithubWebhook;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open automatically a task
|
||||||
|
*
|
||||||
|
* @package action
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
class TaskOpen extends Base
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get the list of compatible events
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getCompatibleEvents()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
GithubWebhook::EVENT_ISSUE_REOPENED,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the required parameter for the action (defined by the user)
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getActionRequiredParameters()
|
||||||
|
{
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the required parameter for the event
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getEventRequiredParameters()
|
||||||
|
{
|
||||||
|
return array('task_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the action (close the task)
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $data Event data dictionary
|
||||||
|
* @return bool True if the action was executed or false when not executed
|
||||||
|
*/
|
||||||
|
public function doAction(array $data)
|
||||||
|
{
|
||||||
|
return $this->task->open($data['task_id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the event data meet the action condition
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $data Event data dictionary
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasRequiredCondition(array $data)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,7 @@
|
||||||
namespace Auth;
|
namespace Auth;
|
||||||
|
|
||||||
use Model\User;
|
use Model\User;
|
||||||
|
use Core\Request;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Database authentication
|
* Database authentication
|
||||||
|
@ -40,8 +41,8 @@ class Database extends Base
|
||||||
$this->lastLogin->create(
|
$this->lastLogin->create(
|
||||||
self::AUTH_NAME,
|
self::AUTH_NAME,
|
||||||
$user['id'],
|
$user['id'],
|
||||||
$this->user->getIpAddress(),
|
Request::getIpAddress(),
|
||||||
$this->user->getUserAgent()
|
Request::getUserAgent()
|
||||||
);
|
);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -4,6 +4,7 @@ namespace Auth;
|
||||||
|
|
||||||
require __DIR__.'/../../vendor/OAuth/bootstrap.php';
|
require __DIR__.'/../../vendor/OAuth/bootstrap.php';
|
||||||
|
|
||||||
|
use Core\Request;
|
||||||
use OAuth\Common\Storage\Session;
|
use OAuth\Common\Storage\Session;
|
||||||
use OAuth\Common\Consumer\Credentials;
|
use OAuth\Common\Consumer\Credentials;
|
||||||
use OAuth\Common\Http\Uri\UriFactory;
|
use OAuth\Common\Http\Uri\UriFactory;
|
||||||
|
@ -44,8 +45,8 @@ class GitHub extends Base
|
||||||
$this->lastLogin->create(
|
$this->lastLogin->create(
|
||||||
self::AUTH_NAME,
|
self::AUTH_NAME,
|
||||||
$user['id'],
|
$user['id'],
|
||||||
$this->user->getIpAddress(),
|
Request::getIpAddress(),
|
||||||
$this->user->getUserAgent()
|
Request::getUserAgent()
|
||||||
);
|
);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -4,6 +4,7 @@ namespace Auth;
|
||||||
|
|
||||||
require __DIR__.'/../../vendor/OAuth/bootstrap.php';
|
require __DIR__.'/../../vendor/OAuth/bootstrap.php';
|
||||||
|
|
||||||
|
use Core\Request;
|
||||||
use OAuth\Common\Storage\Session;
|
use OAuth\Common\Storage\Session;
|
||||||
use OAuth\Common\Consumer\Credentials;
|
use OAuth\Common\Consumer\Credentials;
|
||||||
use OAuth\Common\Http\Uri\UriFactory;
|
use OAuth\Common\Http\Uri\UriFactory;
|
||||||
|
@ -45,8 +46,8 @@ class Google extends Base
|
||||||
$this->lastLogin->create(
|
$this->lastLogin->create(
|
||||||
self::AUTH_NAME,
|
self::AUTH_NAME,
|
||||||
$user['id'],
|
$user['id'],
|
||||||
$this->user->getIpAddress(),
|
Request::getIpAddress(),
|
||||||
$this->user->getUserAgent()
|
Request::getUserAgent()
|
||||||
);
|
);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
namespace Auth;
|
namespace Auth;
|
||||||
|
|
||||||
|
use Core\Request;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LDAP model
|
* LDAP model
|
||||||
*
|
*
|
||||||
|
@ -58,8 +60,8 @@ class Ldap extends Base
|
||||||
$this->lastLogin->create(
|
$this->lastLogin->create(
|
||||||
self::AUTH_NAME,
|
self::AUTH_NAME,
|
||||||
$user['id'],
|
$user['id'],
|
||||||
$this->user->getIpAddress(),
|
Request::getIpAddress(),
|
||||||
$this->user->getUserAgent()
|
Request::getUserAgent()
|
||||||
);
|
);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace Auth;
|
namespace Auth;
|
||||||
|
|
||||||
|
use Core\Request;
|
||||||
use Core\Security;
|
use Core\Security;
|
||||||
use Core\Tool;
|
use Core\Tool;
|
||||||
|
|
||||||
|
@ -107,8 +108,8 @@ class RememberMe extends Base
|
||||||
$this->lastLogin->create(
|
$this->lastLogin->create(
|
||||||
self::AUTH_NAME,
|
self::AUTH_NAME,
|
||||||
$this->acl->getUserId(),
|
$this->acl->getUserId(),
|
||||||
$this->user->getIpAddress(),
|
Request::getIpAddress(),
|
||||||
$this->user->getUserAgent()
|
Request::getUserAgent()
|
||||||
);
|
);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace Auth;
|
namespace Auth;
|
||||||
|
|
||||||
|
use Core\Request;
|
||||||
use Core\Security;
|
use Core\Security;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -44,8 +45,8 @@ class ReverseProxy extends Base
|
||||||
$this->lastLogin->create(
|
$this->lastLogin->create(
|
||||||
self::AUTH_NAME,
|
self::AUTH_NAME,
|
||||||
$user['id'],
|
$user['id'],
|
||||||
$this->user->getIpAddress(),
|
Request::getIpAddress(),
|
||||||
$this->user->getUserAgent()
|
Request::getUserAgent()
|
||||||
);
|
);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -17,7 +17,7 @@ class Action extends Base
|
||||||
*/
|
*/
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
$project = $this->getProject();
|
$project = $this->getProjectManagement();
|
||||||
|
|
||||||
$this->response->html($this->projectLayout('action_index', array(
|
$this->response->html($this->projectLayout('action_index', array(
|
||||||
'values' => array('project_id' => $project['id']),
|
'values' => array('project_id' => $project['id']),
|
||||||
|
@ -27,9 +27,9 @@ class Action extends Base
|
||||||
'available_events' => $this->action->getAvailableEvents(),
|
'available_events' => $this->action->getAvailableEvents(),
|
||||||
'available_params' => $this->action->getAllActionParameters(),
|
'available_params' => $this->action->getAllActionParameters(),
|
||||||
'columns_list' => $this->board->getColumnsList($project['id']),
|
'columns_list' => $this->board->getColumnsList($project['id']),
|
||||||
'users_list' => $this->project->getUsersList($project['id']),
|
'users_list' => $this->projectPermission->getUsersList($project['id']),
|
||||||
'projects_list' => $this->project->getList(false),
|
'projects_list' => $this->project->getList(false),
|
||||||
'colors_list' => $this->task->getColors(),
|
'colors_list' => $this->color->getList(),
|
||||||
'categories_list' => $this->category->getList($project['id']),
|
'categories_list' => $this->category->getList($project['id']),
|
||||||
'menu' => 'projects',
|
'menu' => 'projects',
|
||||||
'title' => t('Automatic actions')
|
'title' => t('Automatic actions')
|
||||||
|
@ -37,23 +37,59 @@ class Action extends Base
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define action parameters (step 2)
|
* Choose the event according to the action (step 2)
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
public function event()
|
||||||
|
{
|
||||||
|
$project = $this->getProjectManagement();
|
||||||
|
$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->html($this->projectLayout('action_event', array(
|
||||||
|
'values' => $values,
|
||||||
|
'project' => $project,
|
||||||
|
'events' => $this->action->getCompatibleEvents($values['action_name']),
|
||||||
|
'menu' => 'projects',
|
||||||
|
'title' => t('Automatic actions')
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define action parameters (step 3)
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
*/
|
*/
|
||||||
public function params()
|
public function params()
|
||||||
{
|
{
|
||||||
$project = $this->getProject();
|
$project = $this->getProjectManagement();
|
||||||
$values = $this->request->getValues();
|
$values = $this->request->getValues();
|
||||||
$action = $this->action->load($values['action_name'], $values['project_id']);
|
|
||||||
|
if (empty($values['action_name']) || empty($values['project_id']) || empty($values['event_name'])) {
|
||||||
|
$this->response->redirect('?controller=action&action=index&project_id='.$project['id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$action = $this->action->load($values['action_name'], $values['project_id'], $values['event_name']);
|
||||||
|
$action_params = $action->getActionRequiredParameters();
|
||||||
|
|
||||||
|
if (empty($action_params)) {
|
||||||
|
$this->doCreation($project, $values + array('params' => array()));
|
||||||
|
}
|
||||||
|
|
||||||
|
$projects_list = $this->project->getList(false);
|
||||||
|
unset($projects_list[$project['id']]);
|
||||||
|
|
||||||
$this->response->html($this->projectLayout('action_params', array(
|
$this->response->html($this->projectLayout('action_params', array(
|
||||||
'values' => $values,
|
'values' => $values,
|
||||||
'action_params' => $action->getActionRequiredParameters(),
|
'action_params' => $action_params,
|
||||||
'columns_list' => $this->board->getColumnsList($project['id']),
|
'columns_list' => $this->board->getColumnsList($project['id']),
|
||||||
'users_list' => $this->project->getUsersList($project['id']),
|
'users_list' => $this->projectPermission->getUsersList($project['id']),
|
||||||
'projects_list' => $this->project->getList(false),
|
'projects_list' => $projects_list,
|
||||||
'colors_list' => $this->task->getColors(),
|
'colors_list' => $this->color->getList(),
|
||||||
'categories_list' => $this->category->getList($project['id']),
|
'categories_list' => $this->category->getList($project['id']),
|
||||||
'project' => $project,
|
'project' => $project,
|
||||||
'menu' => 'projects',
|
'menu' => 'projects',
|
||||||
|
@ -68,9 +104,18 @@ class Action extends Base
|
||||||
*/
|
*/
|
||||||
public function create()
|
public function create()
|
||||||
{
|
{
|
||||||
$project = $this->getProject();
|
$this->doCreation($this->getProjectManagement(), $this->request->getValues());
|
||||||
$values = $this->request->getValues();
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save the action
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @param array $project Project properties
|
||||||
|
* @param array $values Form values
|
||||||
|
*/
|
||||||
|
private function doCreation(array $project, array $values)
|
||||||
|
{
|
||||||
list($valid,) = $this->action->validateCreation($values);
|
list($valid,) = $this->action->validateCreation($values);
|
||||||
|
|
||||||
if ($valid) {
|
if ($valid) {
|
||||||
|
@ -93,7 +138,7 @@ class Action extends Base
|
||||||
*/
|
*/
|
||||||
public function confirm()
|
public function confirm()
|
||||||
{
|
{
|
||||||
$project = $this->getProject();
|
$project = $this->getProjectManagement();
|
||||||
|
|
||||||
$this->response->html($this->projectLayout('action_remove', array(
|
$this->response->html($this->projectLayout('action_remove', array(
|
||||||
'action' => $this->action->getById($this->request->getIntegerParam('action_id')),
|
'action' => $this->action->getById($this->request->getIntegerParam('action_id')),
|
||||||
|
@ -113,6 +158,7 @@ class Action extends Base
|
||||||
public function remove()
|
public function remove()
|
||||||
{
|
{
|
||||||
$this->checkCSRFParam();
|
$this->checkCSRFParam();
|
||||||
|
$project = $this->getProjectManagement();
|
||||||
$action = $this->action->getById($this->request->getIntegerParam('action_id'));
|
$action = $this->action->getById($this->request->getIntegerParam('action_id'));
|
||||||
|
|
||||||
if ($action && $this->action->remove($action['id'])) {
|
if ($action && $this->action->remove($action['id'])) {
|
||||||
|
@ -121,6 +167,6 @@ class Action extends Base
|
||||||
$this->session->flashError(t('Unable to remove this action.'));
|
$this->session->flashError(t('Unable to remove this action.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->response->redirect('?controller=action&action=index&project_id='.$action['project_id']);
|
$this->response->redirect('?controller=action&action=index&project_id='.$project['id']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,17 +13,21 @@ use Model\Project as ProjectModel;
|
||||||
class App extends Base
|
class App extends Base
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Redirect to the project creation page or the board controller
|
* Dashboard for the current user
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
*/
|
*/
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
if ($this->project->countByStatus(ProjectModel::ACTIVE)) {
|
$user_id = $this->acl->getUserId();
|
||||||
$this->response->redirect('?controller=board');
|
$projects = $this->projectPermission->getAllowedProjects($user_id);
|
||||||
}
|
|
||||||
else {
|
$this->response->html($this->template->layout('app_index', array(
|
||||||
$this->redirectNoProject();
|
'board_selector' => $projects,
|
||||||
}
|
'events' => $this->projectActivity->getProjects(array_keys($projects), 10),
|
||||||
|
'tasks' => $this->taskFinder->getAllTasksByUser($user_id),
|
||||||
|
'menu' => 'dashboard',
|
||||||
|
'title' => t('Dashboard'),
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ namespace Controller;
|
||||||
use Core\Tool;
|
use Core\Tool;
|
||||||
use Core\Registry;
|
use Core\Registry;
|
||||||
use Core\Security;
|
use Core\Security;
|
||||||
use Core\Translator;
|
|
||||||
use Model\LastLogin;
|
use Model\LastLogin;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -19,17 +18,24 @@ use Model\LastLogin;
|
||||||
* @property \Model\Action $action
|
* @property \Model\Action $action
|
||||||
* @property \Model\Board $board
|
* @property \Model\Board $board
|
||||||
* @property \Model\Category $category
|
* @property \Model\Category $category
|
||||||
|
* @property \Model\Color $color
|
||||||
* @property \Model\Comment $comment
|
* @property \Model\Comment $comment
|
||||||
* @property \Model\Config $config
|
* @property \Model\Config $config
|
||||||
* @property \Model\File $file
|
* @property \Model\File $file
|
||||||
* @property \Model\LastLogin $lastLogin
|
* @property \Model\LastLogin $lastLogin
|
||||||
* @property \Model\Notification $notification
|
* @property \Model\Notification $notification
|
||||||
* @property \Model\Project $project
|
* @property \Model\Project $project
|
||||||
|
* @property \Model\ProjectPermission $projectPermission
|
||||||
* @property \Model\SubTask $subTask
|
* @property \Model\SubTask $subTask
|
||||||
* @property \Model\Task $task
|
* @property \Model\Task $task
|
||||||
* @property \Model\TaskHistory $taskHistory
|
* @property \Model\TaskHistory $taskHistory
|
||||||
|
* @property \Model\TaskExport $taskExport
|
||||||
|
* @property \Model\TaskFinder $taskFinder
|
||||||
|
* @property \Model\TaskPermission $taskPermission
|
||||||
|
* @property \Model\TaskValidator $taskValidator
|
||||||
* @property \Model\CommentHistory $commentHistory
|
* @property \Model\CommentHistory $commentHistory
|
||||||
* @property \Model\SubtaskHistory $subtaskHistory
|
* @property \Model\SubtaskHistory $subtaskHistory
|
||||||
|
* @property \Model\TimeTracking $timeTracking
|
||||||
* @property \Model\User $user
|
* @property \Model\User $user
|
||||||
* @property \Model\Webhook $webhook
|
* @property \Model\Webhook $webhook
|
||||||
*/
|
*/
|
||||||
|
@ -112,19 +118,22 @@ abstract class Base
|
||||||
$this->response->csp(array('style-src' => "'self' 'unsafe-inline'"));
|
$this->response->csp(array('style-src' => "'self' 'unsafe-inline'"));
|
||||||
$this->response->nosniff();
|
$this->response->nosniff();
|
||||||
$this->response->xss();
|
$this->response->xss();
|
||||||
$this->response->hsts();
|
|
||||||
|
// Allow the public board iframe inclusion
|
||||||
|
if ($action !== 'readonly') {
|
||||||
$this->response->xframe();
|
$this->response->xframe();
|
||||||
|
}
|
||||||
|
|
||||||
// Load translations
|
if (ENABLE_HSTS) {
|
||||||
$language = $this->config->get('language', 'en_US');
|
$this->response->hsts();
|
||||||
if ($language !== 'en_US') Translator::load($language);
|
}
|
||||||
|
|
||||||
// Set timezone
|
$this->config->setupTranslations();
|
||||||
date_default_timezone_set($this->config->get('timezone', 'UTC'));
|
$this->config->setupTimezone();
|
||||||
|
|
||||||
// Authentication
|
// Authentication
|
||||||
if (! $this->authentication->isAuthenticated($controller, $action)) {
|
if (! $this->authentication->isAuthenticated($controller, $action)) {
|
||||||
$this->response->redirect('?controller=user&action=login');
|
$this->response->redirect('?controller=user&action=login&redirect_query='.urlencode($this->request->getQueryString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the user is allowed to see this page
|
// Check if the user is allowed to see this page
|
||||||
|
@ -144,13 +153,11 @@ abstract class Base
|
||||||
private function attachEvents()
|
private function attachEvents()
|
||||||
{
|
{
|
||||||
$models = array(
|
$models = array(
|
||||||
|
'projectActivity', // Order is important
|
||||||
'action',
|
'action',
|
||||||
'project',
|
'project',
|
||||||
'webhook',
|
'webhook',
|
||||||
'notification',
|
'notification',
|
||||||
'taskHistory',
|
|
||||||
'commentHistory',
|
|
||||||
'subtaskHistory',
|
|
||||||
);
|
);
|
||||||
|
|
||||||
foreach ($models as $model) {
|
foreach ($models as $model) {
|
||||||
|
@ -206,13 +213,10 @@ abstract class Base
|
||||||
*/
|
*/
|
||||||
protected function checkProjectPermissions($project_id)
|
protected function checkProjectPermissions($project_id)
|
||||||
{
|
{
|
||||||
if ($this->acl->isRegularUser()) {
|
if ($this->acl->isRegularUser() && ! $this->projectPermission->isUserAllowed($project_id, $this->acl->getUserId())) {
|
||||||
|
|
||||||
if ($project_id > 0 && ! $this->project->isUserAllowed($project_id, $this->acl->getUserId())) {
|
|
||||||
$this->forbidden();
|
$this->forbidden();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Redirection when there is no project in the database
|
* Redirection when there is no project in the database
|
||||||
|
@ -235,6 +239,10 @@ abstract class Base
|
||||||
*/
|
*/
|
||||||
protected function taskLayout($template, array $params)
|
protected function taskLayout($template, array $params)
|
||||||
{
|
{
|
||||||
|
if (isset($params['task']) && $this->taskPermission->canRemoveTask($params['task']) === false) {
|
||||||
|
$params['hide_remove_menu'] = true;
|
||||||
|
}
|
||||||
|
|
||||||
$content = $this->template->load($template, $params);
|
$content = $this->template->load($template, $params);
|
||||||
$params['task_content_for_layout'] = $content;
|
$params['task_content_for_layout'] = $content;
|
||||||
|
|
||||||
|
@ -253,6 +261,7 @@ abstract class Base
|
||||||
{
|
{
|
||||||
$content = $this->template->load($template, $params);
|
$content = $this->template->load($template, $params);
|
||||||
$params['project_content_for_layout'] = $content;
|
$params['project_content_for_layout'] = $content;
|
||||||
|
$params['menu'] = 'projects';
|
||||||
|
|
||||||
return $this->template->layout('project_layout', $params);
|
return $this->template->layout('project_layout', $params);
|
||||||
}
|
}
|
||||||
|
@ -265,7 +274,7 @@ abstract class Base
|
||||||
*/
|
*/
|
||||||
protected function getTask()
|
protected function getTask()
|
||||||
{
|
{
|
||||||
$task = $this->task->getById($this->request->getIntegerParam('task_id'), true);
|
$task = $this->taskFinder->getDetails($this->request->getIntegerParam('task_id'));
|
||||||
|
|
||||||
if (! $task) {
|
if (! $task) {
|
||||||
$this->notfound();
|
$this->notfound();
|
||||||
|
@ -297,4 +306,25 @@ abstract class Base
|
||||||
|
|
||||||
return $project;
|
return $project;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common method to get a project with administration rights
|
||||||
|
*
|
||||||
|
* @access protected
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function getProjectManagement()
|
||||||
|
{
|
||||||
|
$project = $this->project->getById($this->request->getIntegerParam('project_id'));
|
||||||
|
|
||||||
|
if (! $project) {
|
||||||
|
$this->notfound();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->acl->isRegularUser() && ! $this->projectPermission->adminAllowed($project['id'], $this->acl->getUserId())) {
|
||||||
|
$this->forbidden();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $project;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,35 +15,22 @@ use Core\Security;
|
||||||
class Board extends Base
|
class Board extends Base
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Move a column up
|
* Move a column down or up
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
*/
|
*/
|
||||||
public function moveUp()
|
public function moveColumn()
|
||||||
{
|
{
|
||||||
$this->checkCSRFParam();
|
$this->checkCSRFParam();
|
||||||
$project_id = $this->request->getIntegerParam('project_id');
|
$project = $this->getProjectManagement();
|
||||||
$column_id = $this->request->getIntegerParam('column_id');
|
$column_id = $this->request->getIntegerParam('column_id');
|
||||||
|
$direction = $this->request->getStringParam('direction');
|
||||||
|
|
||||||
$this->board->moveUp($project_id, $column_id);
|
if ($direction === 'up' || $direction === 'down') {
|
||||||
|
$this->board->{'move'.$direction}($project['id'], $column_id);
|
||||||
$this->response->redirect('?controller=board&action=edit&project_id='.$project_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
$this->response->redirect('?controller=board&action=edit&project_id='.$project['id']);
|
||||||
* Move a column down
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
*/
|
|
||||||
public function moveDown()
|
|
||||||
{
|
|
||||||
$this->checkCSRFParam();
|
|
||||||
$project_id = $this->request->getIntegerParam('project_id');
|
|
||||||
$column_id = $this->request->getIntegerParam('column_id');
|
|
||||||
|
|
||||||
$this->board->moveDown($project_id, $column_id);
|
|
||||||
|
|
||||||
$this->response->redirect('?controller=board&action=edit&project_id='.$project_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -55,11 +42,11 @@ class Board extends Base
|
||||||
{
|
{
|
||||||
$task = $this->getTask();
|
$task = $this->getTask();
|
||||||
$project = $this->project->getById($task['project_id']);
|
$project = $this->project->getById($task['project_id']);
|
||||||
$projects = $this->project->getAvailableList($this->acl->getUserId());
|
$projects = $this->projectPermission->getAllowedProjects($this->acl->getUserId());
|
||||||
$params = array(
|
$params = array(
|
||||||
'errors' => array(),
|
'errors' => array(),
|
||||||
'values' => $task,
|
'values' => $task,
|
||||||
'users_list' => $this->project->getUsersList($project['id']),
|
'users_list' => $this->projectPermission->getUsersList($project['id']),
|
||||||
'projects' => $projects,
|
'projects' => $projects,
|
||||||
'current_project_id' => $project['id'],
|
'current_project_id' => $project['id'],
|
||||||
'current_project_name' => $project['name'],
|
'current_project_name' => $project['name'],
|
||||||
|
@ -88,7 +75,7 @@ class Board extends Base
|
||||||
$values = $this->request->getValues();
|
$values = $this->request->getValues();
|
||||||
$this->checkProjectPermissions($values['project_id']);
|
$this->checkProjectPermissions($values['project_id']);
|
||||||
|
|
||||||
list($valid,) = $this->task->validateAssigneeModification($values);
|
list($valid,) = $this->taskValidator->validateAssigneeModification($values);
|
||||||
|
|
||||||
if ($valid && $this->task->update($values)) {
|
if ($valid && $this->task->update($values)) {
|
||||||
$this->session->flash(t('Task updated successfully.'));
|
$this->session->flash(t('Task updated successfully.'));
|
||||||
|
@ -109,7 +96,7 @@ class Board extends Base
|
||||||
{
|
{
|
||||||
$task = $this->getTask();
|
$task = $this->getTask();
|
||||||
$project = $this->project->getById($task['project_id']);
|
$project = $this->project->getById($task['project_id']);
|
||||||
$projects = $this->project->getAvailableList($this->acl->getUserId());
|
$projects = $this->projectPermission->getAllowedProjects($this->acl->getUserId());
|
||||||
$params = array(
|
$params = array(
|
||||||
'errors' => array(),
|
'errors' => array(),
|
||||||
'values' => $task,
|
'values' => $task,
|
||||||
|
@ -142,7 +129,7 @@ class Board extends Base
|
||||||
$values = $this->request->getValues();
|
$values = $this->request->getValues();
|
||||||
$this->checkProjectPermissions($values['project_id']);
|
$this->checkProjectPermissions($values['project_id']);
|
||||||
|
|
||||||
list($valid,) = $this->task->validateCategoryModification($values);
|
list($valid,) = $this->taskValidator->validateCategoryModification($values);
|
||||||
|
|
||||||
if ($valid && $this->task->update($values)) {
|
if ($valid && $this->task->update($values)) {
|
||||||
$this->session->flash(t('Task updated successfully.'));
|
$this->session->flash(t('Task updated successfully.'));
|
||||||
|
@ -177,8 +164,8 @@ class Board extends Base
|
||||||
'categories' => $this->category->getList($project['id'], false),
|
'categories' => $this->category->getList($project['id'], false),
|
||||||
'title' => $project['name'],
|
'title' => $project['name'],
|
||||||
'no_layout' => true,
|
'no_layout' => true,
|
||||||
'auto_refresh' => true,
|
|
||||||
'not_editable' => true,
|
'not_editable' => true,
|
||||||
|
'board_public_refresh_interval' => $this->config->get('board_public_refresh_interval'),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,7 +181,7 @@ class Board extends Base
|
||||||
$project_id = $last_seen_project_id ?: $favorite_project_id;
|
$project_id = $last_seen_project_id ?: $favorite_project_id;
|
||||||
|
|
||||||
if (! $project_id) {
|
if (! $project_id) {
|
||||||
$projects = $this->project->getAvailableList($this->acl->getUserId());
|
$projects = $this->projectPermission->getAllowedProjects($this->acl->getUserId());
|
||||||
|
|
||||||
if (empty($projects)) {
|
if (empty($projects)) {
|
||||||
|
|
||||||
|
@ -220,7 +207,7 @@ class Board extends Base
|
||||||
public function show($project_id = 0)
|
public function show($project_id = 0)
|
||||||
{
|
{
|
||||||
$project = $this->getProject($project_id);
|
$project = $this->getProject($project_id);
|
||||||
$projects = $this->project->getAvailableList($this->acl->getUserId());
|
$projects = $this->projectPermission->getAllowedProjects($this->acl->getUserId());
|
||||||
|
|
||||||
$board_selector = $projects;
|
$board_selector = $projects;
|
||||||
unset($board_selector[$project['id']]);
|
unset($board_selector[$project['id']]);
|
||||||
|
@ -228,16 +215,18 @@ class Board extends Base
|
||||||
$this->user->storeLastSeenProjectId($project['id']);
|
$this->user->storeLastSeenProjectId($project['id']);
|
||||||
|
|
||||||
$this->response->html($this->template->layout('board_index', array(
|
$this->response->html($this->template->layout('board_index', array(
|
||||||
'users' => $this->project->getUsersList($project['id'], true, true),
|
'users' => $this->projectPermission->getUsersList($project['id'], true, true),
|
||||||
'filters' => array('user_id' => UserModel::EVERYBODY_ID),
|
'filters' => array('user_id' => UserModel::EVERYBODY_ID),
|
||||||
'projects' => $projects,
|
'projects' => $projects,
|
||||||
'current_project_id' => $project['id'],
|
'current_project_id' => $project['id'],
|
||||||
'current_project_name' => $projects[$project['id']],
|
'current_project_name' => $project['name'],
|
||||||
'board' => $this->board->get($project['id']),
|
'board' => $this->board->get($project['id']),
|
||||||
'categories' => $this->category->getList($project['id'], true, true),
|
'categories' => $this->category->getList($project['id'], true, true),
|
||||||
'menu' => 'boards',
|
'menu' => 'boards',
|
||||||
'title' => $projects[$project['id']],
|
'title' => $project['name'],
|
||||||
'board_selector' => $board_selector,
|
'board_selector' => $board_selector,
|
||||||
|
'board_private_refresh_interval' => $this->config->get('board_private_refresh_interval'),
|
||||||
|
'board_highlight_period' => $this->config->get('board_highlight_period'),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,7 +237,7 @@ class Board extends Base
|
||||||
*/
|
*/
|
||||||
public function edit()
|
public function edit()
|
||||||
{
|
{
|
||||||
$project = $this->getProject();
|
$project = $this->getProjectManagement();
|
||||||
$columns = $this->board->getColumns($project['id']);
|
$columns = $this->board->getColumns($project['id']);
|
||||||
$values = array();
|
$values = array();
|
||||||
|
|
||||||
|
@ -274,7 +263,7 @@ class Board extends Base
|
||||||
*/
|
*/
|
||||||
public function update()
|
public function update()
|
||||||
{
|
{
|
||||||
$project = $this->getProject();
|
$project = $this->getProjectManagement();
|
||||||
$columns = $this->board->getColumns($project['id']);
|
$columns = $this->board->getColumns($project['id']);
|
||||||
$data = $this->request->getValues();
|
$data = $this->request->getValues();
|
||||||
$values = $columns_list = array();
|
$values = $columns_list = array();
|
||||||
|
@ -315,7 +304,7 @@ class Board extends Base
|
||||||
*/
|
*/
|
||||||
public function add()
|
public function add()
|
||||||
{
|
{
|
||||||
$project = $this->getProject();
|
$project = $this->getProjectManagement();
|
||||||
$columns = $this->board->getColumnsList($project['id']);
|
$columns = $this->board->getColumnsList($project['id']);
|
||||||
$data = $this->request->getValues();
|
$data = $this->request->getValues();
|
||||||
$values = array();
|
$values = array();
|
||||||
|
@ -347,23 +336,6 @@ class Board extends Base
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Confirmation dialog before removing a column
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
*/
|
|
||||||
public function confirm()
|
|
||||||
{
|
|
||||||
$project = $this->getProject();
|
|
||||||
|
|
||||||
$this->response->html($this->projectLayout('board_remove', array(
|
|
||||||
'column' => $this->board->getColumn($this->request->getIntegerParam('column_id')),
|
|
||||||
'project' => $project,
|
|
||||||
'menu' => 'projects',
|
|
||||||
'title' => t('Remove a column from a board')
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a column
|
* Remove a column
|
||||||
*
|
*
|
||||||
|
@ -371,6 +343,10 @@ class Board extends Base
|
||||||
*/
|
*/
|
||||||
public function remove()
|
public function remove()
|
||||||
{
|
{
|
||||||
|
$project = $this->getProjectManagement();
|
||||||
|
|
||||||
|
if ($this->request->getStringParam('remove') === 'yes') {
|
||||||
|
|
||||||
$this->checkCSRFParam();
|
$this->checkCSRFParam();
|
||||||
$column = $this->board->getColumn($this->request->getIntegerParam('column_id'));
|
$column = $this->board->getColumn($this->request->getIntegerParam('column_id'));
|
||||||
|
|
||||||
|
@ -380,7 +356,15 @@ class Board extends Base
|
||||||
$this->session->flashError(t('Unable to remove this column.'));
|
$this->session->flashError(t('Unable to remove this column.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->response->redirect('?controller=board&action=edit&project_id='.$column['project_id']);
|
$this->response->redirect('?controller=board&action=edit&project_id='.$project['id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->response->html($this->projectLayout('board_remove', array(
|
||||||
|
'column' => $this->board->getColumn($this->request->getIntegerParam('column_id')),
|
||||||
|
'project' => $project,
|
||||||
|
'menu' => 'projects',
|
||||||
|
'title' => t('Remove a column from a board')
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -394,7 +378,7 @@ class Board extends Base
|
||||||
|
|
||||||
if ($project_id > 0 && $this->request->isAjax()) {
|
if ($project_id > 0 && $this->request->isAjax()) {
|
||||||
|
|
||||||
if (! $this->project->isUserAllowed($project_id, $this->acl->getUserId())) {
|
if (! $this->projectPermission->isUserAllowed($project_id, $this->acl->getUserId())) {
|
||||||
$this->response->status(401);
|
$this->response->status(401);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,6 +391,8 @@ class Board extends Base
|
||||||
'current_project_id' => $project_id,
|
'current_project_id' => $project_id,
|
||||||
'board' => $this->board->get($project_id),
|
'board' => $this->board->get($project_id),
|
||||||
'categories' => $this->category->getList($project_id, false),
|
'categories' => $this->category->getList($project_id, false),
|
||||||
|
'board_private_refresh_interval' => $this->config->get('board_private_refresh_interval'),
|
||||||
|
'board_highlight_period' => $this->config->get('board_highlight_period'),
|
||||||
)),
|
)),
|
||||||
201
|
201
|
||||||
);
|
);
|
||||||
|
@ -433,7 +419,7 @@ class Board extends Base
|
||||||
$project_id = $this->request->getIntegerParam('project_id');
|
$project_id = $this->request->getIntegerParam('project_id');
|
||||||
$timestamp = $this->request->getIntegerParam('timestamp');
|
$timestamp = $this->request->getIntegerParam('timestamp');
|
||||||
|
|
||||||
if ($project_id > 0 && ! $this->project->isUserAllowed($project_id, $this->acl->getUserId())) {
|
if ($project_id > 0 && ! $this->projectPermission->isUserAllowed($project_id, $this->acl->getUserId())) {
|
||||||
$this->response->text('Not Authorized', 401);
|
$this->response->text('Not Authorized', 401);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -443,6 +429,8 @@ class Board extends Base
|
||||||
'current_project_id' => $project_id,
|
'current_project_id' => $project_id,
|
||||||
'board' => $this->board->get($project_id),
|
'board' => $this->board->get($project_id),
|
||||||
'categories' => $this->category->getList($project_id, false),
|
'categories' => $this->category->getList($project_id, false),
|
||||||
|
'board_private_refresh_interval' => $this->config->get('board_private_refresh_interval'),
|
||||||
|
'board_highlight_period' => $this->config->get('board_highlight_period'),
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
namespace Controller;
|
namespace Controller;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Categories management
|
* Category management
|
||||||
*
|
*
|
||||||
* @package controller
|
* @package controller
|
||||||
* @author Frederic Guillot
|
* @author Frederic Guillot
|
||||||
|
@ -36,7 +36,7 @@ class Category extends Base
|
||||||
*/
|
*/
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
$project = $this->getProject();
|
$project = $this->getProjectManagement();
|
||||||
|
|
||||||
$this->response->html($this->projectLayout('category_index', array(
|
$this->response->html($this->projectLayout('category_index', array(
|
||||||
'categories' => $this->category->getList($project['id'], false),
|
'categories' => $this->category->getList($project['id'], false),
|
||||||
|
@ -55,7 +55,7 @@ class Category extends Base
|
||||||
*/
|
*/
|
||||||
public function save()
|
public function save()
|
||||||
{
|
{
|
||||||
$project = $this->getProject();
|
$project = $this->getProjectManagement();
|
||||||
|
|
||||||
$values = $this->request->getValues();
|
$values = $this->request->getValues();
|
||||||
list($valid, $errors) = $this->category->validateCreation($values);
|
list($valid, $errors) = $this->category->validateCreation($values);
|
||||||
|
@ -88,7 +88,7 @@ class Category extends Base
|
||||||
*/
|
*/
|
||||||
public function edit()
|
public function edit()
|
||||||
{
|
{
|
||||||
$project = $this->getProject();
|
$project = $this->getProjectManagement();
|
||||||
$category = $this->getCategory($project['id']);
|
$category = $this->getCategory($project['id']);
|
||||||
|
|
||||||
$this->response->html($this->projectLayout('category_edit', array(
|
$this->response->html($this->projectLayout('category_edit', array(
|
||||||
|
@ -107,7 +107,7 @@ class Category extends Base
|
||||||
*/
|
*/
|
||||||
public function update()
|
public function update()
|
||||||
{
|
{
|
||||||
$project = $this->getProject();
|
$project = $this->getProjectManagement();
|
||||||
|
|
||||||
$values = $this->request->getValues();
|
$values = $this->request->getValues();
|
||||||
list($valid, $errors) = $this->category->validateModification($values);
|
list($valid, $errors) = $this->category->validateModification($values);
|
||||||
|
@ -139,7 +139,7 @@ class Category extends Base
|
||||||
*/
|
*/
|
||||||
public function confirm()
|
public function confirm()
|
||||||
{
|
{
|
||||||
$project = $this->getProject();
|
$project = $this->getProjectManagement();
|
||||||
$category = $this->getCategory($project['id']);
|
$category = $this->getCategory($project['id']);
|
||||||
|
|
||||||
$this->response->html($this->projectLayout('category_remove', array(
|
$this->response->html($this->projectLayout('category_remove', array(
|
||||||
|
@ -158,7 +158,7 @@ class Category extends Base
|
||||||
public function remove()
|
public function remove()
|
||||||
{
|
{
|
||||||
$this->checkCSRFParam();
|
$this->checkCSRFParam();
|
||||||
$project = $this->getProject();
|
$project = $this->getProjectManagement();
|
||||||
$category = $this->getCategory($project['id']);
|
$category = $this->getCategory($project['id']);
|
||||||
|
|
||||||
if ($this->category->remove($category['id'])) {
|
if ($this->category->remove($category['id'])) {
|
||||||
|
|
|
@ -11,55 +11,115 @@ namespace Controller;
|
||||||
class Config extends Base
|
class Config extends Base
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Display the settings page
|
* Common layout for config views
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @param string $template Template name
|
||||||
|
* @param array $params Template parameters
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function layout($template, array $params)
|
||||||
|
{
|
||||||
|
$params['values'] = $this->config->getAll();
|
||||||
|
$params['errors'] = array();
|
||||||
|
$params['menu'] = 'config';
|
||||||
|
$params['config_content_for_layout'] = $this->template->load($template, $params);
|
||||||
|
|
||||||
|
return $this->template->layout('config_layout', $params);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common method between pages
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @param string $redirect Action to redirect after saving the form
|
||||||
|
*/
|
||||||
|
private function common($redirect)
|
||||||
|
{
|
||||||
|
if ($this->request->isPost()) {
|
||||||
|
|
||||||
|
$values = $this->request->getValues();
|
||||||
|
|
||||||
|
if ($this->config->save($values)) {
|
||||||
|
$this->config->reload();
|
||||||
|
$this->session->flash(t('Settings saved successfully.'));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->session->flashError(t('Unable to save your settings.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->response->redirect('?controller=config&action='.$redirect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the about page
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
*/
|
*/
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
$this->response->html($this->template->layout('config_index', array(
|
$this->response->html($this->layout('config_about', array(
|
||||||
'db_size' => $this->config->getDatabaseSize(),
|
'db_size' => $this->config->getDatabaseSize(),
|
||||||
|
'title' => t('About'),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the application settings page
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
public function application()
|
||||||
|
{
|
||||||
|
$this->common('application');
|
||||||
|
|
||||||
|
$this->response->html($this->layout('config_application', array(
|
||||||
|
'title' => t('Application settings'),
|
||||||
'languages' => $this->config->getLanguages(),
|
'languages' => $this->config->getLanguages(),
|
||||||
'values' => $this->config->getAll(),
|
|
||||||
'errors' => array(),
|
|
||||||
'menu' => 'config',
|
|
||||||
'title' => t('Settings'),
|
|
||||||
'timezones' => $this->config->getTimezones(),
|
'timezones' => $this->config->getTimezones(),
|
||||||
|
'date_formats' => $this->dateParser->getAvailableFormats(),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the board settings page
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
public function board()
|
||||||
|
{
|
||||||
|
$this->common('board');
|
||||||
|
|
||||||
|
$this->response->html($this->layout('config_board', array(
|
||||||
|
'title' => t('Board settings'),
|
||||||
'default_columns' => implode(', ', $this->board->getDefaultColumns()),
|
'default_columns' => implode(', ', $this->board->getDefaultColumns()),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate and save settings
|
* Display the webhook settings page
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
*/
|
*/
|
||||||
public function save()
|
public function webhook()
|
||||||
{
|
{
|
||||||
$values = $this->request->getValues();
|
$this->common('webhook');
|
||||||
list($valid, $errors) = $this->config->validateModification($values);
|
|
||||||
|
|
||||||
if ($valid) {
|
$this->response->html($this->layout('config_webhook', array(
|
||||||
|
'title' => t('Webhook settings'),
|
||||||
if ($this->config->save($values)) {
|
)));
|
||||||
$this->config->reload();
|
|
||||||
$this->session->flash(t('Settings saved successfully.'));
|
|
||||||
} else {
|
|
||||||
$this->session->flashError(t('Unable to save your settings.'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->response->redirect('?controller=config');
|
/**
|
||||||
}
|
* Display the api settings page
|
||||||
|
*
|
||||||
$this->response->html($this->template->layout('config_index', array(
|
* @access public
|
||||||
'db_size' => $this->config->getDatabaseSize(),
|
*/
|
||||||
'languages' => $this->config->getLanguages(),
|
public function api()
|
||||||
'values' => $values,
|
{
|
||||||
'errors' => $errors,
|
$this->response->html($this->layout('config_api', array(
|
||||||
'menu' => 'config',
|
'title' => t('API'),
|
||||||
'title' => t('Settings'),
|
|
||||||
'timezones' => $this->config->getTimezones(),
|
|
||||||
'default_columns' => implode(', ', $this->board->getDefaultColumns()),
|
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,15 +149,18 @@ class Config extends Base
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Regenerate all application tokens
|
* Regenerate webhook token
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
*/
|
*/
|
||||||
public function tokens()
|
public function token()
|
||||||
{
|
{
|
||||||
|
$type = $this->request->getStringParam('type');
|
||||||
|
|
||||||
$this->checkCSRFParam();
|
$this->checkCSRFParam();
|
||||||
$this->config->regenerateTokens();
|
$this->config->regenerateToken($type.'_token');
|
||||||
$this->session->flash(t('All tokens have been regenerated.'));
|
|
||||||
$this->response->redirect('?controller=config');
|
$this->session->flash(t('Token regenerated.'));
|
||||||
|
$this->response->redirect('?controller=config&action='.$type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
namespace Controller;
|
namespace Controller;
|
||||||
|
|
||||||
use Model\Task as TaskModel;
|
use Model\Task as TaskModel;
|
||||||
use Core\Translator;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Project controller
|
* Project controller
|
||||||
|
@ -55,7 +54,7 @@ class Project extends Base
|
||||||
$this->response->html($this->projectLayout('project_show', array(
|
$this->response->html($this->projectLayout('project_show', array(
|
||||||
'project' => $project,
|
'project' => $project,
|
||||||
'stats' => $this->project->getStats($project['id']),
|
'stats' => $this->project->getStats($project['id']),
|
||||||
'menu' => 'projects',
|
'webhook_token' => $this->config->get('webhook_token'),
|
||||||
'title' => $project['name'],
|
'title' => $project['name'],
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
@ -67,12 +66,12 @@ class Project extends Base
|
||||||
*/
|
*/
|
||||||
public function export()
|
public function export()
|
||||||
{
|
{
|
||||||
$project = $this->getProject();
|
$project = $this->getProjectManagement();
|
||||||
$from = $this->request->getStringParam('from');
|
$from = $this->request->getStringParam('from');
|
||||||
$to = $this->request->getStringParam('to');
|
$to = $this->request->getStringParam('to');
|
||||||
|
|
||||||
if ($from && $to) {
|
if ($from && $to) {
|
||||||
$data = $this->task->export($project['id'], $from, $to);
|
$data = $this->taskExport->export($project['id'], $from, $to);
|
||||||
$this->response->forceDownload('Export_'.date('Y_m_d_H_i_S').'.csv');
|
$this->response->forceDownload('Export_'.date('Y_m_d_H_i_S').'.csv');
|
||||||
$this->response->csv($data);
|
$this->response->csv($data);
|
||||||
}
|
}
|
||||||
|
@ -86,7 +85,8 @@ class Project extends Base
|
||||||
'to' => $to,
|
'to' => $to,
|
||||||
),
|
),
|
||||||
'errors' => array(),
|
'errors' => array(),
|
||||||
'menu' => 'projects',
|
'date_format' => $this->config->get('application_date_format'),
|
||||||
|
'date_formats' => $this->dateParser->getAvailableFormats(),
|
||||||
'project' => $project,
|
'project' => $project,
|
||||||
'title' => t('Tasks Export')
|
'title' => t('Tasks Export')
|
||||||
)));
|
)));
|
||||||
|
@ -99,53 +99,28 @@ class Project extends Base
|
||||||
*/
|
*/
|
||||||
public function share()
|
public function share()
|
||||||
{
|
{
|
||||||
$project = $this->getProject();
|
$project = $this->getProjectManagement();
|
||||||
|
$switch = $this->request->getStringParam('switch');
|
||||||
|
|
||||||
|
if ($switch === 'enable' || $switch === 'disable') {
|
||||||
|
|
||||||
|
$this->checkCSRFParam();
|
||||||
|
|
||||||
|
if ($this->project->{$switch.'PublicAccess'}($project['id'])) {
|
||||||
|
$this->session->flash(t('Project updated successfully.'));
|
||||||
|
} else {
|
||||||
|
$this->session->flashError(t('Unable to update this project.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->response->redirect('?controller=project&action=share&project_id='.$project['id']);
|
||||||
|
}
|
||||||
|
|
||||||
$this->response->html($this->projectLayout('project_share', array(
|
$this->response->html($this->projectLayout('project_share', array(
|
||||||
'project' => $project,
|
'project' => $project,
|
||||||
'menu' => 'projects',
|
|
||||||
'title' => t('Public access'),
|
'title' => t('Public access'),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Enable public access for a project
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
*/
|
|
||||||
public function enablePublic()
|
|
||||||
{
|
|
||||||
$this->checkCSRFParam();
|
|
||||||
$project_id = $this->request->getIntegerParam('project_id');
|
|
||||||
|
|
||||||
if ($project_id && $this->project->enablePublicAccess($project_id)) {
|
|
||||||
$this->session->flash(t('Project updated successfully.'));
|
|
||||||
} else {
|
|
||||||
$this->session->flashError(t('Unable to update this project.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->response->redirect('?controller=project&action=share&project_id='.$project_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disable public access for a project
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
*/
|
|
||||||
public function disablePublic()
|
|
||||||
{
|
|
||||||
$this->checkCSRFParam();
|
|
||||||
$project_id = $this->request->getIntegerParam('project_id');
|
|
||||||
|
|
||||||
if ($project_id && $this->project->disablePublicAccess($project_id)) {
|
|
||||||
$this->session->flash(t('Project updated successfully.'));
|
|
||||||
} else {
|
|
||||||
$this->session->flashError(t('Unable to update this project.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->response->redirect('?controller=project&action=share&project_id='.$project_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display a form to edit a project
|
* Display a form to edit a project
|
||||||
*
|
*
|
||||||
|
@ -153,13 +128,12 @@ class Project extends Base
|
||||||
*/
|
*/
|
||||||
public function edit()
|
public function edit()
|
||||||
{
|
{
|
||||||
$project = $this->getProject();
|
$project = $this->getProjectManagement();
|
||||||
|
|
||||||
$this->response->html($this->projectLayout('project_edit', array(
|
$this->response->html($this->projectLayout('project_edit', array(
|
||||||
'errors' => array(),
|
'errors' => array(),
|
||||||
'values' => $project,
|
'values' => $project,
|
||||||
'project' => $project,
|
'project' => $project,
|
||||||
'menu' => 'projects',
|
|
||||||
'title' => t('Edit project')
|
'title' => t('Edit project')
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
@ -171,7 +145,7 @@ class Project extends Base
|
||||||
*/
|
*/
|
||||||
public function update()
|
public function update()
|
||||||
{
|
{
|
||||||
$project = $this->getProject();
|
$project = $this->getProjectManagement();
|
||||||
$values = $this->request->getValues() + array('is_active' => 0);
|
$values = $this->request->getValues() + array('is_active' => 0);
|
||||||
list($valid, $errors) = $this->project->validateModification($values);
|
list($valid, $errors) = $this->project->validateModification($values);
|
||||||
|
|
||||||
|
@ -190,7 +164,6 @@ class Project extends Base
|
||||||
'errors' => $errors,
|
'errors' => $errors,
|
||||||
'values' => $values,
|
'values' => $values,
|
||||||
'project' => $project,
|
'project' => $project,
|
||||||
'menu' => 'projects',
|
|
||||||
'title' => t('Edit Project')
|
'title' => t('Edit Project')
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
@ -202,29 +175,52 @@ class Project extends Base
|
||||||
*/
|
*/
|
||||||
public function users()
|
public function users()
|
||||||
{
|
{
|
||||||
$project = $this->getProject();
|
$project = $this->getProjectManagement();
|
||||||
|
|
||||||
$this->response->html($this->projectLayout('project_users', array(
|
$this->response->html($this->projectLayout('project_users', array(
|
||||||
'project' => $project,
|
'project' => $project,
|
||||||
'users' => $this->project->getAllUsers($project['id']),
|
'users' => $this->projectPermission->getAllUsers($project['id']),
|
||||||
'menu' => 'projects',
|
|
||||||
'title' => t('Edit project access list')
|
'title' => t('Edit project access list')
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allow a specific user for the selected project
|
* Allow everybody
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
public function allowEverybody()
|
||||||
|
{
|
||||||
|
$project = $this->getProjectManagement();
|
||||||
|
$values = $this->request->getValues() + array('is_everybody_allowed' => 0);
|
||||||
|
list($valid,) = $this->projectPermission->validateProjectModification($values);
|
||||||
|
|
||||||
|
if ($valid) {
|
||||||
|
|
||||||
|
if ($this->project->update($values)) {
|
||||||
|
$this->session->flash(t('Project updated successfully.'));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->session->flashError(t('Unable to update this project.'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->response->redirect('?controller=project&action=users&project_id='.$project['id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow a specific user (admin only)
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
*/
|
*/
|
||||||
public function allow()
|
public function allow()
|
||||||
{
|
{
|
||||||
$values = $this->request->getValues();
|
$values = $this->request->getValues();
|
||||||
list($valid,) = $this->project->validateUserAccess($values);
|
list($valid,) = $this->projectPermission->validateUserModification($values);
|
||||||
|
|
||||||
if ($valid) {
|
if ($valid) {
|
||||||
|
|
||||||
if ($this->project->allowUser($values['project_id'], $values['user_id'])) {
|
if ($this->projectPermission->allowUser($values['project_id'], $values['user_id'])) {
|
||||||
$this->session->flash(t('Project updated successfully.'));
|
$this->session->flash(t('Project updated successfully.'));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -236,7 +232,7 @@ class Project extends Base
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Revoke user access
|
* Revoke user access (admin only)
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
*/
|
*/
|
||||||
|
@ -249,11 +245,11 @@ class Project extends Base
|
||||||
'user_id' => $this->request->getIntegerParam('user_id'),
|
'user_id' => $this->request->getIntegerParam('user_id'),
|
||||||
);
|
);
|
||||||
|
|
||||||
list($valid,) = $this->project->validateUserAccess($values);
|
list($valid,) = $this->projectPermission->validateUserModification($values);
|
||||||
|
|
||||||
if ($valid) {
|
if ($valid) {
|
||||||
|
|
||||||
if ($this->project->revokeUser($values['project_id'], $values['user_id'])) {
|
if ($this->projectPermission->revokeUser($values['project_id'], $values['user_id'])) {
|
||||||
$this->session->flash(t('Project updated successfully.'));
|
$this->session->flash(t('Project updated successfully.'));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -264,22 +260,6 @@ class Project extends Base
|
||||||
$this->response->redirect('?controller=project&action=users&project_id='.$values['project_id']);
|
$this->response->redirect('?controller=project&action=users&project_id='.$values['project_id']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Confirmation dialog before to remove a project
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
*/
|
|
||||||
public function confirmRemove()
|
|
||||||
{
|
|
||||||
$project = $this->getProject();
|
|
||||||
|
|
||||||
$this->response->html($this->projectLayout('project_remove', array(
|
|
||||||
'project' => $project,
|
|
||||||
'menu' => 'projects',
|
|
||||||
'title' => t('Remove project')
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a project
|
* Remove a project
|
||||||
*
|
*
|
||||||
|
@ -287,10 +267,13 @@ class Project extends Base
|
||||||
*/
|
*/
|
||||||
public function remove()
|
public function remove()
|
||||||
{
|
{
|
||||||
$this->checkCSRFParam();
|
$project = $this->getProjectManagement();
|
||||||
$project_id = $this->request->getIntegerParam('project_id');
|
|
||||||
|
|
||||||
if ($project_id && $this->project->remove($project_id)) {
|
if ($this->request->getStringParam('remove') === 'yes') {
|
||||||
|
|
||||||
|
$this->checkCSRFParam();
|
||||||
|
|
||||||
|
if ($this->project->remove($project['id'])) {
|
||||||
$this->session->flash(t('Project removed successfully.'));
|
$this->session->flash(t('Project removed successfully.'));
|
||||||
} else {
|
} else {
|
||||||
$this->session->flashError(t('Unable to remove this project.'));
|
$this->session->flashError(t('Unable to remove this project.'));
|
||||||
|
@ -299,19 +282,9 @@ class Project extends Base
|
||||||
$this->response->redirect('?controller=project');
|
$this->response->redirect('?controller=project');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
$this->response->html($this->projectLayout('project_remove', array(
|
||||||
* Confirmation dialog before to clone a project
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
*/
|
|
||||||
public function confirmDuplicate()
|
|
||||||
{
|
|
||||||
$project = $this->getProject();
|
|
||||||
|
|
||||||
$this->response->html($this->projectLayout('project_duplicate', array(
|
|
||||||
'project' => $project,
|
'project' => $project,
|
||||||
'menu' => 'projects',
|
'title' => t('Remove project')
|
||||||
'title' => t('Clone this project')
|
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,10 +296,13 @@ class Project extends Base
|
||||||
*/
|
*/
|
||||||
public function duplicate()
|
public function duplicate()
|
||||||
{
|
{
|
||||||
$this->checkCSRFParam();
|
$project = $this->getProjectManagement();
|
||||||
$project_id = $this->request->getIntegerParam('project_id');
|
|
||||||
|
|
||||||
if ($project_id && $this->project->duplicate($project_id)) {
|
if ($this->request->getStringParam('duplicate') === 'yes') {
|
||||||
|
|
||||||
|
$this->checkCSRFParam();
|
||||||
|
|
||||||
|
if ($this->project->duplicate($project['id'])) {
|
||||||
$this->session->flash(t('Project cloned successfully.'));
|
$this->session->flash(t('Project cloned successfully.'));
|
||||||
} else {
|
} else {
|
||||||
$this->session->flashError(t('Unable to clone this project.'));
|
$this->session->flashError(t('Unable to clone this project.'));
|
||||||
|
@ -335,19 +311,9 @@ class Project extends Base
|
||||||
$this->response->redirect('?controller=project');
|
$this->response->redirect('?controller=project');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
$this->response->html($this->projectLayout('project_duplicate', array(
|
||||||
* Confirmation dialog before to disable a project
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
*/
|
|
||||||
public function confirmDisable()
|
|
||||||
{
|
|
||||||
$project = $this->getProject();
|
|
||||||
|
|
||||||
$this->response->html($this->projectLayout('project_disable', array(
|
|
||||||
'project' => $project,
|
'project' => $project,
|
||||||
'menu' => 'projects',
|
'title' => t('Clone this project')
|
||||||
'title' => t('Project activation')
|
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -358,30 +324,23 @@ class Project extends Base
|
||||||
*/
|
*/
|
||||||
public function disable()
|
public function disable()
|
||||||
{
|
{
|
||||||
$this->checkCSRFParam();
|
$project = $this->getProjectManagement();
|
||||||
$project_id = $this->request->getIntegerParam('project_id');
|
|
||||||
|
|
||||||
if ($project_id && $this->project->disable($project_id)) {
|
if ($this->request->getStringParam('disable') === 'yes') {
|
||||||
|
|
||||||
|
$this->checkCSRFParam();
|
||||||
|
|
||||||
|
if ($this->project->disable($project['id'])) {
|
||||||
$this->session->flash(t('Project disabled successfully.'));
|
$this->session->flash(t('Project disabled successfully.'));
|
||||||
} else {
|
} else {
|
||||||
$this->session->flashError(t('Unable to disable this project.'));
|
$this->session->flashError(t('Unable to disable this project.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->response->redirect('?controller=project&action=show&project_id='.$project_id);
|
$this->response->redirect('?controller=project&action=show&project_id='.$project['id']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
$this->response->html($this->projectLayout('project_disable', array(
|
||||||
* Confirmation dialog before to enable a project
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
*/
|
|
||||||
public function confirmEnable()
|
|
||||||
{
|
|
||||||
$project = $this->getProject();
|
|
||||||
|
|
||||||
$this->response->html($this->projectLayout('project_enable', array(
|
|
||||||
'project' => $project,
|
'project' => $project,
|
||||||
'menu' => 'projects',
|
|
||||||
'title' => t('Project activation')
|
'title' => t('Project activation')
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
@ -393,20 +352,29 @@ class Project extends Base
|
||||||
*/
|
*/
|
||||||
public function enable()
|
public function enable()
|
||||||
{
|
{
|
||||||
$this->checkCSRFParam();
|
$project = $this->getProjectManagement();
|
||||||
$project_id = $this->request->getIntegerParam('project_id');
|
|
||||||
|
|
||||||
if ($project_id && $this->project->enable($project_id)) {
|
if ($this->request->getStringParam('enable') === 'yes') {
|
||||||
|
|
||||||
|
$this->checkCSRFParam();
|
||||||
|
|
||||||
|
if ($this->project->enable($project['id'])) {
|
||||||
$this->session->flash(t('Project activated successfully.'));
|
$this->session->flash(t('Project activated successfully.'));
|
||||||
} else {
|
} else {
|
||||||
$this->session->flashError(t('Unable to activate this project.'));
|
$this->session->flashError(t('Unable to activate this project.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->response->redirect('?controller=project&action=show&project_id='.$project_id);
|
$this->response->redirect('?controller=project&action=show&project_id='.$project['id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->response->html($this->projectLayout('project_enable', array(
|
||||||
|
'project' => $project,
|
||||||
|
'title' => t('Project activation')
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RSS feed for a project
|
* RSS feed for a project (public)
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
*/
|
*/
|
||||||
|
@ -421,7 +389,7 @@ class Project extends Base
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->response->xml($this->template->load('project_feed', array(
|
$this->response->xml($this->template->load('project_feed', array(
|
||||||
'events' => $this->project->getActivity($project['id']),
|
'events' => $this->projectActivity->getProject($project['id']),
|
||||||
'project' => $project,
|
'project' => $project,
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
@ -436,7 +404,7 @@ class Project extends Base
|
||||||
$project = $this->getProject();
|
$project = $this->getProject();
|
||||||
|
|
||||||
$this->response->html($this->template->layout('project_activity', array(
|
$this->response->html($this->template->layout('project_activity', array(
|
||||||
'events' => $this->project->getActivity($project['id']),
|
'events' => $this->projectActivity->getProject($project['id']),
|
||||||
'menu' => 'projects',
|
'menu' => 'projects',
|
||||||
'project' => $project,
|
'project' => $project,
|
||||||
'title' => t('%s\'s activity', $project['name'])
|
'title' => t('%s\'s activity', $project['name'])
|
||||||
|
@ -452,34 +420,39 @@ class Project extends Base
|
||||||
{
|
{
|
||||||
$project = $this->getProject();
|
$project = $this->getProject();
|
||||||
$search = $this->request->getStringParam('search');
|
$search = $this->request->getStringParam('search');
|
||||||
|
$direction = $this->request->getStringParam('direction', 'DESC');
|
||||||
|
$order = $this->request->getStringParam('order', 'tasks.id');
|
||||||
|
$offset = $this->request->getIntegerParam('offset', 0);
|
||||||
$tasks = array();
|
$tasks = array();
|
||||||
$nb_tasks = 0;
|
$nb_tasks = 0;
|
||||||
|
$limit = 25;
|
||||||
|
|
||||||
if ($search !== '') {
|
if ($search !== '') {
|
||||||
|
$tasks = $this->taskFinder->search($project['id'], $search, $offset, $limit, $order, $direction);
|
||||||
$filters = array(
|
$nb_tasks = $this->taskFinder->countSearch($project['id'], $search);
|
||||||
array('column' => 'project_id', 'operator' => 'eq', 'value' => $project['id']),
|
|
||||||
'or' => array(
|
|
||||||
array('column' => 'title', 'operator' => 'like', 'value' => '%'.$search.'%'),
|
|
||||||
//array('column' => 'description', 'operator' => 'like', 'value' => '%'.$search.'%'),
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
$tasks = $this->task->find($filters);
|
|
||||||
$nb_tasks = count($tasks);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->response->html($this->template->layout('project_search', array(
|
$this->response->html($this->template->layout('project_search', array(
|
||||||
'tasks' => $tasks,
|
'tasks' => $tasks,
|
||||||
'nb_tasks' => $nb_tasks,
|
'nb_tasks' => $nb_tasks,
|
||||||
|
'pagination' => array(
|
||||||
|
'controller' => 'project',
|
||||||
|
'action' => 'search',
|
||||||
|
'params' => array('search' => $search, 'project_id' => $project['id']),
|
||||||
|
'direction' => $direction,
|
||||||
|
'order' => $order,
|
||||||
|
'total' => $nb_tasks,
|
||||||
|
'offset' => $offset,
|
||||||
|
'limit' => $limit,
|
||||||
|
),
|
||||||
'values' => array(
|
'values' => array(
|
||||||
'search' => $search,
|
'search' => $search,
|
||||||
'controller' => 'project',
|
'controller' => 'project',
|
||||||
'action' => 'search',
|
'action' => 'search',
|
||||||
'project_id' => $project['id'],
|
'project_id' => $project['id'],
|
||||||
),
|
),
|
||||||
'menu' => 'projects',
|
|
||||||
'project' => $project,
|
'project' => $project,
|
||||||
|
'menu' => 'projects',
|
||||||
'columns' => $this->board->getColumnsList($project['id']),
|
'columns' => $this->board->getColumnsList($project['id']),
|
||||||
'categories' => $this->category->getList($project['id'], false),
|
'categories' => $this->category->getList($project['id'], false),
|
||||||
'title' => $project['name'].($nb_tasks > 0 ? ' ('.$nb_tasks.')' : '')
|
'title' => $project['name'].($nb_tasks > 0 ? ' ('.$nb_tasks.')' : '')
|
||||||
|
@ -494,18 +467,27 @@ class Project extends Base
|
||||||
public function tasks()
|
public function tasks()
|
||||||
{
|
{
|
||||||
$project = $this->getProject();
|
$project = $this->getProject();
|
||||||
|
$direction = $this->request->getStringParam('direction', 'DESC');
|
||||||
|
$order = $this->request->getStringParam('order', 'tasks.date_completed');
|
||||||
|
$offset = $this->request->getIntegerParam('offset', 0);
|
||||||
|
$limit = 25;
|
||||||
|
|
||||||
$filters = array(
|
$tasks = $this->taskFinder->getClosedTasks($project['id'], $offset, $limit, $order, $direction);
|
||||||
array('column' => 'project_id', 'operator' => 'eq', 'value' => $project['id']),
|
$nb_tasks = $this->taskFinder->countByProjectId($project['id'], array(TaskModel::STATUS_CLOSED));
|
||||||
array('column' => 'is_active', 'operator' => 'eq', 'value' => TaskModel::STATUS_CLOSED),
|
|
||||||
);
|
|
||||||
|
|
||||||
$tasks = $this->task->find($filters);
|
|
||||||
$nb_tasks = count($tasks);
|
|
||||||
|
|
||||||
$this->response->html($this->template->layout('project_tasks', array(
|
$this->response->html($this->template->layout('project_tasks', array(
|
||||||
'menu' => 'projects',
|
'pagination' => array(
|
||||||
|
'controller' => 'project',
|
||||||
|
'action' => 'tasks',
|
||||||
|
'params' => array('project_id' => $project['id']),
|
||||||
|
'direction' => $direction,
|
||||||
|
'order' => $order,
|
||||||
|
'total' => $nb_tasks,
|
||||||
|
'offset' => $offset,
|
||||||
|
'limit' => $limit,
|
||||||
|
),
|
||||||
'project' => $project,
|
'project' => $project,
|
||||||
|
'menu' => 'projects',
|
||||||
'columns' => $this->board->getColumnsList($project['id']),
|
'columns' => $this->board->getColumnsList($project['id']),
|
||||||
'categories' => $this->category->getList($project['id'], false),
|
'categories' => $this->category->getList($project['id'], false),
|
||||||
'tasks' => $tasks,
|
'tasks' => $tasks,
|
||||||
|
@ -523,8 +505,9 @@ class Project extends Base
|
||||||
{
|
{
|
||||||
$this->response->html($this->template->layout('project_new', array(
|
$this->response->html($this->template->layout('project_new', array(
|
||||||
'errors' => array(),
|
'errors' => array(),
|
||||||
'values' => array(),
|
'values' => array(
|
||||||
'menu' => 'projects',
|
'is_private' => $this->request->getIntegerParam('private', $this->acl->isRegularUser()),
|
||||||
|
),
|
||||||
'title' => t('New project')
|
'title' => t('New project')
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
@ -541,7 +524,7 @@ class Project extends Base
|
||||||
|
|
||||||
if ($valid) {
|
if ($valid) {
|
||||||
|
|
||||||
if ($this->project->create($values)) {
|
if ($this->project->create($values, $this->acl->getUserId())) {
|
||||||
$this->session->flash(t('Your project have been created successfully.'));
|
$this->session->flash(t('Your project have been created successfully.'));
|
||||||
$this->response->redirect('?controller=project');
|
$this->response->redirect('?controller=project');
|
||||||
}
|
}
|
||||||
|
@ -553,7 +536,6 @@ class Project extends Base
|
||||||
$this->response->html($this->template->layout('project_new', array(
|
$this->response->html($this->template->layout('project_new', array(
|
||||||
'errors' => $errors,
|
'errors' => $errors,
|
||||||
'values' => $values,
|
'values' => $values,
|
||||||
'menu' => 'projects',
|
|
||||||
'title' => t('New Project')
|
'title' => t('New Project')
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,9 +39,10 @@ class Subtask extends Base
|
||||||
$this->response->html($this->taskLayout('subtask_create', array(
|
$this->response->html($this->taskLayout('subtask_create', array(
|
||||||
'values' => array(
|
'values' => array(
|
||||||
'task_id' => $task['id'],
|
'task_id' => $task['id'],
|
||||||
|
'another_subtask' => $this->request->getIntegerParam('another_subtask', 0)
|
||||||
),
|
),
|
||||||
'errors' => array(),
|
'errors' => array(),
|
||||||
'users_list' => $this->project->getUsersList($task['project_id']),
|
'users_list' => $this->projectPermission->getUsersList($task['project_id']),
|
||||||
'task' => $task,
|
'task' => $task,
|
||||||
'menu' => 'tasks',
|
'menu' => 'tasks',
|
||||||
'title' => t('Add a sub-task')
|
'title' => t('Add a sub-task')
|
||||||
|
@ -70,7 +71,7 @@ class Subtask extends Base
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($values['another_subtask']) && $values['another_subtask'] == 1) {
|
if (isset($values['another_subtask']) && $values['another_subtask'] == 1) {
|
||||||
$this->response->redirect('?controller=subtask&action=create&task_id='.$task['id']);
|
$this->response->redirect('?controller=subtask&action=create&task_id='.$task['id'].'&another_subtask=1');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'#subtasks');
|
$this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'#subtasks');
|
||||||
|
@ -79,7 +80,7 @@ class Subtask extends Base
|
||||||
$this->response->html($this->taskLayout('subtask_create', array(
|
$this->response->html($this->taskLayout('subtask_create', array(
|
||||||
'values' => $values,
|
'values' => $values,
|
||||||
'errors' => $errors,
|
'errors' => $errors,
|
||||||
'users_list' => $this->project->getUsersList($task['project_id']),
|
'users_list' => $this->projectPermission->getUsersList($task['project_id']),
|
||||||
'task' => $task,
|
'task' => $task,
|
||||||
'menu' => 'tasks',
|
'menu' => 'tasks',
|
||||||
'title' => t('Add a sub-task')
|
'title' => t('Add a sub-task')
|
||||||
|
@ -99,7 +100,7 @@ class Subtask extends Base
|
||||||
$this->response->html($this->taskLayout('subtask_edit', array(
|
$this->response->html($this->taskLayout('subtask_edit', array(
|
||||||
'values' => $subtask,
|
'values' => $subtask,
|
||||||
'errors' => array(),
|
'errors' => array(),
|
||||||
'users_list' => $this->project->getUsersList($task['project_id']),
|
'users_list' => $this->projectPermission->getUsersList($task['project_id']),
|
||||||
'status_list' => $this->subTask->getStatusList(),
|
'status_list' => $this->subTask->getStatusList(),
|
||||||
'subtask' => $subtask,
|
'subtask' => $subtask,
|
||||||
'task' => $task,
|
'task' => $task,
|
||||||
|
@ -136,7 +137,7 @@ class Subtask extends Base
|
||||||
$this->response->html($this->taskLayout('subtask_edit', array(
|
$this->response->html($this->taskLayout('subtask_edit', array(
|
||||||
'values' => $values,
|
'values' => $values,
|
||||||
'errors' => $errors,
|
'errors' => $errors,
|
||||||
'users_list' => $this->project->getUsersList($task['project_id']),
|
'users_list' => $this->projectPermission->getUsersList($task['project_id']),
|
||||||
'status_list' => $this->subTask->getStatusList(),
|
'status_list' => $this->subTask->getStatusList(),
|
||||||
'subtask' => $subtask,
|
'subtask' => $subtask,
|
||||||
'task' => $task,
|
'task' => $task,
|
||||||
|
@ -183,4 +184,27 @@ class Subtask extends Base
|
||||||
|
|
||||||
$this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'#subtasks');
|
$this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'#subtasks');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change status to the next status: Toto -> In Progress -> Done
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
public function toggleStatus()
|
||||||
|
{
|
||||||
|
$task = $this->getTask();
|
||||||
|
$subtask = $this->getSubtask();
|
||||||
|
|
||||||
|
$value = array(
|
||||||
|
'id' => $subtask['id'],
|
||||||
|
'status' => ($subtask['status'] + 1) % 3,
|
||||||
|
'task_id' => $task['id'],
|
||||||
|
);
|
||||||
|
|
||||||
|
if (! $this->subTask->update($value)) {
|
||||||
|
$this->session->flashError(t('Unable to update your sub-task.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'#subtasks');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,40 +12,6 @@ use Model\Project as ProjectModel;
|
||||||
*/
|
*/
|
||||||
class Task extends Base
|
class Task extends Base
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Webhook to create a task (useful for external software)
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
*/
|
|
||||||
public function add()
|
|
||||||
{
|
|
||||||
$token = $this->request->getStringParam('token');
|
|
||||||
|
|
||||||
if ($this->config->get('webhooks_token') !== $token) {
|
|
||||||
$this->response->text('Not Authorized', 401);
|
|
||||||
}
|
|
||||||
|
|
||||||
$defaultProject = $this->project->getFirst();
|
|
||||||
|
|
||||||
$values = array(
|
|
||||||
'title' => $this->request->getStringParam('title'),
|
|
||||||
'description' => $this->request->getStringParam('description'),
|
|
||||||
'color_id' => $this->request->getStringParam('color_id'),
|
|
||||||
'project_id' => $this->request->getIntegerParam('project_id', $defaultProject['id']),
|
|
||||||
'owner_id' => $this->request->getIntegerParam('owner_id'),
|
|
||||||
'column_id' => $this->request->getIntegerParam('column_id'),
|
|
||||||
'category_id' => $this->request->getIntegerParam('category_id'),
|
|
||||||
);
|
|
||||||
|
|
||||||
list($valid,) = $this->task->validateCreation($values);
|
|
||||||
|
|
||||||
if ($valid && $this->task->create($values)) {
|
|
||||||
$this->response->text('OK');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->response->text('FAILED');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Public access (display a task)
|
* Public access (display a task)
|
||||||
*
|
*
|
||||||
|
@ -60,7 +26,7 @@ class Task extends Base
|
||||||
$this->forbidden(true);
|
$this->forbidden(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
$task = $this->task->getById($this->request->getIntegerParam('task_id'), true);
|
$task = $this->taskFinder->getDetails($this->request->getIntegerParam('task_id'));
|
||||||
|
|
||||||
if (! $task) {
|
if (! $task) {
|
||||||
$this->notfound(true);
|
$this->notfound(true);
|
||||||
|
@ -72,7 +38,7 @@ class Task extends Base
|
||||||
'subtasks' => $this->subTask->getAll($task['id']),
|
'subtasks' => $this->subTask->getAll($task['id']),
|
||||||
'task' => $task,
|
'task' => $task,
|
||||||
'columns_list' => $this->board->getColumnsList($task['project_id']),
|
'columns_list' => $this->board->getColumnsList($task['project_id']),
|
||||||
'colors_list' => $this->task->getColors(),
|
'colors_list' => $this->color->getList(),
|
||||||
'title' => $task['title'],
|
'title' => $task['title'],
|
||||||
'no_layout' => true,
|
'no_layout' => true,
|
||||||
'auto_refresh' => true,
|
'auto_refresh' => true,
|
||||||
|
@ -88,15 +54,29 @@ class Task extends Base
|
||||||
public function show()
|
public function show()
|
||||||
{
|
{
|
||||||
$task = $this->getTask();
|
$task = $this->getTask();
|
||||||
|
$subtasks = $this->subTask->getAll($task['id']);
|
||||||
|
|
||||||
|
$values = array(
|
||||||
|
'id' => $task['id'],
|
||||||
|
'date_started' => $task['date_started'],
|
||||||
|
'time_estimated' => $task['time_estimated'] ?: '',
|
||||||
|
'time_spent' => $task['time_spent'] ?: '',
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->dateParser->format($values, array('date_started'));
|
||||||
|
|
||||||
$this->response->html($this->taskLayout('task_show', array(
|
$this->response->html($this->taskLayout('task_show', array(
|
||||||
'project' => $this->project->getById($task['project_id']),
|
'project' => $this->project->getById($task['project_id']),
|
||||||
'files' => $this->file->getAll($task['id']),
|
'files' => $this->file->getAll($task['id']),
|
||||||
'comments' => $this->comment->getAll($task['id']),
|
'comments' => $this->comment->getAll($task['id']),
|
||||||
'subtasks' => $this->subTask->getAll($task['id']),
|
'subtasks' => $subtasks,
|
||||||
'task' => $task,
|
'task' => $task,
|
||||||
|
'values' => $values,
|
||||||
|
'timesheet' => $this->timeTracking->getTaskTimesheet($task, $subtasks),
|
||||||
'columns_list' => $this->board->getColumnsList($task['project_id']),
|
'columns_list' => $this->board->getColumnsList($task['project_id']),
|
||||||
'colors_list' => $this->task->getColors(),
|
'colors_list' => $this->color->getList(),
|
||||||
|
'date_format' => $this->config->get('application_date_format'),
|
||||||
|
'date_formats' => $this->dateParser->getAvailableFormats(),
|
||||||
'menu' => 'tasks',
|
'menu' => 'tasks',
|
||||||
'title' => $task['title'],
|
'title' => $task['title'],
|
||||||
)));
|
)));
|
||||||
|
@ -123,9 +103,11 @@ class Task extends Base
|
||||||
),
|
),
|
||||||
'projects_list' => $this->project->getListByStatus(ProjectModel::ACTIVE),
|
'projects_list' => $this->project->getListByStatus(ProjectModel::ACTIVE),
|
||||||
'columns_list' => $this->board->getColumnsList($project_id),
|
'columns_list' => $this->board->getColumnsList($project_id),
|
||||||
'users_list' => $this->project->getUsersList($project_id),
|
'users_list' => $this->projectPermission->getUsersList($project_id),
|
||||||
'colors_list' => $this->task->getColors(),
|
'colors_list' => $this->color->getList(),
|
||||||
'categories_list' => $this->category->getList($project_id),
|
'categories_list' => $this->category->getList($project_id),
|
||||||
|
'date_format' => $this->config->get('application_date_format'),
|
||||||
|
'date_formats' => $this->dateParser->getAvailableFormats(),
|
||||||
'menu' => 'tasks',
|
'menu' => 'tasks',
|
||||||
'title' => t('New task')
|
'title' => t('New task')
|
||||||
)));
|
)));
|
||||||
|
@ -143,7 +125,7 @@ class Task extends Base
|
||||||
|
|
||||||
$this->checkProjectPermissions($values['project_id']);
|
$this->checkProjectPermissions($values['project_id']);
|
||||||
|
|
||||||
list($valid, $errors) = $this->task->validateCreation($values);
|
list($valid, $errors) = $this->taskValidator->validateCreation($values);
|
||||||
|
|
||||||
if ($valid) {
|
if ($valid) {
|
||||||
|
|
||||||
|
@ -169,9 +151,11 @@ class Task extends Base
|
||||||
'values' => $values,
|
'values' => $values,
|
||||||
'projects_list' => $this->project->getListByStatus(ProjectModel::ACTIVE),
|
'projects_list' => $this->project->getListByStatus(ProjectModel::ACTIVE),
|
||||||
'columns_list' => $this->board->getColumnsList($values['project_id']),
|
'columns_list' => $this->board->getColumnsList($values['project_id']),
|
||||||
'users_list' => $this->project->getUsersList($values['project_id']),
|
'users_list' => $this->projectPermission->getUsersList($values['project_id']),
|
||||||
'colors_list' => $this->task->getColors(),
|
'colors_list' => $this->color->getList(),
|
||||||
'categories_list' => $this->category->getList($values['project_id']),
|
'categories_list' => $this->category->getList($values['project_id']),
|
||||||
|
'date_format' => $this->config->get('application_date_format'),
|
||||||
|
'date_formats' => $this->dateParser->getAvailableFormats(),
|
||||||
'menu' => 'tasks',
|
'menu' => 'tasks',
|
||||||
'title' => t('New task')
|
'title' => t('New task')
|
||||||
)));
|
)));
|
||||||
|
@ -185,32 +169,29 @@ class Task extends Base
|
||||||
public function edit()
|
public function edit()
|
||||||
{
|
{
|
||||||
$task = $this->getTask();
|
$task = $this->getTask();
|
||||||
|
$ajax = $this->request->isAjax();
|
||||||
|
|
||||||
if (! empty($task['date_due'])) {
|
$this->dateParser->format($task, array('date_due'));
|
||||||
$task['date_due'] = date(t('m/d/Y'), $task['date_due']);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$task['date_due'] = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
$task['score'] = $task['score'] ?: '';
|
|
||||||
|
|
||||||
$params = array(
|
$params = array(
|
||||||
'values' => $task,
|
'values' => $task,
|
||||||
'errors' => array(),
|
'errors' => array(),
|
||||||
'task' => $task,
|
'task' => $task,
|
||||||
'users_list' => $this->project->getUsersList($task['project_id']),
|
'users_list' => $this->projectPermission->getUsersList($task['project_id']),
|
||||||
'colors_list' => $this->task->getColors(),
|
'colors_list' => $this->color->getList(),
|
||||||
'categories_list' => $this->category->getList($task['project_id']),
|
'categories_list' => $this->category->getList($task['project_id']),
|
||||||
'ajax' => $this->request->isAjax(),
|
'date_format' => $this->config->get('application_date_format'),
|
||||||
|
'date_formats' => $this->dateParser->getAvailableFormats(),
|
||||||
|
'ajax' => $ajax,
|
||||||
'menu' => 'tasks',
|
'menu' => 'tasks',
|
||||||
'title' => t('Edit a task')
|
'title' => t('Edit a task')
|
||||||
);
|
);
|
||||||
if ($this->request->isAjax()) {
|
|
||||||
|
if ($ajax) {
|
||||||
$this->response->html($this->template->load('task_edit', $params));
|
$this->response->html($this->template->load('task_edit', $params));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$this->response->html($this->template->layout('task_edit', $params));
|
$this->response->html($this->taskLayout('task_edit', $params));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,7 +205,7 @@ class Task extends Base
|
||||||
$task = $this->getTask();
|
$task = $this->getTask();
|
||||||
$values = $this->request->getValues();
|
$values = $this->request->getValues();
|
||||||
|
|
||||||
list($valid, $errors) = $this->task->validateModification($values);
|
list($valid, $errors) = $this->taskValidator->validateModification($values);
|
||||||
|
|
||||||
if ($valid) {
|
if ($valid) {
|
||||||
|
|
||||||
|
@ -235,7 +216,7 @@ class Task extends Base
|
||||||
$this->response->redirect('?controller=board&action=show&project_id='.$task['project_id']);
|
$this->response->redirect('?controller=board&action=show&project_id='.$task['project_id']);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$this->response->redirect('?controller=task&action=show&task_id='.$values['id']);
|
$this->response->redirect('?controller=task&action=show&task_id='.$task['id']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -243,19 +224,44 @@ class Task extends Base
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->response->html($this->template->layout('task_edit', array(
|
$this->response->html($this->taskLayout('task_edit', array(
|
||||||
'values' => $values,
|
'values' => $values,
|
||||||
'errors' => $errors,
|
'errors' => $errors,
|
||||||
'task' => $task,
|
'task' => $task,
|
||||||
'columns_list' => $this->board->getColumnsList($values['project_id']),
|
'columns_list' => $this->board->getColumnsList($values['project_id']),
|
||||||
'users_list' => $this->project->getUsersList($values['project_id']),
|
'users_list' => $this->projectPermission->getUsersList($values['project_id']),
|
||||||
'colors_list' => $this->task->getColors(),
|
'colors_list' => $this->color->getList(),
|
||||||
'categories_list' => $this->category->getList($values['project_id']),
|
'categories_list' => $this->category->getList($values['project_id']),
|
||||||
|
'date_format' => $this->config->get('application_date_format'),
|
||||||
|
'date_formats' => $this->dateParser->getAvailableFormats(),
|
||||||
'menu' => 'tasks',
|
'menu' => 'tasks',
|
||||||
'title' => t('Edit a task')
|
'title' => t('Edit a task'),
|
||||||
|
'ajax' => $this->request->isAjax(),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update time tracking information
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
public function time()
|
||||||
|
{
|
||||||
|
$task = $this->getTask();
|
||||||
|
$values = $this->request->getValues();
|
||||||
|
|
||||||
|
list($valid, $errors) = $this->taskValidator->validateTimeModification($values);
|
||||||
|
|
||||||
|
if ($valid && $this->task->update($values)) {
|
||||||
|
$this->session->flash(t('Task updated successfully.'));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->session->flashError(t('Unable to update your task.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->response->redirect('?controller=task&action=show&task_id='.$task['id']);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hide a task
|
* Hide a task
|
||||||
*
|
*
|
||||||
|
@ -323,6 +329,10 @@ class Task extends Base
|
||||||
{
|
{
|
||||||
$task = $this->getTask();
|
$task = $this->getTask();
|
||||||
|
|
||||||
|
if (! $this->taskPermission->canRemoveTask($task)) {
|
||||||
|
$this->forbidden();
|
||||||
|
}
|
||||||
|
|
||||||
if ($this->request->getStringParam('confirmation') === 'yes') {
|
if ($this->request->getStringParam('confirmation') === 'yes') {
|
||||||
|
|
||||||
$this->checkCSRFParam();
|
$this->checkCSRFParam();
|
||||||
|
@ -355,7 +365,7 @@ class Task extends Base
|
||||||
if ($this->request->getStringParam('confirmation') === 'yes') {
|
if ($this->request->getStringParam('confirmation') === 'yes') {
|
||||||
|
|
||||||
$this->checkCSRFParam();
|
$this->checkCSRFParam();
|
||||||
$task_id = $this->task->duplicateSameProject($task);
|
$task_id = $this->task->duplicateToSameProject($task);
|
||||||
|
|
||||||
if ($task_id) {
|
if ($task_id) {
|
||||||
$this->session->flash(t('Task created successfully.'));
|
$this->session->flash(t('Task created successfully.'));
|
||||||
|
@ -387,7 +397,7 @@ class Task extends Base
|
||||||
|
|
||||||
$values = $this->request->getValues();
|
$values = $this->request->getValues();
|
||||||
|
|
||||||
list($valid, $errors) = $this->task->validateDescriptionCreation($values);
|
list($valid, $errors) = $this->taskValidator->validateDescriptionCreation($values);
|
||||||
|
|
||||||
if ($valid) {
|
if ($valid) {
|
||||||
|
|
||||||
|
@ -458,14 +468,14 @@ class Task extends Base
|
||||||
$task = $this->getTask();
|
$task = $this->getTask();
|
||||||
$values = $task;
|
$values = $task;
|
||||||
$errors = array();
|
$errors = array();
|
||||||
$projects_list = $this->project->getAvailableList($this->acl->getUserId());
|
$projects_list = $this->projectPermission->getAllowedProjects($this->acl->getUserId());
|
||||||
|
|
||||||
unset($projects_list[$task['project_id']]);
|
unset($projects_list[$task['project_id']]);
|
||||||
|
|
||||||
if ($this->request->isPost()) {
|
if ($this->request->isPost()) {
|
||||||
|
|
||||||
$values = $this->request->getValues();
|
$values = $this->request->getValues();
|
||||||
list($valid, $errors) = $this->task->validateProjectModification($values);
|
list($valid, $errors) = $this->taskValidator->validateProjectModification($values);
|
||||||
|
|
||||||
if ($valid) {
|
if ($valid) {
|
||||||
$task_id = $this->task->{$action.'ToAnotherProject'}($values['project_id'], $task);
|
$task_id = $this->task->{$action.'ToAnotherProject'}($values['project_id'], $task);
|
||||||
|
|
|
@ -38,6 +38,7 @@ class User extends Base
|
||||||
'errors' => array(),
|
'errors' => array(),
|
||||||
'values' => array(),
|
'values' => array(),
|
||||||
'no_layout' => true,
|
'no_layout' => true,
|
||||||
|
'redirect_query' => $this->request->getStringParam('redirect_query'),
|
||||||
'title' => t('Login')
|
'title' => t('Login')
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
@ -49,23 +50,30 @@ class User extends Base
|
||||||
*/
|
*/
|
||||||
public function check()
|
public function check()
|
||||||
{
|
{
|
||||||
|
$redirect_query = $this->request->getStringParam('redirect_query');
|
||||||
$values = $this->request->getValues();
|
$values = $this->request->getValues();
|
||||||
list($valid, $errors) = $this->authentication->validateForm($values);
|
list($valid, $errors) = $this->authentication->validateForm($values);
|
||||||
|
|
||||||
if ($valid) {
|
if ($valid) {
|
||||||
$this->response->redirect('?controller=board');
|
if ($redirect_query !== '') {
|
||||||
|
$this->response->redirect('?'.$redirect_query);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->response->redirect('?controller=app');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->response->html($this->template->layout('user_login', array(
|
$this->response->html($this->template->layout('user_login', array(
|
||||||
'errors' => $errors,
|
'errors' => $errors,
|
||||||
'values' => $values,
|
'values' => $values,
|
||||||
'no_layout' => true,
|
'no_layout' => true,
|
||||||
|
'redirect_query' => $redirect_query,
|
||||||
'title' => t('Login')
|
'title' => t('Login')
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Common layout for project views
|
* Common layout for user views
|
||||||
*
|
*
|
||||||
* @access private
|
* @access private
|
||||||
* @param string $template Template name
|
* @param string $template Template name
|
||||||
|
@ -113,16 +121,31 @@ class User extends Base
|
||||||
*/
|
*/
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
$users = $this->user->getAll();
|
$direction = $this->request->getStringParam('direction', 'ASC');
|
||||||
$nb_users = count($users);
|
$order = $this->request->getStringParam('order', 'username');
|
||||||
|
$offset = $this->request->getIntegerParam('offset', 0);
|
||||||
|
$limit = 25;
|
||||||
|
|
||||||
|
$users = $this->user->paginate($offset, $limit, $order, $direction);
|
||||||
|
$nb_users = $this->user->count();
|
||||||
|
|
||||||
$this->response->html(
|
$this->response->html(
|
||||||
$this->template->layout('user_index', array(
|
$this->template->layout('user_index', array(
|
||||||
'projects' => $this->project->getList(),
|
'projects' => $this->project->getList(),
|
||||||
'users' => $users,
|
|
||||||
'nb_users' => $nb_users,
|
'nb_users' => $nb_users,
|
||||||
|
'users' => $users,
|
||||||
'menu' => 'users',
|
'menu' => 'users',
|
||||||
'title' => t('Users').' ('.$nb_users.')'
|
'title' => t('Users').' ('.$nb_users.')',
|
||||||
|
'pagination' => array(
|
||||||
|
'controller' => 'user',
|
||||||
|
'action' => 'index',
|
||||||
|
'direction' => $direction,
|
||||||
|
'order' => $order,
|
||||||
|
'total' => $nb_users,
|
||||||
|
'offset' => $offset,
|
||||||
|
'limit' => $limit,
|
||||||
|
'params' => array(),
|
||||||
|
),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,7 +204,7 @@ class User extends Base
|
||||||
{
|
{
|
||||||
$user = $this->getUser();
|
$user = $this->getUser();
|
||||||
$this->response->html($this->layout('user_show', array(
|
$this->response->html($this->layout('user_show', array(
|
||||||
'projects' => $this->project->getAvailableList($user['id']),
|
'projects' => $this->projectPermission->getAllowedProjects($user['id']),
|
||||||
'user' => $user,
|
'user' => $user,
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
@ -244,7 +267,7 @@ class User extends Base
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->response->html($this->layout('user_notifications', array(
|
$this->response->html($this->layout('user_notifications', array(
|
||||||
'projects' => $this->project->getAvailableList($user['id']),
|
'projects' => $this->projectPermission->getAllowedProjects($user['id']),
|
||||||
'notifications' => $this->notification->readSettings($user['id']),
|
'notifications' => $this->notification->readSettings($user['id']),
|
||||||
'user' => $user,
|
'user' => $user,
|
||||||
)));
|
)));
|
||||||
|
@ -345,7 +368,7 @@ class User extends Base
|
||||||
$this->response->html($this->layout('user_edit', array(
|
$this->response->html($this->layout('user_edit', array(
|
||||||
'values' => $values,
|
'values' => $values,
|
||||||
'errors' => $errors,
|
'errors' => $errors,
|
||||||
'projects' => $this->project->filterListByAccess($this->project->getList(), $user['id']),
|
'projects' => $this->projectPermission->filterProjects($this->project->getList(), $user['id']),
|
||||||
'user' => $user,
|
'user' => $user,
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
@ -412,6 +435,7 @@ class User extends Base
|
||||||
'errors' => array('login' => t('Google authentication failed')),
|
'errors' => array('login' => t('Google authentication failed')),
|
||||||
'values' => array(),
|
'values' => array(),
|
||||||
'no_layout' => true,
|
'no_layout' => true,
|
||||||
|
'redirect_query' => '',
|
||||||
'title' => t('Login')
|
'title' => t('Login')
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
@ -473,6 +497,7 @@ class User extends Base
|
||||||
'errors' => array('login' => t('GitHub authentication failed')),
|
'errors' => array('login' => t('GitHub authentication failed')),
|
||||||
'values' => array(),
|
'values' => array(),
|
||||||
'no_layout' => true,
|
'no_layout' => true,
|
||||||
|
'redirect_query' => '',
|
||||||
'title' => t('Login')
|
'title' => t('Login')
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
65
sources/app/Controller/Webhook.php
Normal file
65
sources/app/Controller/Webhook.php
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Controller;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Webhook controller
|
||||||
|
*
|
||||||
|
* @package controller
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
class Webhook extends Base
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Webhook to create a task
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
public function task()
|
||||||
|
{
|
||||||
|
if ($this->config->get('webhook_token') !== $this->request->getStringParam('token')) {
|
||||||
|
$this->response->text('Not Authorized', 401);
|
||||||
|
}
|
||||||
|
|
||||||
|
$defaultProject = $this->project->getFirst();
|
||||||
|
|
||||||
|
$values = array(
|
||||||
|
'title' => $this->request->getStringParam('title'),
|
||||||
|
'description' => $this->request->getStringParam('description'),
|
||||||
|
'color_id' => $this->request->getStringParam('color_id'),
|
||||||
|
'project_id' => $this->request->getIntegerParam('project_id', $defaultProject['id']),
|
||||||
|
'owner_id' => $this->request->getIntegerParam('owner_id'),
|
||||||
|
'column_id' => $this->request->getIntegerParam('column_id'),
|
||||||
|
'category_id' => $this->request->getIntegerParam('category_id'),
|
||||||
|
);
|
||||||
|
|
||||||
|
list($valid,) = $this->taskValidator->validateCreation($values);
|
||||||
|
|
||||||
|
if ($valid && $this->task->create($values)) {
|
||||||
|
$this->response->text('OK');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->response->text('FAILED');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle Github webhooks
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
public function github()
|
||||||
|
{
|
||||||
|
if ($this->config->get('webhook_token') !== $this->request->getStringParam('token')) {
|
||||||
|
$this->response->text('Not Authorized', 401);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->githubWebhook->setProjectId($this->request->getIntegerParam('project_id'));
|
||||||
|
|
||||||
|
$result = $this->githubWebhook->parsePayload(
|
||||||
|
$this->request->getHeader('X-Github-Event'),
|
||||||
|
$this->request->getBody()
|
||||||
|
);
|
||||||
|
|
||||||
|
echo $result ? 'PARSED' : 'IGNORED';
|
||||||
|
}
|
||||||
|
}
|
|
@ -69,11 +69,14 @@ class Event
|
||||||
{
|
{
|
||||||
if (! $this->isEventTriggered($eventName)) {
|
if (! $this->isEventTriggered($eventName)) {
|
||||||
|
|
||||||
$this->lastEvent = $eventName;
|
|
||||||
$this->events[] = $eventName;
|
$this->events[] = $eventName;
|
||||||
|
|
||||||
if (isset($this->listeners[$eventName])) {
|
if (isset($this->listeners[$eventName])) {
|
||||||
|
|
||||||
foreach ($this->listeners[$eventName] as $listener) {
|
foreach ($this->listeners[$eventName] as $listener) {
|
||||||
|
|
||||||
|
$this->lastEvent = $eventName;
|
||||||
|
|
||||||
if ($listener->execute($data)) {
|
if ($listener->execute($data)) {
|
||||||
$this->lastListener = get_class($listener);
|
$this->lastListener = get_class($listener);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,8 @@ namespace Core;
|
||||||
* @package core
|
* @package core
|
||||||
* @author Frederic Guillot
|
* @author Frederic Guillot
|
||||||
*/
|
*/
|
||||||
interface Listener {
|
interface Listener
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* Execute the listener
|
* Execute the listener
|
||||||
*
|
*
|
||||||
|
|
|
@ -50,31 +50,20 @@ class Request
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get form values or unserialized json request
|
* Get form values and check for CSRF token
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getValues()
|
public function getValues()
|
||||||
{
|
{
|
||||||
if (! empty($_POST)) {
|
if (! empty($_POST) && Security::validateCSRFFormToken($_POST)) {
|
||||||
|
|
||||||
if (Security::validateCSRFFormToken($_POST)) {
|
|
||||||
return $_POST;
|
return $_POST;
|
||||||
}
|
}
|
||||||
|
|
||||||
return array();
|
return array();
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = json_decode($this->getBody(), true);
|
|
||||||
|
|
||||||
if ($result) {
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the raw body of the HTTP request
|
* Get the raw body of the HTTP request
|
||||||
*
|
*
|
||||||
|
@ -136,4 +125,73 @@ class Request
|
||||||
$name = 'HTTP_'.str_replace('-', '_', strtoupper($name));
|
$name = 'HTTP_'.str_replace('-', '_', strtoupper($name));
|
||||||
return isset($_SERVER[$name]) ? $_SERVER[$name] : '';
|
return isset($_SERVER[$name]) ? $_SERVER[$name] : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns current request's query string, useful for redirecting
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getQueryString()
|
||||||
|
{
|
||||||
|
return isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the user agent
|
||||||
|
*
|
||||||
|
* @static
|
||||||
|
* @access public
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function getUserAgent()
|
||||||
|
{
|
||||||
|
return empty($_SERVER['HTTP_USER_AGENT']) ? t('Unknown') : $_SERVER['HTTP_USER_AGENT'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the real IP address of the user
|
||||||
|
*
|
||||||
|
* @static
|
||||||
|
* @access public
|
||||||
|
* @param bool $only_public Return only public IP address
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function getIpAddress($only_public = false)
|
||||||
|
{
|
||||||
|
$keys = array(
|
||||||
|
'HTTP_CLIENT_IP',
|
||||||
|
'HTTP_X_FORWARDED_FOR',
|
||||||
|
'HTTP_X_FORWARDED',
|
||||||
|
'HTTP_X_CLUSTER_CLIENT_IP',
|
||||||
|
'HTTP_FORWARDED_FOR',
|
||||||
|
'HTTP_FORWARDED',
|
||||||
|
'REMOTE_ADDR'
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($keys as $key) {
|
||||||
|
|
||||||
|
if (isset($_SERVER[$key])) {
|
||||||
|
|
||||||
|
foreach (explode(',', $_SERVER[$key]) as $ip_address) {
|
||||||
|
|
||||||
|
$ip_address = trim($ip_address);
|
||||||
|
|
||||||
|
if ($only_public) {
|
||||||
|
|
||||||
|
// Return only public IP address
|
||||||
|
if (filter_var($ip_address, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false) {
|
||||||
|
return $ip_address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
return $ip_address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return t('Unknown');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,18 @@ class Session
|
||||||
*/
|
*/
|
||||||
const SESSION_LIFETIME = 0; // Until the browser is closed
|
const SESSION_LIFETIME = 0; // Until the browser is closed
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the session is open
|
||||||
|
*
|
||||||
|
* @static
|
||||||
|
* @access public
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public static function isOpen()
|
||||||
|
{
|
||||||
|
return session_id() !== '';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open a session
|
* Open a session
|
||||||
*
|
*
|
||||||
|
@ -50,14 +62,14 @@ class Session
|
||||||
ini_set('session.hash_bits_per_character', 6);
|
ini_set('session.hash_bits_per_character', 6);
|
||||||
|
|
||||||
// If session was autostarted with session.auto_start = 1 in php.ini destroy it, otherwise we cannot login
|
// If session was autostarted with session.auto_start = 1 in php.ini destroy it, otherwise we cannot login
|
||||||
if (isset($_SESSION))
|
if (isset($_SESSION)) {
|
||||||
{
|
|
||||||
session_destroy();
|
session_destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom session name
|
// Custom session name
|
||||||
session_name('__S');
|
session_name('__S');
|
||||||
|
|
||||||
|
// Start the session
|
||||||
session_start();
|
session_start();
|
||||||
|
|
||||||
// Regenerate the session id to avoid session fixation issue
|
// Regenerate the session id to avoid session fixation issue
|
||||||
|
|
|
@ -17,7 +17,7 @@ class Template
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
const PATH = 'app/Templates/';
|
const PATH = 'app/Template/';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load a template
|
* Load a template
|
||||||
|
|
|
@ -11,14 +11,14 @@ namespace Core;
|
||||||
class Translator
|
class Translator
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Locales path
|
* Locale path
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
const PATH = 'app/Locales/';
|
const PATH = 'app/Locale/';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Locales
|
* Locale
|
||||||
*
|
*
|
||||||
* @static
|
* @static
|
||||||
* @access private
|
* @access private
|
||||||
|
|
79
sources/app/Event/Base.php
Normal file
79
sources/app/Event/Base.php
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Event;
|
||||||
|
|
||||||
|
use Core\Listener;
|
||||||
|
use Core\Registry;
|
||||||
|
use Core\Tool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base Listener
|
||||||
|
*
|
||||||
|
* @package event
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*
|
||||||
|
* @property \Model\Comment $comment
|
||||||
|
* @property \Model\Project $project
|
||||||
|
* @property \Model\ProjectActivity $projectActivity
|
||||||
|
* @property \Model\SubTask $subTask
|
||||||
|
* @property \Model\Task $task
|
||||||
|
* @property \Model\TaskFinder $taskFinder
|
||||||
|
*/
|
||||||
|
abstract class Base implements Listener
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Registry instance
|
||||||
|
*
|
||||||
|
* @access protected
|
||||||
|
* @var \Core\Registry
|
||||||
|
*/
|
||||||
|
protected $registry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param \Core\Registry $registry Regsitry instance
|
||||||
|
*/
|
||||||
|
public function __construct(Registry $registry)
|
||||||
|
{
|
||||||
|
$this->registry = $registry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return class information
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
return get_called_class();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load automatically models
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param string $name Model name
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function __get($name)
|
||||||
|
{
|
||||||
|
return Tool::loadModel($this->registry, $name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get event namespace
|
||||||
|
*
|
||||||
|
* Event = task.close | Namespace = task
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getEventNamespace()
|
||||||
|
{
|
||||||
|
$event_name = $this->registry->event->getLastTriggeredEvent();
|
||||||
|
return substr($event_name, 0, strpos($event_name, '.'));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,87 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Event;
|
|
||||||
|
|
||||||
use Core\Listener;
|
|
||||||
use Model\Notification;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base notification listener
|
|
||||||
*
|
|
||||||
* @package event
|
|
||||||
* @author Frederic Guillot
|
|
||||||
*/
|
|
||||||
abstract class BaseNotificationListener implements Listener
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Notification model
|
|
||||||
*
|
|
||||||
* @accesss protected
|
|
||||||
* @var Model\Notification
|
|
||||||
*/
|
|
||||||
protected $notification;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Template name
|
|
||||||
*
|
|
||||||
* @accesss private
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $template = '';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch data for the mail template
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param array $data Event data
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
abstract public function getTemplateData(array $data);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param \Model\Notification $notification Notification model instance
|
|
||||||
* @param string $template Template name
|
|
||||||
*/
|
|
||||||
public function __construct(Notification $notification, $template)
|
|
||||||
{
|
|
||||||
$this->template = $template;
|
|
||||||
$this->notification = $notification;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return class information
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function __toString()
|
|
||||||
{
|
|
||||||
return get_called_class();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the action
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param array $data Event data dictionary
|
|
||||||
* @return bool True if the action was executed or false when not executed
|
|
||||||
*/
|
|
||||||
public function execute(array $data)
|
|
||||||
{
|
|
||||||
$values = $this->getTemplateData($data);
|
|
||||||
|
|
||||||
// Get the list of users to be notified
|
|
||||||
$users = $this->notification->getUsersList($values['task']['project_id']);
|
|
||||||
|
|
||||||
// Send notifications
|
|
||||||
if ($users) {
|
|
||||||
$this->notification->sendEmails($this->template, $users, $values);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,73 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Event;
|
|
||||||
|
|
||||||
use Core\Listener;
|
|
||||||
use Model\CommentHistory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Comment history listener
|
|
||||||
*
|
|
||||||
* @package event
|
|
||||||
* @author Frederic Guillot
|
|
||||||
*/
|
|
||||||
class CommentHistoryListener implements Listener
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Comment History model
|
|
||||||
*
|
|
||||||
* @accesss private
|
|
||||||
* @var \Model\CommentHistory
|
|
||||||
*/
|
|
||||||
private $model;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param \Model\CommentHistory $model Comment History model instance
|
|
||||||
*/
|
|
||||||
public function __construct(CommentHistory $model)
|
|
||||||
{
|
|
||||||
$this->model = $model;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return class information
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function __toString()
|
|
||||||
{
|
|
||||||
return get_called_class();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the action
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param array $data Event data dictionary
|
|
||||||
* @return bool True if the action was executed or false when not executed
|
|
||||||
*/
|
|
||||||
public function execute(array $data)
|
|
||||||
{
|
|
||||||
$creator_id = $this->model->acl->getUserId();
|
|
||||||
|
|
||||||
if ($creator_id && isset($data['task_id']) && isset($data['id'])) {
|
|
||||||
|
|
||||||
$task = $this->model->task->getById($data['task_id']);
|
|
||||||
|
|
||||||
$this->model->create(
|
|
||||||
$task['project_id'],
|
|
||||||
$data['task_id'],
|
|
||||||
$data['id'],
|
|
||||||
$creator_id,
|
|
||||||
$this->model->event->getLastTriggeredEvent(),
|
|
||||||
$data['comment']
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Event;
|
|
||||||
|
|
||||||
use Event\BaseNotificationListener;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Comment notification listener
|
|
||||||
*
|
|
||||||
* @package event
|
|
||||||
* @author Frederic Guillot
|
|
||||||
*/
|
|
||||||
class CommentNotificationListener extends BaseNotificationListener
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Fetch data for the mail template
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param array $data Event data
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getTemplateData(array $data)
|
|
||||||
{
|
|
||||||
$values = array();
|
|
||||||
$values['comment'] = $this->notification->comment->getById($data['id']);
|
|
||||||
$values['task'] = $this->notification->task->getById($values['comment']['task_id'], true);
|
|
||||||
|
|
||||||
return $values;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Event;
|
|
||||||
|
|
||||||
use Event\BaseNotificationListener;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* File notification listener
|
|
||||||
*
|
|
||||||
* @package event
|
|
||||||
* @author Frederic Guillot
|
|
||||||
*/
|
|
||||||
class FileNotificationListener extends BaseNotificationListener
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Fetch data for the mail template
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param array $data Event data
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getTemplateData(array $data)
|
|
||||||
{
|
|
||||||
$values = array();
|
|
||||||
$values['file'] = $data;
|
|
||||||
$values['task'] = $this->notification->task->getById($data['task_id'], true);
|
|
||||||
|
|
||||||
return $values;
|
|
||||||
}
|
|
||||||
}
|
|
83
sources/app/Event/NotificationListener.php
Normal file
83
sources/app/Event/NotificationListener.php
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notification listener
|
||||||
|
*
|
||||||
|
* @package event
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
class NotificationListener extends Base
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Template name
|
||||||
|
*
|
||||||
|
* @accesss private
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $template = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set template name
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param string $template Template name
|
||||||
|
*/
|
||||||
|
public function setTemplate($template)
|
||||||
|
{
|
||||||
|
$this->template = $template;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the action
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $data Event data dictionary
|
||||||
|
* @return bool True if the action was executed or false when not executed
|
||||||
|
*/
|
||||||
|
public function execute(array $data)
|
||||||
|
{
|
||||||
|
$values = $this->getTemplateData($data);
|
||||||
|
$users = $this->notification->getUsersList($values['task']['project_id']);
|
||||||
|
|
||||||
|
if ($users) {
|
||||||
|
$this->notification->sendEmails($this->template, $users, $values);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch data for the mail template
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $data Event data
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getTemplateData(array $data)
|
||||||
|
{
|
||||||
|
$values = array();
|
||||||
|
|
||||||
|
switch ($this->getEventNamespace()) {
|
||||||
|
case 'task':
|
||||||
|
$values['task'] = $this->taskFinder->getDetails($data['task_id']);
|
||||||
|
break;
|
||||||
|
case 'subtask':
|
||||||
|
$values['subtask'] = $this->subtask->getById($data['id'], true);
|
||||||
|
$values['task'] = $this->taskFinder->getDetails($data['task_id']);
|
||||||
|
break;
|
||||||
|
case 'file':
|
||||||
|
$values['file'] = $data;
|
||||||
|
$values['task'] = $this->taskFinder->getDetails($data['task_id']);
|
||||||
|
break;
|
||||||
|
case 'comment':
|
||||||
|
$values['comment'] = $this->comment->getById($data['id']);
|
||||||
|
$values['task'] = $this->taskFinder->getDetails($values['comment']['task_id']);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $values;
|
||||||
|
}
|
||||||
|
}
|
61
sources/app/Event/ProjectActivityListener.php
Normal file
61
sources/app/Event/ProjectActivityListener.php
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Project activity listener
|
||||||
|
*
|
||||||
|
* @package event
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
class ProjectActivityListener extends Base
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Execute the action
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $data Event data dictionary
|
||||||
|
* @return bool True if the action was executed or false when not executed
|
||||||
|
*/
|
||||||
|
public function execute(array $data)
|
||||||
|
{
|
||||||
|
if (isset($data['task_id'])) {
|
||||||
|
|
||||||
|
$values = $this->getValues($data);
|
||||||
|
|
||||||
|
return $this->projectActivity->createEvent(
|
||||||
|
$values['task']['project_id'],
|
||||||
|
$values['task']['id'],
|
||||||
|
$this->acl->getUserId(),
|
||||||
|
$this->registry->event->getLastTriggeredEvent(),
|
||||||
|
$values
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get event activity data
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @param array $data Event data dictionary
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function getValues(array $data)
|
||||||
|
{
|
||||||
|
$values = array();
|
||||||
|
$values['task'] = $this->taskFinder->getDetails($data['task_id']);
|
||||||
|
|
||||||
|
switch ($this->getEventNamespace()) {
|
||||||
|
case 'subtask':
|
||||||
|
$values['subtask'] = $this->subTask->getById($data['id'], true);
|
||||||
|
break;
|
||||||
|
case 'comment':
|
||||||
|
$values['comment'] = $this->comment->getById($data['id']);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $values;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,63 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Event;
|
|
||||||
|
|
||||||
use Core\Listener;
|
|
||||||
use Model\Project;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Project modification date listener
|
|
||||||
*
|
|
||||||
* Update the last modified field for a project
|
|
||||||
*
|
|
||||||
* @package event
|
|
||||||
* @author Frederic Guillot
|
|
||||||
*/
|
|
||||||
class ProjectModificationDate implements Listener
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Project model
|
|
||||||
*
|
|
||||||
* @accesss private
|
|
||||||
* @var \Model\Project
|
|
||||||
*/
|
|
||||||
private $project;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param \Model\Project $project Project model instance
|
|
||||||
*/
|
|
||||||
public function __construct(Project $project)
|
|
||||||
{
|
|
||||||
$this->project = $project;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return class information
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function __toString()
|
|
||||||
{
|
|
||||||
return get_called_class();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the action
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param array $data Event data dictionary
|
|
||||||
* @return bool True if the action was executed or false when not executed
|
|
||||||
*/
|
|
||||||
public function execute(array $data)
|
|
||||||
{
|
|
||||||
if (isset($data['project_id'])) {
|
|
||||||
return $this->project->updateModificationDate($data['project_id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
30
sources/app/Event/ProjectModificationDateListener.php
Normal file
30
sources/app/Event/ProjectModificationDateListener.php
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Project modification date listener
|
||||||
|
*
|
||||||
|
* Update the "last_modified" field for a project
|
||||||
|
*
|
||||||
|
* @package event
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
class ProjectModificationDateListener extends Base
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Execute the action
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $data Event data dictionary
|
||||||
|
* @return bool True if the action was executed or false when not executed
|
||||||
|
*/
|
||||||
|
public function execute(array $data)
|
||||||
|
{
|
||||||
|
if (isset($data['project_id'])) {
|
||||||
|
return $this->project->updateModificationDate($data['project_id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,30 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Event;
|
|
||||||
|
|
||||||
use Event\BaseNotificationListener;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SubTask notification listener
|
|
||||||
*
|
|
||||||
* @package event
|
|
||||||
* @author Frederic Guillot
|
|
||||||
*/
|
|
||||||
class SubTaskNotificationListener extends BaseNotificationListener
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Fetch data for the mail template
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param array $data Event data
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getTemplateData(array $data)
|
|
||||||
{
|
|
||||||
$values = array();
|
|
||||||
$values['subtask'] = $this->notification->subtask->getById($data['id'], true);
|
|
||||||
$values['task'] = $this->notification->task->getById($data['task_id'], true);
|
|
||||||
|
|
||||||
return $values;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,73 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Event;
|
|
||||||
|
|
||||||
use Core\Listener;
|
|
||||||
use Model\SubtaskHistory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Subtask history listener
|
|
||||||
*
|
|
||||||
* @package event
|
|
||||||
* @author Frederic Guillot
|
|
||||||
*/
|
|
||||||
class SubtaskHistoryListener implements Listener
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Comment History model
|
|
||||||
*
|
|
||||||
* @accesss private
|
|
||||||
* @var \Model\SubtaskHistory
|
|
||||||
*/
|
|
||||||
private $model;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param \Model\SubtaskHistory $model Subtask History model instance
|
|
||||||
*/
|
|
||||||
public function __construct(SubtaskHistory $model)
|
|
||||||
{
|
|
||||||
$this->model = $model;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return class information
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function __toString()
|
|
||||||
{
|
|
||||||
return get_called_class();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the action
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param array $data Event data dictionary
|
|
||||||
* @return bool True if the action was executed or false when not executed
|
|
||||||
*/
|
|
||||||
public function execute(array $data)
|
|
||||||
{
|
|
||||||
$creator_id = $this->model->acl->getUserId();
|
|
||||||
|
|
||||||
if ($creator_id && isset($data['task_id']) && isset($data['id'])) {
|
|
||||||
|
|
||||||
$task = $this->model->task->getById($data['task_id']);
|
|
||||||
|
|
||||||
$this->model->create(
|
|
||||||
$task['project_id'],
|
|
||||||
$data['task_id'],
|
|
||||||
$data['id'],
|
|
||||||
$creator_id,
|
|
||||||
$this->model->event->getLastTriggeredEvent(),
|
|
||||||
''
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Event;
|
|
||||||
|
|
||||||
use Core\Listener;
|
|
||||||
use Model\TaskHistory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Task history listener
|
|
||||||
*
|
|
||||||
* @package event
|
|
||||||
* @author Frederic Guillot
|
|
||||||
*/
|
|
||||||
class TaskHistoryListener implements Listener
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Task History model
|
|
||||||
*
|
|
||||||
* @accesss private
|
|
||||||
* @var \Model\TaskHistory
|
|
||||||
*/
|
|
||||||
private $model;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param \Model\TaskHistory $model Task History model instance
|
|
||||||
*/
|
|
||||||
public function __construct(TaskHistory $model)
|
|
||||||
{
|
|
||||||
$this->model = $model;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return class information
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function __toString()
|
|
||||||
{
|
|
||||||
return get_called_class();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the action
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param array $data Event data dictionary
|
|
||||||
* @return bool True if the action was executed or false when not executed
|
|
||||||
*/
|
|
||||||
public function execute(array $data)
|
|
||||||
{
|
|
||||||
$creator_id = $this->model->acl->getUserId();
|
|
||||||
|
|
||||||
if ($creator_id && isset($data['task_id']) && isset($data['project_id'])) {
|
|
||||||
$this->model->create($data['project_id'], $data['task_id'], $creator_id, $this->model->event->getLastTriggeredEvent());
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Event;
|
|
||||||
|
|
||||||
use Event\BaseNotificationListener;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Task notification listener
|
|
||||||
*
|
|
||||||
* @package event
|
|
||||||
* @author Frederic Guillot
|
|
||||||
*/
|
|
||||||
class TaskNotificationListener extends BaseNotificationListener
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Fetch data for the mail template
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param array $data Event data
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getTemplateData(array $data)
|
|
||||||
{
|
|
||||||
$values = array();
|
|
||||||
$values['task'] = $this->notification->task->getById($data['task_id'], true);
|
|
||||||
|
|
||||||
return $values;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,25 +2,14 @@
|
||||||
|
|
||||||
namespace Event;
|
namespace Event;
|
||||||
|
|
||||||
use Core\Listener;
|
|
||||||
use Model\Webhook;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Webhook task events
|
* Webhook task events
|
||||||
*
|
*
|
||||||
* @package event
|
* @package event
|
||||||
* @author Frederic Guillot
|
* @author Frederic Guillot
|
||||||
*/
|
*/
|
||||||
class WebhookListener implements Listener
|
class WebhookListener extends Base
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Webhook model
|
|
||||||
*
|
|
||||||
* @accesss private
|
|
||||||
* @var \Model\Webhook
|
|
||||||
*/
|
|
||||||
private $webhook;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Url to call
|
* Url to call
|
||||||
*
|
*
|
||||||
|
@ -30,27 +19,14 @@ class WebhookListener implements Listener
|
||||||
private $url = '';
|
private $url = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Set webhook url
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @param string $url URL to call
|
* @param string $url URL to call
|
||||||
* @param \Model\Webhook $webhook Webhook model instance
|
|
||||||
*/
|
*/
|
||||||
public function __construct($url, Webhook $webhook)
|
public function setUrl($url)
|
||||||
{
|
{
|
||||||
$this->url = $url;
|
$this->url = $url;
|
||||||
$this->webhook = $webhook;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return class information
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function __toString()
|
|
||||||
{
|
|
||||||
return get_called_class();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
561
sources/app/Locale/da_DK/translations.php
Normal file
561
sources/app/Locale/da_DK/translations.php
Normal file
|
@ -0,0 +1,561 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'None' => 'Ingen',
|
||||||
|
'edit' => 'rediger',
|
||||||
|
'Edit' => 'Rediger',
|
||||||
|
'remove' => 'fjern',
|
||||||
|
'Remove' => 'Fjern',
|
||||||
|
'Update' => 'Opdater',
|
||||||
|
'Yes' => 'Ja',
|
||||||
|
'No' => 'Nej',
|
||||||
|
'cancel' => 'annuller',
|
||||||
|
'or' => 'eller',
|
||||||
|
'Yellow' => 'Gul',
|
||||||
|
'Blue' => 'Blå',
|
||||||
|
'Green' => 'Grøn',
|
||||||
|
'Purple' => 'Lilla',
|
||||||
|
'Red' => 'Rød',
|
||||||
|
'Orange' => 'Orange',
|
||||||
|
'Grey' => 'Grå',
|
||||||
|
'Save' => 'Gem',
|
||||||
|
'Login' => 'Login',
|
||||||
|
'Official website:' => 'Officielt website:',
|
||||||
|
'Unassigned' => 'Ingen ansvarlig',
|
||||||
|
'View this task' => 'Se denne opgave',
|
||||||
|
'Remove user' => 'Fjern bruger',
|
||||||
|
'Do you really want to remove this user: "%s"?' => 'Ønsker du virkelig at fjerne denne bruger: "%s"?',
|
||||||
|
'New user' => 'Ny bruger',
|
||||||
|
'All users' => 'Alle brugere',
|
||||||
|
'Username' => 'Brugernavn',
|
||||||
|
'Password' => 'Password',
|
||||||
|
'Default project' => 'Standard projekt',
|
||||||
|
'Administrator' => 'Administrator',
|
||||||
|
'Sign in' => 'Log ind',
|
||||||
|
'Users' => 'Brugere',
|
||||||
|
'No user' => 'Ingen bruger',
|
||||||
|
'Forbidden' => 'Forbudt',
|
||||||
|
'Access Forbidden' => 'Adgang nægtet',
|
||||||
|
'Only administrators can access to this page.' => 'Kun administratorer har adgang til denne side.',
|
||||||
|
'Edit user' => 'Rediger bruger',
|
||||||
|
'Logout' => 'Log ud',
|
||||||
|
'Bad username or password' => 'Forkert brugernavn eller adgangskode',
|
||||||
|
'users' => 'Brugere',
|
||||||
|
'projects' => 'Projekter',
|
||||||
|
'Edit project' => 'Rediger projekt',
|
||||||
|
'Name' => 'Navn',
|
||||||
|
'Activated' => 'Aktiveret',
|
||||||
|
'Projects' => 'Projekter',
|
||||||
|
'No project' => 'Intet projekt',
|
||||||
|
'Project' => 'Projekt',
|
||||||
|
'Status' => 'Status',
|
||||||
|
'Tasks' => 'Opgave',
|
||||||
|
'Board' => 'Board',
|
||||||
|
'Actions' => 'Handlinger',
|
||||||
|
'Inactive' => 'Inaktiv',
|
||||||
|
'Active' => 'Aktiv',
|
||||||
|
'Column %d' => 'Kolonne %d',
|
||||||
|
'Add this column' => 'Tilføj denne kolonne',
|
||||||
|
'%d tasks on the board' => '%d Opgaver på boardet',
|
||||||
|
'%d tasks in total' => '%d Opgaver i alt',
|
||||||
|
'Unable to update this board.' => 'Ikke muligt at opdatere dette board',
|
||||||
|
'Edit board' => 'Rediger board',
|
||||||
|
'Disable' => 'Deaktiver',
|
||||||
|
'Enable' => 'Aktiver',
|
||||||
|
'New project' => 'Nyt projekt',
|
||||||
|
'Do you really want to remove this project: "%s"?' => 'Vil du virkelig fjerne dette projekt: "%s"?',
|
||||||
|
'Remove project' => 'Fjern projekt',
|
||||||
|
'Boards' => 'Boards',
|
||||||
|
'Edit the board for "%s"' => 'Rediger boardet for "%s"',
|
||||||
|
'All projects' => 'Alle Projekter',
|
||||||
|
'Change columns' => 'Ændre kolonner',
|
||||||
|
'Add a new column' => 'Tilføj en ny kolonne',
|
||||||
|
'Title' => 'Titel',
|
||||||
|
'Add Column' => 'Tilføj kolonne',
|
||||||
|
'Project "%s"' => 'Projekt "%s"',
|
||||||
|
'Nobody assigned' => 'Ingen ansvarlig',
|
||||||
|
'Assigned to %s' => 'Ansvarlig: %s',
|
||||||
|
'Remove a column' => 'Fjern en kolonne',
|
||||||
|
'Remove a column from a board' => 'Fjern en kolonne fra et board',
|
||||||
|
'Unable to remove this column.' => 'Ikke muligt at fjerne denne kolonne',
|
||||||
|
'Do you really want to remove this column: "%s"?' => 'Vil du virkelig fjerne denne kolonne: "%s"?',
|
||||||
|
'This action will REMOVE ALL TASKS associated to this column!' => 'Denne handling vil SLETTE ALLE OPGAVER tilknyttet denne kolonne',
|
||||||
|
'Settings' => 'Indstillinger',
|
||||||
|
'Application settings' => 'Applikationsindstillinger',
|
||||||
|
'Language' => 'Sprog',
|
||||||
|
'Webhook token:' => 'Webhook token:',
|
||||||
|
'API token:' => 'API Token:',
|
||||||
|
'More information' => 'Mere Information',
|
||||||
|
'Database size:' => 'Databasestørrelse:',
|
||||||
|
'Download the database' => 'Download databasen',
|
||||||
|
'Optimize the database' => 'Optimer databasen',
|
||||||
|
'(VACUUM command)' => '(VACUUM kommando)',
|
||||||
|
'(Gzip compressed Sqlite file)' => '(Gzip-komprimeret Sqlite fil)',
|
||||||
|
'User settings' => 'Brugerindstillinger',
|
||||||
|
'My default project:' => 'Mit standard projekt:',
|
||||||
|
'Close a task' => 'Luk en opgave',
|
||||||
|
'Do you really want to close this task: "%s"?' => 'Vil du virkelig lukke denne opgave: "%s"?',
|
||||||
|
'Edit a task' => 'Rediger en opgave',
|
||||||
|
'Column' => 'Kolonne',
|
||||||
|
'Color' => 'Farve',
|
||||||
|
'Assignee' => 'Ansvarlig',
|
||||||
|
'Create another task' => 'Opret en anden opgave',
|
||||||
|
'New task' => 'Ny opgave',
|
||||||
|
'Open a task' => 'Åben en opgave',
|
||||||
|
'Do you really want to open this task: "%s"?' => 'Vil du virkelig åbne denne opgave: "%s"?',
|
||||||
|
'Back to the board' => 'Tilbage til boardet',
|
||||||
|
'Created on %B %e, %Y at %k:%M %p' => 'Oprettet %d.%m.%Y - %H:%M',
|
||||||
|
'There is nobody assigned' => 'Der er ingen tilføjet',
|
||||||
|
'Column on the board:' => 'Kolonne:',
|
||||||
|
'Status is open' => 'Status er åbnet',
|
||||||
|
'Status is closed' => 'Status er lukket',
|
||||||
|
'Close this task' => 'Luk denne opgave',
|
||||||
|
'Open this task' => 'Åben denne opgave',
|
||||||
|
'There is no description.' => 'Der er ingen beskrivning.',
|
||||||
|
'Add a new task' => 'Tilføj en ny opgave',
|
||||||
|
'The username is required' => 'Brugernavn er krævet',
|
||||||
|
'The maximum length is %d characters' => 'Den maksimale længde er %d karakterer',
|
||||||
|
'The minimum length is %d characters' => 'Den minimale længde er %d karakterer',
|
||||||
|
'The password is required' => 'Adgangskode er krævet',
|
||||||
|
'This value must be an integer' => 'Denne værdig skal være et tal',
|
||||||
|
'The username must be unique' => 'Brugernavn skal være unikt',
|
||||||
|
'The username must be alphanumeric' => 'Brugernavnet skal være alfanumerisk',
|
||||||
|
'The user id is required' => 'Bruger id er krævet',
|
||||||
|
'Passwords don\'t match' => 'Adgangskoderne stemmer ikke overens',
|
||||||
|
'The confirmation is required' => 'Verifikation er nødvendigt',
|
||||||
|
'The column is required' => 'Kolonnen er krævet',
|
||||||
|
'The project is required' => 'Projektet er krævet',
|
||||||
|
'The color is required' => 'Farven er krævet',
|
||||||
|
'The id is required' => 'Id\'et er krævet',
|
||||||
|
'The project id is required' => 'Projektets id er krævet',
|
||||||
|
'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',
|
||||||
|
'The language is required' => 'Sproget 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.',
|
||||||
|
'Your project have been created successfully.' => 'Dit projekt er oprettet.',
|
||||||
|
'Unable to create your project.' => 'Projektet kunne ikke oprettes',
|
||||||
|
'Project updated successfully.' => 'Projektet er opdateret.',
|
||||||
|
'Unable to update this project.' => 'Projektet kunne ikke opdateres.',
|
||||||
|
'Unable to remove this project.' => 'Projektet kunne ikke slettes.',
|
||||||
|
'Project removed successfully.' => 'Projektet er slettet.',
|
||||||
|
'Project activated successfully.' => 'Projektet er aktiveret.',
|
||||||
|
'Unable to activate this project.' => 'Projektet kunne ikke aktiveres.',
|
||||||
|
'Project disabled successfully.' => 'Projektet er deaktiveret.',
|
||||||
|
'Unable to disable this project.' => 'Projektet kunne ikke deaktiveres.',
|
||||||
|
'Unable to open this task.' => 'Opgaven kunne ikke ånnes.',
|
||||||
|
'Task opened successfully.' => 'Opgaven er åbnet.',
|
||||||
|
'Unable to close this task.' => 'Opgaven kunne ikke åbnes.',
|
||||||
|
'Task closed successfully.' => 'Opgaven er lukket.',
|
||||||
|
'Unable to update your task.' => 'Opgaven kunne ikke opdateres.',
|
||||||
|
'Task updated successfully.' => 'Opgaven er opdateret.',
|
||||||
|
'Unable to create your task.' => 'Opgave kunne ikke oprettes.',
|
||||||
|
'Task created successfully.' => 'Opgaven er oprettet.',
|
||||||
|
'User created successfully.' => 'Brugeren er oprettet.',
|
||||||
|
'Unable to create your user.' => 'Brugeren kunne ikke oprettes.',
|
||||||
|
'User updated successfully.' => 'Brugeren er opdateret',
|
||||||
|
'Unable to update your user.' => 'Din bruger kunne ikke opdateres.',
|
||||||
|
'User removed successfully.' => 'Brugeren er fjernet.',
|
||||||
|
'Unable to remove this user.' => 'Brugeren kunne ikke fjernes.',
|
||||||
|
'Board updated successfully.' => 'Boardet er opdateret.',
|
||||||
|
'Ready' => 'Klar',
|
||||||
|
'Backlog' => 'Backlog',
|
||||||
|
'Work in progress' => 'Igangværende',
|
||||||
|
'Done' => 'Færdig',
|
||||||
|
'Application version:' => 'Version:',
|
||||||
|
'Completed on %B %e, %Y at %k:%M %p' => 'Fuldført %d.%m.%Y - %H:%M',
|
||||||
|
'%B %e, %Y at %k:%M %p' => '%d.%m.%Y - %H:%M',
|
||||||
|
'Date created' => 'Dato for oprettelse',
|
||||||
|
'Date completed' => 'Dato for fuldført',
|
||||||
|
'Id' => 'ID',
|
||||||
|
'No task' => 'Ingen opgave',
|
||||||
|
'Completed tasks' => 'Fuldførte opgaver',
|
||||||
|
'List of projects' => 'Liste over projekter',
|
||||||
|
'Completed tasks for "%s"' => 'Fuldførte opgaver for "%s"',
|
||||||
|
'%d closed tasks' => '%d lukket opgavet',
|
||||||
|
'No task for this project' => 'Ingen opgaver i dette projekt',
|
||||||
|
'Public link' => 'Offentligt link',
|
||||||
|
'There is no column in your project!' => 'Der er ingen kolonner i dit projekt!',
|
||||||
|
'Change assignee' => 'Ændre ansvarlig',
|
||||||
|
'Change assignee for the task "%s"' => 'Ændre ansvarlig for opgaven: "%s"',
|
||||||
|
'Timezone' => 'Tidszone',
|
||||||
|
'Sorry, I didn\'t found this information in my database!' => 'Denne information kunne ikke findes i databasen!',
|
||||||
|
'Page not found' => 'Siden er ikke fundet',
|
||||||
|
'Complexity' => 'Kompleksitet',
|
||||||
|
'limit' => 'Begrænsning',
|
||||||
|
'Task limit' => 'Opgave begrænsning',
|
||||||
|
'This value must be greater than %d' => 'Denne værdi skal være større end %d',
|
||||||
|
'Edit project access list' => 'Rediger adgangstilladelser for projektet',
|
||||||
|
'Edit users access' => 'Rediger brugertilladelser',
|
||||||
|
'Allow this user' => 'Tillad denne bruger',
|
||||||
|
'Only those users have access to this project:' => 'Kunne disse brugere har adgang til dette projekt:',
|
||||||
|
'Don\'t forget that administrators have access to everything.' => 'Glem ikke at administratorer har adgang til alt.',
|
||||||
|
'revoke' => 'fjern',
|
||||||
|
'List of authorized users' => 'Liste over autoriserede brugere',
|
||||||
|
'User' => 'Bruger',
|
||||||
|
'Nobody have access to this project.' => 'Ingen har adgang til dette projekt.',
|
||||||
|
'You are not allowed to access to this project.' => 'Du har ikke tilladelse til at få adgang til dette projekt.',
|
||||||
|
'Comments' => 'Kommentarer',
|
||||||
|
'Post comment' => 'Skriv en kommentar',
|
||||||
|
'Write your text in Markdown' => 'Skriv din tekst i markdown',
|
||||||
|
'Leave a comment' => 'Efterlad en kommentar',
|
||||||
|
'Comment is required' => 'Kommentar er krævet',
|
||||||
|
'Leave a description' => 'Efterlad en beskrivelse...',
|
||||||
|
'Comment added successfully.' => 'Kommentaren er tilføjet.',
|
||||||
|
'Unable to create your comment.' => 'Din kommentar kunne ikke oprettes.',
|
||||||
|
'The description is required' => 'Beskrivelsen er krævet',
|
||||||
|
'Edit this task' => 'Rediger denne opgave',
|
||||||
|
'Due Date' => 'Forfaldsdato',
|
||||||
|
'Invalid date' => 'Ugyldig dato',
|
||||||
|
'Must be done before %B %e, %Y' => 'Skal være fuldført inden %d.%m.%Y',
|
||||||
|
'%B %e, %Y' => '%d.%m.%Y',
|
||||||
|
'Automatic actions' => 'Automatiske handlinger',
|
||||||
|
'Your automatic action have been created successfully.' => 'Din automatiske handling er oprettet.',
|
||||||
|
'Unable to create your automatic action.' => 'Din automatiske handling kunne ikke oprettes.',
|
||||||
|
'Remove an action' => 'Fjern an handling',
|
||||||
|
'Unable to remove this action.' => 'Handlingen kunne ikke fjernes.',
|
||||||
|
'Action removed successfully.' => 'Handlingen er fjernet.',
|
||||||
|
'Automatic actions for the project "%s"' => 'Automatiske handlinger for projektet "%s"',
|
||||||
|
'Defined actions' => 'Defineret handlinger',
|
||||||
|
'Add an action' => 'Tilføj en handling',
|
||||||
|
'Event name' => 'Begivenhed',
|
||||||
|
'Action name' => 'Handling',
|
||||||
|
'Action parameters' => 'Handlingsparametre',
|
||||||
|
'Action' => 'Handling',
|
||||||
|
'Event' => 'Begivenhed',
|
||||||
|
'When the selected event occurs execute the corresponding action.' => 'Når den valgte begivenhed opstår, udfør den tilsvarende handling.',
|
||||||
|
'Next step' => 'Næste',
|
||||||
|
'Define action parameters' => 'Definer Handlingsparametre',
|
||||||
|
'Save this action' => 'Gem denne handling',
|
||||||
|
'Do you really want to remove this action: "%s"?' => 'Vil du virkelig slette denne handling: "%s"?',
|
||||||
|
'Remove an automatic action' => 'Fjern en automatisk handling',
|
||||||
|
'Close the task' => 'Luk opgaven',
|
||||||
|
'Assign the task to a specific user' => 'Tildel opgaven til en bestem bruger',
|
||||||
|
'Assign the task to the person who does the action' => 'Tildel opgaven til den person, der udfører handlingen',
|
||||||
|
'Duplicate the task to another project' => 'Kopier opgaven til et andet projekt',
|
||||||
|
'Move a task to another column' => 'Flyt opgaven til en anden kolonne',
|
||||||
|
'Move a task to another position in the same column' => 'Flyt opgaven til en anden position, i den samme kolonne',
|
||||||
|
'Task modification' => 'Opgave forandring',
|
||||||
|
'Task creation' => 'Opgave oprettelse',
|
||||||
|
'Open a closed task' => 'Åbne en lukket opgave',
|
||||||
|
'Closing a task' => 'Lukke en opgave',
|
||||||
|
'Assign a color to a specific user' => 'Tildel en farve til en bestemt bruger',
|
||||||
|
'Column title' => 'Kolonne titel',
|
||||||
|
'Position' => 'Position',
|
||||||
|
'Move Up' => 'Ryk op',
|
||||||
|
'Move Down' => 'Ryk ned',
|
||||||
|
'Duplicate to another project' => 'Kopier til et andet projekt',
|
||||||
|
'Duplicate' => 'Kopier',
|
||||||
|
'link' => 'link',
|
||||||
|
'Update this comment' => 'Opdater denne kommentar',
|
||||||
|
'Comment updated successfully.' => 'Kommentar opdateret.',
|
||||||
|
'Unable to update your comment.' => 'Din kommentar kunne ikke opdateres.',
|
||||||
|
'Remove a comment' => 'Fjern en kommentar',
|
||||||
|
'Comment removed successfully.' => 'Kommentaren blev fjernet.',
|
||||||
|
'Unable to remove this comment.' => 'Kommentaren kunne ikke fjernes.',
|
||||||
|
'Do you really want to remove this comment?' => 'Vil du virkelig fjerne denne kommentar?',
|
||||||
|
'Only administrators or the creator of the comment can access to this page.' => 'Kun administratore eller brugeren, som har oprettet kommentaren har adgang til denne side.',
|
||||||
|
'Details' => 'Detaljer',
|
||||||
|
'Current password for the user "%s"' => 'Aktuelle adgangskode for brugeren "%s"',
|
||||||
|
'The current password is required' => 'Den aktuelle adgangskode er krævet',
|
||||||
|
'Wrong password' => 'Forkert adgangskode',
|
||||||
|
'Reset all tokens' => 'Nulstil alle tokens',
|
||||||
|
'All tokens have been regenerated.' => 'Alle tokens er blevet regenereret.',
|
||||||
|
'Unknown' => 'Ukendt',
|
||||||
|
'Last logins' => 'Sidste login',
|
||||||
|
'Login date' => 'Login dato',
|
||||||
|
'Authentication method' => 'Godkendelsesmetode',
|
||||||
|
'IP address' => 'IP Adresse',
|
||||||
|
'User agent' => 'User Agent',
|
||||||
|
'Persistent connections' => 'Vedvarende forbindelser',
|
||||||
|
'No session.' => 'Ingen session.',
|
||||||
|
'Expiration date' => 'Udløbsdato',
|
||||||
|
'Remember Me' => 'Husk mig',
|
||||||
|
'Creation date' => 'Oprettelsesdato',
|
||||||
|
'Filter by user' => 'Filtrer efter bruger',
|
||||||
|
'Filter by due date' => 'Filtrer efter forfaldsdato',
|
||||||
|
'Everybody' => 'Alle',
|
||||||
|
'Open' => 'Åben',
|
||||||
|
'Closed' => 'Lukket',
|
||||||
|
'Search' => 'Søg',
|
||||||
|
'Nothing found.' => 'Intet fundet.',
|
||||||
|
'Search in the project "%s"' => 'Søg i projektet "%s"',
|
||||||
|
'Due date' => 'Forfaldsdato',
|
||||||
|
'Others formats accepted: %s and %s' => 'Andre acceptable formater: %s und %s',
|
||||||
|
'Description' => 'Beskrivelse',
|
||||||
|
'%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.',
|
||||||
|
'Email' => 'E-Mail',
|
||||||
|
'Link my Google Account' => 'Forbind min Google-konto',
|
||||||
|
'Unlink my Google Account' => 'Fjern forbindelsen til min Google-konto',
|
||||||
|
'Login with my Google Account' => 'Login med min Google-konto',
|
||||||
|
'Project not found.' => 'Projekt ikke fundet.',
|
||||||
|
'Task #%d' => 'Opgave %d',
|
||||||
|
'Task removed successfully.' => 'Opgaven er fjernet.',
|
||||||
|
'Unable to remove this task.' => 'Opgaven kunne ikke fjernes.',
|
||||||
|
'Remove a task' => 'Fjern en opgave',
|
||||||
|
'Do you really want to remove this task: "%s"?' => 'Vil du virkelig fjerne denne opgave: "%s"?',
|
||||||
|
'Assign automatically a color based on a category' => 'Tildel automatisk en farve baseret for en kategori',
|
||||||
|
'Assign automatically a category based on a color' => 'Tildel automatisk en kategori baseret op en farve',
|
||||||
|
'Task creation or modification' => 'Opgave oprettelse eller forandring',
|
||||||
|
'Category' => 'Kategori',
|
||||||
|
'Category:' => 'Kategori:',
|
||||||
|
'Categories' => 'Kategorier',
|
||||||
|
'Category not found.' => 'Kategori ikke fundet.',
|
||||||
|
'Your category have been created successfully.' => 'Kategorien er oprettet.',
|
||||||
|
'Unable to create your category.' => 'Kategorien kunne ikke oprettes.',
|
||||||
|
'Your category have been updated successfully.' => 'Kategorien er opdateret.',
|
||||||
|
'Unable to update your category.' => 'Kategorien kunne ikke opdateres.',
|
||||||
|
'Remove a category' => 'Fjern en kategori',
|
||||||
|
'Category removed successfully.' => 'Kategorien er fjernet.',
|
||||||
|
'Unable to remove this category.' => 'Kategorien kunne ikke fjernes.',
|
||||||
|
'Category modification for the project "%s"' => 'Forandring af kategori for projektet "%s"',
|
||||||
|
'Category Name' => 'Kategorinavn',
|
||||||
|
'Categories for the project "%s"' => 'Kategorier i projektet "%s"',
|
||||||
|
'Add a new category' => 'Tilfæj en ny kategori',
|
||||||
|
'Do you really want to remove this category: "%s"?' => 'Vil du virkelig fjerne denne kategori: "%s"?',
|
||||||
|
'Filter by category' => 'Filter efter kategori',
|
||||||
|
'All categories' => 'Alle kategorier',
|
||||||
|
'No category' => 'Ingen kategori',
|
||||||
|
'The name is required' => 'Navnet er krævet',
|
||||||
|
'Remove a file' => 'Fjern en fil',
|
||||||
|
'Unable to remove this file.' => 'Filen kunne ikke fjernes.',
|
||||||
|
'File removed successfully.' => 'Filen er fjernet.',
|
||||||
|
'Attach a document' => 'Vedhæft et dokument',
|
||||||
|
'Do you really want to remove this file: "%s"?' => 'Vil du virkelig fjerne denne fil: "%s"?',
|
||||||
|
'open' => 'åben',
|
||||||
|
'Attachments' => 'Vedhæftninger',
|
||||||
|
'Edit the task' => 'Rediger opgaven',
|
||||||
|
'Edit the description' => 'Rediger beskrivelsen',
|
||||||
|
'Add a comment' => 'Tilføj en kommentar',
|
||||||
|
'Edit a comment' => 'Rediger en kommentar',
|
||||||
|
'Summary' => 'Resumé',
|
||||||
|
'Time tracking' => 'Tidsregistrering',
|
||||||
|
'Estimate:' => 'Estimering:',
|
||||||
|
'Spent:' => 'Brugt:',
|
||||||
|
'Do you really want to remove this sub-task?' => 'Vil du virkeligt fjerne denne under-opgave: "%s"?',
|
||||||
|
'Remaining:' => 'Tilbageværende:',
|
||||||
|
'hours' => 'timer',
|
||||||
|
'spent' => 'brugt',
|
||||||
|
'estimated' => 'estimeret',
|
||||||
|
'Sub-Tasks' => 'Under-opgave',
|
||||||
|
'Add a sub-task' => 'Tilføj en under-opgave',
|
||||||
|
'Original estimate' => 'Original estimering',
|
||||||
|
'Create another sub-task' => 'Tilføj endnu en under-opgave',
|
||||||
|
'Time spent' => 'Tidsforbrug',
|
||||||
|
'Edit a sub-task' => 'Rediger en under-opgave',
|
||||||
|
'Remove a sub-task' => 'Fjern en under-opgave',
|
||||||
|
'The time must be a numeric value' => 'Tiden skal være en nummerisk værdi',
|
||||||
|
'Todo' => 'Todo',
|
||||||
|
'In progress' => 'I gang',
|
||||||
|
'Sub-task removed successfully.' => 'Under-opgaven er fjernet.',
|
||||||
|
'Unable to remove this sub-task.' => 'Under-opgaven kunne ikke fjernes.',
|
||||||
|
'Sub-task updated successfully.' => 'Under-opgaven er opdateret.',
|
||||||
|
'Unable to update your sub-task.' => 'Under-opgaven kunne ikke opdateres.',
|
||||||
|
'Unable to create your sub-task.' => 'Under-opgaven kunne ikke oprettes.',
|
||||||
|
'Sub-task added successfully.' => 'Under-opgaven er tilføjet.',
|
||||||
|
'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',
|
||||||
|
'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',
|
||||||
|
'Tasks exportation for "%s"' => 'Opgave eksport for "%s"',
|
||||||
|
'Start Date' => 'Start-dato',
|
||||||
|
'End Date' => 'Slut-dato',
|
||||||
|
'Execute' => 'Udfør',
|
||||||
|
'Task Id' => 'Opgave ID',
|
||||||
|
'Creator' => 'Skaber',
|
||||||
|
'Modification date' => 'Ændringsdato',
|
||||||
|
'Completion date' => 'Afslutningsdato',
|
||||||
|
'Webhook URL for task creation' => 'Webhook URL for opgave oprettelse',
|
||||||
|
'Webhook URL for task modification' => 'Webhook URL opgave redigering',
|
||||||
|
'Clone' => 'Kopier',
|
||||||
|
'Clone Project' => 'Kopier projekt',
|
||||||
|
'Project cloned successfully.' => 'Projektet er kopieret.',
|
||||||
|
'Unable to clone this project.' => 'Projektet kunne ikke kopieres',
|
||||||
|
'Email notifications' => 'Email notifikationer',
|
||||||
|
'Enable email notifications' => 'Aktivér email notifikationer',
|
||||||
|
'Task position:' => 'Opgave position:',
|
||||||
|
'The task #%d have been opened.' => 'Opgaven #%d er blevet åbnet.',
|
||||||
|
'The task #%d have been closed.' => 'Opgaven #%d er blevet lukket.',
|
||||||
|
'Sub-task updated' => 'Under-opgave opdateret',
|
||||||
|
'Title:' => 'Titel:',
|
||||||
|
'Status:' => 'Status:',
|
||||||
|
'Assignee:' => 'Ansvarlig:',
|
||||||
|
'Time tracking:' => 'Tidsmåling:',
|
||||||
|
'New sub-task' => 'Ny under-opgave',
|
||||||
|
'New attachment added "%s"' => 'Ny vedhæftning tilføjet "%s"',
|
||||||
|
'Comment updated' => 'Kommentar opdateret',
|
||||||
|
'New comment posted by %s' => 'Ny kommentar af %s',
|
||||||
|
'List of due tasks for the project "%s"' => 'Udestående opgaver for projektet "%s"',
|
||||||
|
'[%s][New attachment] %s (#%d)' => '[%s][Ny vedhæftning] %s (#%d)',
|
||||||
|
'[%s][New comment] %s (#%d)' => '[%s][Ny kommentar] %s (#%d)',
|
||||||
|
'[%s][Comment updated] %s (#%d)' => '[%s][Kommentar opdateret] %s (#%d)',
|
||||||
|
'[%s][New subtask] %s (#%d)' => '[%s][Ny under-opgave] %s (#%d)',
|
||||||
|
'[%s][Subtask updated] %s (#%d)' => '[%s][Under-opgave opdateret] %s (#%d)',
|
||||||
|
'[%s][New task] %s (#%d)' => '[%s][Ny opgave] %s (#%d)',
|
||||||
|
'[%s][Task updated] %s (#%d)' => '[%s][Opgave opdateret] %s (#%d)',
|
||||||
|
'[%s][Task closed] %s (#%d)' => '[%s][Opgave lukket] %s (#%d)',
|
||||||
|
'[%s][Task opened] %s (#%d)' => '[%s][Opgave åbnet] %s (#%d)',
|
||||||
|
'[%s][Due tasks]' => 'Udestående opgaver',
|
||||||
|
'[Kanboard] Notification' => '[Kanboard] Notifikation',
|
||||||
|
'I want to receive notifications only for those projects:' => 'Jeg vil kun have notifikationer for disse projekter:',
|
||||||
|
'view the task on Kanboard' => 'se opgaven på Kanboard',
|
||||||
|
'Public access' => 'Offentlig adgang',
|
||||||
|
'Category management' => 'Kategorier',
|
||||||
|
'User management' => 'Brugerstyring',
|
||||||
|
'Active tasks' => 'Aktive opgaver',
|
||||||
|
'Disable public access' => 'Deaktiver offentlig adgang',
|
||||||
|
'Enable public access' => 'Aktivér offentlig adgang',
|
||||||
|
'Active projects' => 'Aktive Projekter',
|
||||||
|
'Inactive projects' => 'Inaktive projekter',
|
||||||
|
'Public access disabled' => 'Offentlig adgang deaktiveret',
|
||||||
|
'Do you really want to disable this project: "%s"?' => 'Vil du virkelig deaktivere dette projekt: "%s"?',
|
||||||
|
'Do you really want to duplicate this project: "%s"?' => 'Vil du virkelig kopiere dette projekt: "%s"?',
|
||||||
|
'Do you really want to enable this project: "%s"?' => 'Vil du virkelig aktiverer dette projekt: "%s"?',
|
||||||
|
'Project activation' => 'Projekt aktivering',
|
||||||
|
'Move the task to another project' => 'Flyt opgaven til et andet projekt',
|
||||||
|
'Move to another project' => 'Flyt til et andet projekt',
|
||||||
|
'Do you really want to duplicate this task?' => 'Vil du virkelig kopiere denne opgave?',
|
||||||
|
'Duplicate a task' => 'Kopier en opgave',
|
||||||
|
'External accounts' => 'Eksterne kontoer',
|
||||||
|
'Account type' => 'Kontotype',
|
||||||
|
'Local' => 'Lokal',
|
||||||
|
'Remote' => 'Remote',
|
||||||
|
'Enabled' => 'Aktiv',
|
||||||
|
'Disabled' => 'Deaktiveret',
|
||||||
|
'Google account linked' => 'Google-konto forbundet',
|
||||||
|
'Github account linked' => 'GitHub-konto forbundet',
|
||||||
|
'Username:' => 'Brugernavn',
|
||||||
|
'Name:' => 'Navn:',
|
||||||
|
'Email:' => 'Email:',
|
||||||
|
'Default project:' => 'Standard projekt:',
|
||||||
|
'Notifications:' => 'Notifikationer:',
|
||||||
|
'Notifications' => 'Notifikationer',
|
||||||
|
'Group:' => 'Gruppe:',
|
||||||
|
'Regular user' => 'Normal bruger',
|
||||||
|
'Account type:' => 'Konto type:',
|
||||||
|
'Edit profile' => 'Rediger profil',
|
||||||
|
'Change password' => 'Skift adgangskode',
|
||||||
|
'Password modification' => 'Adgangskode ændring',
|
||||||
|
'External authentications' => 'Ekstern autentificering',
|
||||||
|
'Google Account' => 'Google-konto',
|
||||||
|
'Github Account' => 'GitHub-konto',
|
||||||
|
'Never connected.' => 'Aldrig forbundet.',
|
||||||
|
'No account linked.' => 'Ingen kontoer forfundet.',
|
||||||
|
'Account linked.' => 'Konto forbundet.',
|
||||||
|
'No external authentication enabled.' => 'Ingen eksterne autentificering aktiveret.',
|
||||||
|
'Password modified successfully.' => 'Adgangskode ændret.',
|
||||||
|
'Unable to change the password.' => 'Adgangskoden kunne ikke ændres.',
|
||||||
|
'Change category for the task "%s"' => 'Skift kategori for opgaven "%s"',
|
||||||
|
'Change category' => 'Skift kategori',
|
||||||
|
'%s updated the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s opdatert opgaven <a href="?controller=task&action=show&task_id=%d">#%d</a>',
|
||||||
|
'%s open the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s åben opgaven <a href="?controller=task&action=show&task_id=%d">#%d</a>',
|
||||||
|
'%s moved the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to the position #%d in the column "%s"' => '%s flyt opgaven <a href="?controller=task&action=show&task_id=%d">#%d</a> til positionen #%d i kolonnen "%s"',
|
||||||
|
'%s moved the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to the column "%s"' => '%s flyttede opgaven <a href="?controller=task&action=show&task_id=%d">#%d</a> til kolonnen "%s"',
|
||||||
|
'%s created the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s oprettede opgaven <a href="?controller=task&action=show&task_id=%d">#%d</a>',
|
||||||
|
'%s closed the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '',
|
||||||
|
'%s created a subtask for the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s oprettede en under-opgave for opgaven <a href="?controller=task&action=show&task_id=%d">#%d</a>',
|
||||||
|
'%s updated a subtask for the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s opdaterede en under-opgave for opgaven <a href="?controller=task&action=show&task_id=%d">#%d</a>',
|
||||||
|
'Assigned to %s with an estimate of %s/%sh' => 'Tildelt til %s med en estimering på %s/%sh',
|
||||||
|
'Not assigned, estimate of %sh' => 'Ikke tildelt, estimeret til %sh',
|
||||||
|
'%s updated a comment on the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s opdateret en kommentar på opgaven <a href="?controller=task&action=show&task_id=%d">#%d</a>',
|
||||||
|
'%s commented the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s har kommenteret opgaven <a href="?controller=task&action=show&task_id=%d">#%d</a>',
|
||||||
|
'%s\'s activity' => '%s\'s aktvitet',
|
||||||
|
'No activity.' => 'Ingen aktivitet',
|
||||||
|
'RSS feed' => 'RSS feed',
|
||||||
|
'%s updated a comment on the task #%d' => '%s opdaterede en kommentar på opgaven #%d',
|
||||||
|
'%s commented on the task #%d' => '%s kommenteret op opgaven #%d',
|
||||||
|
'%s updated a subtask for the task #%d' => '%s opdaterede en under-opgave for opgaven #%d',
|
||||||
|
'%s created a subtask for the task #%d' => '%s oprettede en under-opgave for opgaven #%d',
|
||||||
|
'%s updated the task #%d' => '%s opdaterede opgaven #%d',
|
||||||
|
'%s created the task #%d' => '%s oprettede opgaven #%d',
|
||||||
|
'%s closed the task #%d' => '%s lukkede opgaven #%d',
|
||||||
|
'%s open the task #%d' => '%s åbnede opgaven #%d',
|
||||||
|
'%s moved the task #%d to the column "%s"' => '%s flyttede opgaven #%d til kolonnen "%s"',
|
||||||
|
'%s moved the task #%d to the position %d in the column "%s"' => '%s flyttede opgaven #%d til position %d i kolonnen "%s"',
|
||||||
|
'Activity' => 'Aktivitet',
|
||||||
|
'Default values are "%s"' => 'Standard værdier er "%s"',
|
||||||
|
'Default columns for new projects (Comma-separated)' => 'Standard kolonne for nye projekter (kommasepareret)',
|
||||||
|
'Task assignee change' => 'Opgaven ansvarlig ændring',
|
||||||
|
'%s change the assignee of the task #%d to %s' => '%s skrift ansvarlig for opgaven #%d til %s',
|
||||||
|
'%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to %s' => '%s skift ansvarlig for opgaven <a href="?controller=task&action=show&task_id=%d">#%d</a> til %s',
|
||||||
|
'[%s][Column Change] %s (#%d)' => '[%s][Kolonne Skift] %s (#%d)',
|
||||||
|
'[%s][Position Change] %s (#%d)' => '[%s][Position Skift] %s (#%d)',
|
||||||
|
'[%s][Assignee Change] %s (#%d)' => '[%s][Ansvarlig Skift] %s (#%d)',
|
||||||
|
'New password for the user "%s"' => 'Ny adgangskode for brugeren',
|
||||||
|
'Choose an event' => 'Vælg et event',
|
||||||
|
'Github commit received' => 'Github commit modtaget',
|
||||||
|
'Github issue opened' => 'Github problem åbet',
|
||||||
|
'Github issue closed' => 'Github problem lukket',
|
||||||
|
'Github issue reopened' => 'Github problem genåbnet',
|
||||||
|
'Github issue assignee change' => 'Github problem ansvarlig skift',
|
||||||
|
'Github issue label change' => 'Github problem label skift',
|
||||||
|
'Create a task from an external provider' => 'Opret en opgave fra en ekstern udbyder',
|
||||||
|
'Change the assignee based on an external username' => 'Skift den ansvarlige baseret på et eksternt brugernavn',
|
||||||
|
'Change the category based on an external label' => 'Skift kategorien baseret på en ekstern label',
|
||||||
|
'Reference' => 'Reference',
|
||||||
|
'Reference: %s' => 'Reference:',
|
||||||
|
'Label' => 'Label',
|
||||||
|
'Database' => 'Database',
|
||||||
|
'About' => 'Om',
|
||||||
|
'Database driver:' => 'Database driver:',
|
||||||
|
'Board settings' => 'Baord indstillinger',
|
||||||
|
'URL and token' => 'URL og token',
|
||||||
|
'Webhook settings' => 'Webhook indstillinger',
|
||||||
|
'URL for task creation:' => 'URL for opgave oprettelse:',
|
||||||
|
'Reset token' => 'Reset endpoint',
|
||||||
|
'API endpoint:' => 'API endpoint:',
|
||||||
|
'Refresh interval for private board' => 'Refresh interval for privat board',
|
||||||
|
'Refresh interval for public board' => 'Refresh interval for offentligt board',
|
||||||
|
'Task highlight period' => 'Opgave fremhævet periode',
|
||||||
|
'Period (in second) to consider a task was modified recently (0 to disable, 2 days by default)' => 'Periode for at antage en opgave er ændret fornylig (0 for at deaktivere, 2 dage som standard)',
|
||||||
|
'Frequency in second (60 seconds by default)' => 'Frekevens i sekunder (60 sekunder som standard)',
|
||||||
|
'Frequency in second (0 to disable this feature, 10 seconds by default)' => 'Frekvens i sekunder (0 for at deaktivere denne funktion, 10 sekunder som standard)',
|
||||||
|
'Application URL' => 'Applikation URL',
|
||||||
|
'Example: http://example.kanboard.net/ (used by email notifications)' => 'Eksempel: http://example.kanboard.net/ (bruges til email notifikationer)',
|
||||||
|
'Token regenerated.' => 'Token regenereret.',
|
||||||
|
'Date format' => 'Dato format',
|
||||||
|
'ISO format is always accepted, example: "%s" and "%s"' => 'ISO format er altid accepteret, eksempelvis: "%s" og "%s"',
|
||||||
|
'New private project' => 'Nyt privat projekt',
|
||||||
|
'This project is private' => 'Dette projekt er privat',
|
||||||
|
'Type here to create a new sub-task' => 'Skriv her for at tilføje en ny under-opgave',
|
||||||
|
'Add' => 'Tilføj',
|
||||||
|
'Estimated time: %s hours' => 'Estimeret tid: %s timer',
|
||||||
|
'Time spent: %s hours' => 'Tid brugt: %s timer',
|
||||||
|
'Started on %B %e, %Y' => 'Startet %d.%m.%Y ',
|
||||||
|
'Start date' => 'Start dato',
|
||||||
|
'Time estimated' => 'Tid estimeret',
|
||||||
|
'There is nothing assigned to you.' => 'Der er ingenting tildelt til dig.',
|
||||||
|
'My tasks' => 'Mine opgaver',
|
||||||
|
'Activity stream' => 'Aktivitets strøm',
|
||||||
|
'Dashboard' => 'Dashboard',
|
||||||
|
'Confirmation' => 'Bekræftelse',
|
||||||
|
// 'Allow everybody to access to this project' => '',
|
||||||
|
// 'Everybody have access to this project.' => '',
|
||||||
|
// 'Webhooks' => '',
|
||||||
|
// 'API' => '',
|
||||||
|
// 'Integration' => '',
|
||||||
|
// 'Github webhook' => '',
|
||||||
|
// 'Help on Github webhook' => '',
|
||||||
|
// 'Create a comment from an external provider' => '',
|
||||||
|
// 'Github issue comment created' => '',
|
||||||
|
);
|
|
@ -35,8 +35,8 @@ return array(
|
||||||
'Users' => 'Benutzer',
|
'Users' => 'Benutzer',
|
||||||
'No user' => 'Kein Benutzer',
|
'No user' => 'Kein Benutzer',
|
||||||
'Forbidden' => 'Verboten',
|
'Forbidden' => 'Verboten',
|
||||||
'Access Forbidden' => 'Zugang verboten',
|
'Access Forbidden' => 'Zugriff verboten',
|
||||||
'Only administrators can access to this page.' => 'Nur Administratoren haben Zugang zu dieser Seite.',
|
'Only administrators can access to this page.' => 'Nur Administratoren haben Zugriff zu dieser Seite.',
|
||||||
'Edit user' => 'Benutzer bearbeiten',
|
'Edit user' => 'Benutzer bearbeiten',
|
||||||
'Logout' => 'Abmelden',
|
'Logout' => 'Abmelden',
|
||||||
'Bad username or password' => 'Falscher Benutzername oder Passwort',
|
'Bad username or password' => 'Falscher Benutzername oder Passwort',
|
||||||
|
@ -83,7 +83,7 @@ return array(
|
||||||
'Settings' => 'Einstellungen',
|
'Settings' => 'Einstellungen',
|
||||||
'Application settings' => 'Anwendungskonfiguration',
|
'Application settings' => 'Anwendungskonfiguration',
|
||||||
'Language' => 'Sprache',
|
'Language' => 'Sprache',
|
||||||
'Webhooks token:' => 'Webhooks Token:',
|
'Webhook token:' => 'Webhook Token:',
|
||||||
'API token:' => 'API Token:',
|
'API token:' => 'API Token:',
|
||||||
'More information' => 'Mehr Informationen',
|
'More information' => 'Mehr Informationen',
|
||||||
'Database size:' => 'Datenbankgröße:',
|
'Database size:' => 'Datenbankgröße:',
|
||||||
|
@ -184,19 +184,19 @@ return array(
|
||||||
'Timezone' => 'Zeitzone',
|
'Timezone' => 'Zeitzone',
|
||||||
'Sorry, I didn\'t found this information in my database!' => 'Diese Information wurde in der Datenbank nicht gefunden!',
|
'Sorry, I didn\'t found this information in my database!' => 'Diese Information wurde in der Datenbank nicht gefunden!',
|
||||||
'Page not found' => 'Seite nicht gefunden',
|
'Page not found' => 'Seite nicht gefunden',
|
||||||
// 'Complexity' => '',
|
'Complexity' => 'Komplexität',
|
||||||
'limit' => 'Limit',
|
'limit' => 'Limit',
|
||||||
'Task limit' => 'Maximale Anzahl von Aufgaben',
|
'Task limit' => 'Maximale Anzahl von Aufgaben',
|
||||||
'This value must be greater than %d' => 'Dieser Wert muss größer sein als %d',
|
'This value must be greater than %d' => 'Dieser Wert muss größer sein als %d',
|
||||||
'Edit project access list' => 'Zugriffsberechtigungen des Projektes bearbeiten',
|
'Edit project access list' => 'Zugriffsberechtigungen des Projektes bearbeiten',
|
||||||
'Edit users access' => 'Benutzerzugriff ändern',
|
'Edit users access' => 'Benutzerzugriff ändern',
|
||||||
'Allow this user' => 'Diesen Benutzer autorisieren',
|
'Allow this user' => 'Diesen Benutzer autorisieren',
|
||||||
'Only those users have access to this project:' => 'Nur diese Benutzer haben Zugang zum Projekt:',
|
'Only those users have access to this project:' => 'Nur diese Benutzer haben Zugriff zum Projekt:',
|
||||||
'Don\'t forget that administrators have access to everything.' => 'Nicht vergessen: Administratoren haben überall Zugang.',
|
'Don\'t forget that administrators have access to everything.' => 'Nicht vergessen: Administratoren haben überall Zugriff.',
|
||||||
'revoke' => 'entfernen',
|
'revoke' => 'entfernen',
|
||||||
'List of authorized users' => 'Liste der autorisierten Benutzer',
|
'List of authorized users' => 'Liste der autorisierten Benutzer',
|
||||||
'User' => 'Benutzer',
|
'User' => 'Benutzer',
|
||||||
'Everybody have access to this project.' => 'Jeder hat Zugang zu diesem Projekt.',
|
'Nobody have access to this project.' => 'Niemand hat Zugriff auf dieses Projekt.',
|
||||||
'You are not allowed to access to this project.' => 'Unzureichende Zugriffsrechte zu diesem Projekt.',
|
'You are not allowed to access to this project.' => 'Unzureichende Zugriffsrechte zu diesem Projekt.',
|
||||||
'Comments' => 'Kommentare',
|
'Comments' => 'Kommentare',
|
||||||
'Post comment' => 'Kommentieren',
|
'Post comment' => 'Kommentieren',
|
||||||
|
@ -209,8 +209,6 @@ return array(
|
||||||
'The description is required' => 'Eine Beschreibung wird benötigt',
|
'The description is required' => 'Eine Beschreibung wird benötigt',
|
||||||
'Edit this task' => 'Aufgabe bearbeiten',
|
'Edit this task' => 'Aufgabe bearbeiten',
|
||||||
'Due Date' => 'Fällig am',
|
'Due Date' => 'Fällig am',
|
||||||
'm/d/Y' => 'd.m.Y',
|
|
||||||
'month/day/year' => 'TT.MM.JJJJ',
|
|
||||||
'Invalid date' => 'Ungültiges Datum',
|
'Invalid date' => 'Ungültiges Datum',
|
||||||
'Must be done before %B %e, %Y' => 'Muss vor dem %d.%m.%Y erledigt werden',
|
'Must be done before %B %e, %Y' => 'Muss vor dem %d.%m.%Y erledigt werden',
|
||||||
'%B %e, %Y' => '%d.%m.%Y',
|
'%B %e, %Y' => '%d.%m.%Y',
|
||||||
|
@ -261,7 +259,7 @@ return array(
|
||||||
'Do you really want to remove this comment?' => 'Soll dieser Kommentar wirklich gelöscht werden?',
|
'Do you really want to remove this comment?' => 'Soll dieser Kommentar wirklich gelöscht werden?',
|
||||||
'Only administrators or the creator of the comment can access to this page.' => 'Nur Administratoren und der Ersteller des Kommentars haben Zugriff auf diese Seite.',
|
'Only administrators or the creator of the comment can access to this page.' => 'Nur Administratoren und der Ersteller des Kommentars haben Zugriff auf diese Seite.',
|
||||||
'Details' => 'Details',
|
'Details' => 'Details',
|
||||||
'Current password for the user "%s"' => 'Aktuelles Passwort für den Benutzer "%s"',
|
'Current password for the user "%s"' => 'Aktuelles Passwort des Benutzers "%s"',
|
||||||
'The current password is required' => 'Das aktuelle Passwort wird benötigt',
|
'The current password is required' => 'Das aktuelle Passwort wird benötigt',
|
||||||
'Wrong password' => 'Falsches Passwort',
|
'Wrong password' => 'Falsches Passwort',
|
||||||
'Reset all tokens' => 'Alle Tokens zurücksetzen',
|
'Reset all tokens' => 'Alle Tokens zurücksetzen',
|
||||||
|
@ -293,7 +291,7 @@ return array(
|
||||||
'Email address invalid' => 'Ungültige E-Mail-Adresse',
|
'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.',
|
'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.',
|
'Unable to unlink your Google Account.' => 'Trennung der Verbindung zum Google Account nicht möglich.',
|
||||||
'Google authentication failed' => 'Zugang mit Google fehl geschlagen',
|
'Google authentication failed' => 'Zugriff mit Google fehlgeschlagen',
|
||||||
'Unable to link your Google Account.' => 'Verbindung mit diesem Google Account nicht möglich.',
|
'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 Google Account is linked to your profile successfully.' => 'Der Google Account wurde erfolgreich verbunden.',
|
||||||
'Email' => 'E-Mail',
|
'Email' => 'E-Mail',
|
||||||
|
@ -351,9 +349,9 @@ return array(
|
||||||
'estimated' => 'geschätzt',
|
'estimated' => 'geschätzt',
|
||||||
'Sub-Tasks' => 'Unteraufgaben',
|
'Sub-Tasks' => 'Unteraufgaben',
|
||||||
'Add a sub-task' => 'Unteraufgabe anlegen',
|
'Add a sub-task' => 'Unteraufgabe anlegen',
|
||||||
'Original Estimate' => 'Geschätzter Aufwand',
|
'Original estimate' => 'Geschätzter Aufwand',
|
||||||
'Create another sub-task' => 'Weitere Unteraufgabe anlegen',
|
'Create another sub-task' => 'Weitere Unteraufgabe anlegen',
|
||||||
'Time Spent' => 'Aufgewendete Zeit',
|
'Time spent' => 'Aufgewendete Zeit',
|
||||||
'Edit a sub-task' => 'Unteraufgabe bearbeiten',
|
'Edit a sub-task' => 'Unteraufgabe bearbeiten',
|
||||||
'Remove a sub-task' => 'Unteraufgabe löschen',
|
'Remove a sub-task' => 'Unteraufgabe löschen',
|
||||||
'The time must be a numeric value' => 'Zeit nur als nummerische Angabe',
|
'The time must be a numeric value' => 'Zeit nur als nummerische Angabe',
|
||||||
|
@ -370,7 +368,7 @@ return array(
|
||||||
'Display another project' => 'Zu Projekt wechseln...',
|
'Display another project' => 'Zu Projekt wechseln...',
|
||||||
'Your GitHub account was successfully linked to your profile.' => 'GitHub Account erfolgreich mit dem Profil verbunden.',
|
'Your GitHub account was successfully linked to your profile.' => 'GitHub Account erfolgreich mit dem Profil verbunden.',
|
||||||
'Unable to link your GitHub Account.' => 'Verbindung mit diesem GitHub Account nicht möglich.',
|
'Unable to link your GitHub Account.' => 'Verbindung mit diesem GitHub Account nicht möglich.',
|
||||||
'GitHub authentication failed' => 'Zugang mit GitHub fehl geschlagen',
|
'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.',
|
'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.',
|
'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',
|
'Login with my GitHub Account' => 'Anmelden mit meinem GitHub Account',
|
||||||
|
@ -388,119 +386,176 @@ return array(
|
||||||
'Modification date' => 'Änderungsdatum',
|
'Modification date' => 'Änderungsdatum',
|
||||||
'Completion date' => 'Abschlussdatum',
|
'Completion date' => 'Abschlussdatum',
|
||||||
'Webhook URL for task creation' => 'Webhook URL zur Aufgabenerstellung',
|
'Webhook URL for task creation' => 'Webhook URL zur Aufgabenerstellung',
|
||||||
'Webhook URL for task modification' => 'Webhook URL zur Aufgabenänderung',
|
'Webhook URL for task modification' => 'Webhook URL zur Aufgabenbearbeitung',
|
||||||
// 'Clone' => '',
|
'Clone' => 'duplizieren',
|
||||||
// 'Clone Project' => '',
|
'Clone Project' => 'Projekt duplizieren',
|
||||||
// 'Project cloned successfully.' => '',
|
'Project cloned successfully.' => 'Projekt wurde dupliziert.',
|
||||||
// 'Unable to clone this project.' => '',
|
'Unable to clone this project.' => 'Duplizieren dieses Projekts schlug fehl.',
|
||||||
// 'Email notifications' => '',
|
'Email notifications' => 'E-Mail Benachrichtigungen',
|
||||||
// 'Enable email notifications' => '',
|
'Enable email notifications' => 'E-Mail Benachrichtigungen einschalten',
|
||||||
// 'Task position:' => '',
|
'Task position:' => 'Position der Aufgabe',
|
||||||
// 'The task #%d have been opened.' => '',
|
'The task #%d have been opened.' => 'Die Aufgabe #%d wurde geöffnet.',
|
||||||
// 'The task #%d have been closed.' => '',
|
'The task #%d have been closed.' => 'Die Aufgabe #%d wurde geschlossen.',
|
||||||
// 'Sub-task updated' => '',
|
'Sub-task updated' => 'Unteraufgabe aktualisiert',
|
||||||
// 'Title:' => '',
|
'Title:' => 'Titel',
|
||||||
// 'Status:' => '',
|
'Status:' => 'Status',
|
||||||
// 'Assignee:' => '',
|
'Assignee:' => 'Zuständigkeit:',
|
||||||
// 'Time tracking:' => '',
|
'Time tracking:' => 'Zeittracking',
|
||||||
// 'New sub-task' => '',
|
'New sub-task' => 'Neue Unteraufgabe',
|
||||||
// 'New attachment added "%s"' => '',
|
'New attachment added "%s"' => 'Neuer Anhang "%s" wurde hinzugefügt.',
|
||||||
// 'Comment updated' => '',
|
'Comment updated' => 'Kommentar wurde aktualisiert',
|
||||||
// 'New comment posted by %s' => '',
|
'New comment posted by %s' => 'Neuer Kommentar verfasst durch %s',
|
||||||
// 'List of due tasks for the project "%s"' => '',
|
'List of due tasks for the project "%s"' => 'Liste der fälligen Aufgaben für das Projekt "%s"',
|
||||||
// '[%s][New attachment] %s (#%d)' => '',
|
'[%s][New attachment] %s (#%d)' => '[%s][Neuer Anhang] %s (#%d)',
|
||||||
// '[%s][New comment] %s (#%d)' => '',
|
'[%s][New comment] %s (#%d)' => '[%s][Neuer Kommentar] %s (#%d)',
|
||||||
// '[%s][Comment updated] %s (#%d)' => '',
|
'[%s][Comment updated] %s (#%d)' => '[%s][Kommentar aktualisisiert] %s (#%d)',
|
||||||
// '[%s][New subtask] %s (#%d)' => '',
|
'[%s][New subtask] %s (#%d)' => '[%s][Neue Unteraufgabe] %s (#%d)',
|
||||||
// '[%s][Subtask updated] %s (#%d)' => '',
|
'[%s][Subtask updated] %s (#%d)' => '[%s][Unteraufgabe aktualisisert] %s (#%d)',
|
||||||
// '[%s][New task] %s (#%d)' => '',
|
'[%s][New task] %s (#%d)' => '[%s][Neue Aufgabe] %s (#%d)',
|
||||||
// '[%s][Task updated] %s (#%d)' => '',
|
'[%s][Task updated] %s (#%d)' => '[%s][Aufgabe aktualisiert] %s (#%d)',
|
||||||
// '[%s][Task closed] %s (#%d)' => '',
|
'[%s][Task closed] %s (#%d)' => '[%s][Aufgabe geschlossen] %s (#%d)',
|
||||||
// '[%s][Task opened] %s (#%d)' => '',
|
'[%s][Task opened] %s (#%d)' => '[%s][Aufgabe geöffnet] %s (#%d)',
|
||||||
// '[%s][Due tasks]' => '',
|
'[%s][Due tasks]' => '[%s][Fällige Aufgaben]',
|
||||||
// '[Kanboard] Notification' => '',
|
'[Kanboard] Notification' => '[Kanboard] Benachrichtigung',
|
||||||
// 'I want to receive notifications only for those projects:' => '',
|
'I want to receive notifications only for those projects:' => 'Ich möchte nur für diese Projekte Benachrichtigungen erhalten:',
|
||||||
// 'view the task on Kanboard' => '',
|
'view the task on Kanboard' => 'diese Aufgabe auf dem Kanboard zeigen',
|
||||||
// 'Public access' => '',
|
'Public access' => 'Öffentlich',
|
||||||
// 'Categories management' => '',
|
'Category management' => 'Kategorien verwalten',
|
||||||
// 'Users management' => '',
|
'User management' => 'Benutzer verwalten',
|
||||||
// 'Active tasks' => '',
|
'Active tasks' => 'Aktive Aufgaben',
|
||||||
// 'Disable public access' => '',
|
'Disable public access' => 'Öffentlichen Zugriff deaktivieren',
|
||||||
// 'Enable public access' => '',
|
'Enable public access' => 'Öffentlichen Zugriff aktivieren',
|
||||||
// 'Active projects' => '',
|
'Active projects' => 'Aktive Projekte',
|
||||||
// 'Inactive projects' => '',
|
'Inactive projects' => 'Inaktive Projekte',
|
||||||
// 'Public access disabled' => '',
|
'Public access disabled' => 'Öffentlicher Zugriff deaktiviert',
|
||||||
// 'Do you really want to disable this project: "%s"?' => '',
|
'Do you really want to disable this project: "%s"?' => 'Möchten Sie dieses Projekt wirklich deaktivieren: "%s"',
|
||||||
// 'Do you really want to duplicate this project: "%s"?' => '',
|
'Do you really want to duplicate this project: "%s"?' => 'Möchten Sie dieses Projekt wirklich duplizieren: "%s"',
|
||||||
// 'Do you really want to enable this project: "%s"?' => '',
|
'Do you really want to enable this project: "%s"?' => 'Möchten Sie dieses Projekt wirklich aktivieren: "%s"',
|
||||||
// 'Project activation' => '',
|
'Project activation' => 'Projektaktivierung',
|
||||||
'Move the task to another project' => 'Aufgabe in ein anderes Projekt verschieben',
|
'Move the task to another project' => 'Aufgabe in ein anderes Projekt verschieben',
|
||||||
'Move to another project' => 'In anderes Projekt verschieben',
|
'Move to another project' => 'In anderes Projekt verschieben',
|
||||||
// 'Do you really want to duplicate this task?' => '',
|
'Do you really want to duplicate this task?' => 'Möchten Sie diese Aufgabe wirklich duplizieren?',
|
||||||
// 'Duplicate a task' => '',
|
'Duplicate a task' => 'Aufgabe duplizieren',
|
||||||
// 'External accounts' => '',
|
'External accounts' => 'Externe Accounts',
|
||||||
// 'Account type' => '',
|
'Account type' => 'Accounttyp',
|
||||||
// 'Local' => '',
|
'Local' => 'Lokal',
|
||||||
// 'Remote' => '',
|
'Remote' => 'Remote',
|
||||||
// 'Enabled' => '',
|
'Enabled' => 'angeschaltet',
|
||||||
// 'Disabled' => '',
|
'Disabled' => 'abgeschaltet',
|
||||||
// 'Google account linked' => '',
|
'Google account linked' => 'Mit Googleaccount verbunden',
|
||||||
// 'Github account linked' => '',
|
'Github account linked' => 'Mit Githubaccount verbunden',
|
||||||
// 'Username:' => '',
|
'Username:' => 'Benutzername',
|
||||||
// 'Name:' => '',
|
'Name:' => 'Name',
|
||||||
// 'Email:' => '',
|
'Email:' => 'E-Mail',
|
||||||
// 'Default project:' => '',
|
'Default project:' => 'Standardprojekt',
|
||||||
// 'Notifications:' => '',
|
'Notifications:' => 'Benachrichtigungen',
|
||||||
// 'Group:' => '',
|
'Notifications' => 'Benachrichtigungen',
|
||||||
// 'Regular user' => '',
|
'Group:' => 'Gruppe',
|
||||||
// 'Account type:' => '',
|
'Regular user' => 'Standardbenutzer',
|
||||||
// 'Edit profile' => '',
|
'Account type:' => 'Accounttyp',
|
||||||
// 'Change password' => '',
|
'Edit profile' => 'Profil bearbeiten',
|
||||||
// 'Password modification' => '',
|
'Change password' => 'Passwort ändern',
|
||||||
// 'External authentications' => '',
|
'Password modification' => 'Passwortänderung',
|
||||||
// 'Google Account' => '',
|
'External authentications' => 'Externe Authentisierungsmethoden',
|
||||||
// 'Github Account' => '',
|
'Google Account' => 'Googleaccount',
|
||||||
// 'Never connected.' => '',
|
'Github Account' => 'Githubaccount',
|
||||||
// 'No account linked.' => '',
|
'Never connected.' => 'Noch nie verbunden.',
|
||||||
// 'Account linked.' => '',
|
'No account linked.' => 'Kein Account verbunden.',
|
||||||
// 'No external authentication enabled.' => '',
|
'Account linked.' => 'Account verbunden',
|
||||||
// 'Password modified successfully.' => '',
|
'No external authentication enabled.' => 'Es sind keine externen Authentisierungsmethoden aktiv.',
|
||||||
// 'Unable to change the password.' => '',
|
'Password modified successfully.' => 'Passwort wurde erfolgreich geändert.',
|
||||||
// 'Change category for the task "%s"' => '',
|
'Unable to change the password.' => 'Passwort konnte nicht geändert werden.',
|
||||||
// 'Change category' => '',
|
'Change category for the task "%s"' => 'Kategorie der Aufgabe "%s" ändern',
|
||||||
// '%s updated the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '',
|
'Change category' => 'Kategorie ändern',
|
||||||
// '%s open the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '',
|
'%s updated the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s hat die Aufgabe <a href="?controller=task&action=show&task_id=%d">#%d</a> aktualisiert',
|
||||||
// '%s moved the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to the position #%d in the column "%s"' => '',
|
'%s open the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s hat die Aufgabe <a href="?controller=task&action=show&task_id=%d">#%d</a> geöffnet',
|
||||||
// '%s moved the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to the column "%s"' => '',
|
'%s moved the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to the position #%d in the column "%s"' => '%s hat die Aufgabe <a href="?controller=task&action=show&task_id=%d">#%d</a> auf die Position #%d in der Spalte "%s" verschoben',
|
||||||
// '%s created the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '',
|
'%s moved the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to the column "%s"' => '%s hat die Aufgabe <a href="?controller=task&action=show&task_id=%d">#%d</a> in die Spalte "%s" verschoben',
|
||||||
// '%s closed the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '',
|
'%s created the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s hat die Aufgabe <a href="?controller=task&action=show&task_id=%d">#%d</a> angelegt',
|
||||||
// '%s created a subtask for the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '',
|
'%s closed the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s hat die Aufgabe <a href="?controller=task&action=show&task_id=%d">#%d</a> geschlossen',
|
||||||
// '%s updated a subtask for the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '',
|
'%s created a subtask for the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s hat eine Unteraufgabe für die Aufgabe <a href="?controller=task&action=show&task_id=%d">#%d</a> angelegt',
|
||||||
// 'Assigned to %s with an estimate of %s/%sh' => '',
|
'%s updated a subtask for the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s hat eine Unteraufgabe der Aufgabe <a href="?controller=task&action=show&task_id=%d">#%d</a> verändert',
|
||||||
// 'Not assigned, estimate of %sh' => '',
|
'Assigned to %s with an estimate of %s/%sh' => 'An %s zugewiesen mit einer Schätzung von %s/%s Stunden',
|
||||||
// '%s updated a comment on the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '',
|
'Not assigned, estimate of %sh' => 'Nicht zugewiesen, Schätzung von %s Stunden',
|
||||||
// '%s commented the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '',
|
'%s updated a comment on the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s hat einen Kommentat der Aufgabe <a href="?controller=task&action=show&task_id=%d">#%d</a> aktualisiert',
|
||||||
// '%s\'s activity' => '',
|
'%s commented the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s hat die Aufgabe <a href="?controller=task&action=show&task_id=%d">#%d</a> kommentiert',
|
||||||
// 'No activity.' => '',
|
'%s\'s activity' => '%s\'s Aktivität',
|
||||||
// 'RSS feed' => '',
|
'No activity.' => 'Keine Aktivität.',
|
||||||
// '%s updated a comment on the task #%d' => '',
|
'RSS feed' => 'RSS Feed',
|
||||||
// '%s commented on the task #%d' => '',
|
'%s updated a comment on the task #%d' => '%s hat einen Kommentar der Aufgabe #%d aktualisiert',
|
||||||
// '%s updated a subtask for the task #%d' => '',
|
'%s commented on the task #%d' => '%s hat die Aufgabe #%d kommentiert',
|
||||||
// '%s created a subtask for the task #%d' => '',
|
'%s updated a subtask for the task #%d' => '%s hat eine Unteraufgabe der Aufgabe #%d aktualisiert',
|
||||||
// '%s updated the task #%d' => '',
|
'%s created a subtask for the task #%d' => '%s hat eine Unteraufgabe der Aufgabe #%d angelegt',
|
||||||
// '%s created the task #%d' => '',
|
'%s updated the task #%d' => '%s hat die Aufgabe #%d aktualisiert',
|
||||||
// '%s closed the task #%d' => '',
|
'%s created the task #%d' => '%s hat die Aufgabe #%d angelegt',
|
||||||
// '%s open the task #%d' => '',
|
'%s closed the task #%d' => '%s hat die Aufgabe #%d geschlossen',
|
||||||
// '%s moved the task #%d to the column "%s"' => '',
|
'%s open the task #%d' => '%s hat die Aufgabe #%d geöffnet',
|
||||||
// '%s moved the task #%d to the position %d in the column "%s"' => '',
|
'%s moved the task #%d to the column "%s"' => '%s hat die Aufgabe #%d in die Spalte "%s" verschoben',
|
||||||
// 'Activity' => '',
|
'%s moved the task #%d to the position %d in the column "%s"' => '%s hat die Aufgabe #%d an die Position %d in der Spalte "%s" verschoben',
|
||||||
// 'Default values are "%s"' => '',
|
'Activity' => 'Aktivität',
|
||||||
// 'Default columns for new projects (Comma-separated)' => '',
|
'Default values are "%s"' => 'Die Standardwerte sind "%s"',
|
||||||
// 'Task assignee change' => '',
|
'Default columns for new projects (Comma-separated)' => 'Standardspalten für neue Projekte (komma-getrennt)',
|
||||||
// '%s change the assignee of the task #%d' => '',
|
'Task assignee change' => 'Zuständigkeit geändert',
|
||||||
// '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '',
|
'%s change the assignee of the task #%d to %s' => '%s hat die Zusständigkeit der Aufgabe #%d geändert um %s',
|
||||||
// '[%s][Column Change] %s (#%d)' => '',
|
'%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to %s' => '%s hat die Zuständigkeit der Aufgabe <a href="?controller=task&action=show&task_id=%d">#%d</a> geändert um %s',
|
||||||
// '[%s][Position Change] %s (#%d)' => '',
|
'[%s][Column Change] %s (#%d)' => '[%s][Spaltenänderung] %s (#%d)',
|
||||||
// '[%s][Assignee Change] %s (#%d)' => '',
|
'[%s][Position Change] %s (#%d)' => '[%s][Positionsänderung] %s (#%d)',
|
||||||
// 'New password for the user "%s"' => '',
|
'[%s][Assignee Change] %s (#%d)' => '[%s][Zuständigkeitsänderung] %s (#%d)',
|
||||||
|
'New password for the user "%s"' => 'Neues Passwort des Benutzers "%s"',
|
||||||
|
'Choose an event' => 'Aktion wählen',
|
||||||
|
'Github commit received' => 'Github commit empfangen',
|
||||||
|
'Github issue opened' => 'Github Fehler geöffnet',
|
||||||
|
'Github issue closed' => 'Github Fehler geschlossen',
|
||||||
|
'Github issue reopened' => 'Github Fehler erneut geöffnet',
|
||||||
|
'Github issue assignee change' => 'Github Fehlerzuständigkeit geändert',
|
||||||
|
'Github issue label change' => 'Github Fehlerkennzeichnung verändert',
|
||||||
|
'Create a task from an external provider' => 'Eine Aufgabe durch einen externen Provider hinzufügen',
|
||||||
|
// 'Change the assignee based on an external username' => '',
|
||||||
|
'Change the category based on an external label' => 'Kategorie basierend auf einer externen Kennzeichnung ändern',
|
||||||
|
'Reference' => 'Referenz',
|
||||||
|
'Reference: %s' => 'Referenz: %s',
|
||||||
|
'Label' => 'Kennzeichnung',
|
||||||
|
'Database' => 'Datenbank',
|
||||||
|
'About' => 'Über',
|
||||||
|
'Database driver:' => 'Datenbanktreiber',
|
||||||
|
'Board settings' => 'Pinnwandeinstellungen',
|
||||||
|
'URL and token' => 'URL und Token',
|
||||||
|
'Webhook settings' => 'Webhook Einstellungen',
|
||||||
|
'URL for task creation:' => 'URL zur Aufgabenerstellung',
|
||||||
|
'Reset token' => 'Token zurücksetzen',
|
||||||
|
'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',
|
||||||
|
'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',
|
||||||
|
'ISO format is always accepted, example: "%s" and "%s"' => 'ISO Format wird immer akzeptiert, z.B.: "%s" und "%s"',
|
||||||
|
'New private project' => 'Neues privates Projekt',
|
||||||
|
'This project is private' => 'Dieses Projekt ist privat',
|
||||||
|
'Type here to create a new sub-task' => 'Hier tippen, um eine neue Unteraufgabe zu erstellen',
|
||||||
|
'Add' => 'Hinzufügen',
|
||||||
|
'Estimated time: %s hours' => 'Geplante Zeit: %s Stunden',
|
||||||
|
'Time spent: %s hours' => 'Aufgewendete Zeit: %s Stunden',
|
||||||
|
'Started on %B %e, %Y' => 'Gestartet am %B %e %Y',
|
||||||
|
'Start date' => 'Startdatum',
|
||||||
|
'Time estimated' => 'Geplante Zeit',
|
||||||
|
'There is nothing assigned to you.' => 'Es ist nichts an Sie zugewiesen.',
|
||||||
|
'My tasks' => 'Meine Aufgaben',
|
||||||
|
'Activity stream' => 'Letzte Aktivitäten',
|
||||||
|
'Dashboard' => 'Dashboard',
|
||||||
|
'Confirmation' => 'Wiederholung',
|
||||||
|
'Allow everybody to access to this project' => 'Jedem Zugriff zu diesem Projekt gewähren',
|
||||||
|
'Everybody have access to this project.' => 'Jeder hat Zugriff zu diesem Projekt',
|
||||||
|
'Webhooks' => 'Webhooks',
|
||||||
|
'API' => 'API',
|
||||||
|
'Integration' => 'Integration',
|
||||||
|
'Github webhook' => 'Github Webhook',
|
||||||
|
'Help on Github webhook' => 'Hilfe bei einem Github Webhook',
|
||||||
|
'Create a comment from an external provider' => 'Kommentar eines externen Providers hinzufügen',
|
||||||
|
'Github issue comment created' => 'Github Fehler Kommentar hinzugefügt',
|
||||||
);
|
);
|
|
@ -83,7 +83,7 @@ return array(
|
||||||
'Settings' => 'Preferencias',
|
'Settings' => 'Preferencias',
|
||||||
'Application settings' => 'Parámetros de la aplicación',
|
'Application settings' => 'Parámetros de la aplicación',
|
||||||
'Language' => 'Idioma',
|
'Language' => 'Idioma',
|
||||||
'Webhooks token:' => 'Ficha de seguridad (token) para los webhooks :',
|
'Webhook token:' => 'Ficha de seguridad (token) para los webhooks :',
|
||||||
'API token:' => 'Ficha de seguridad (token) para API:',
|
'API token:' => 'Ficha de seguridad (token) para API:',
|
||||||
'More information' => 'Más informaciones',
|
'More information' => 'Más informaciones',
|
||||||
'Database size:' => 'Tamaño de la base de datos:',
|
'Database size:' => 'Tamaño de la base de datos:',
|
||||||
|
@ -196,7 +196,7 @@ return array(
|
||||||
'revoke' => 'revocar',
|
'revoke' => 'revocar',
|
||||||
'List of authorized users' => 'Lista de los usuarios autorizados',
|
'List of authorized users' => 'Lista de los usuarios autorizados',
|
||||||
'User' => 'Usuario',
|
'User' => 'Usuario',
|
||||||
'Everybody have access to this project.' => 'Todo el mundo tiene acceso al proyecto.',
|
// 'Nobody have access to this project.' => '',
|
||||||
'You are not allowed to access to this project.' => 'No está autorizado a acceder a este proyecto.',
|
'You are not allowed to access to this project.' => 'No está autorizado a acceder a este proyecto.',
|
||||||
'Comments' => 'Comentarios',
|
'Comments' => 'Comentarios',
|
||||||
'Post comment' => 'Commentar',
|
'Post comment' => 'Commentar',
|
||||||
|
@ -209,8 +209,6 @@ return array(
|
||||||
'The description is required' => 'La descripción es obligatoria',
|
'The description is required' => 'La descripción es obligatoria',
|
||||||
'Edit this task' => 'Editar esta tarea',
|
'Edit this task' => 'Editar esta tarea',
|
||||||
'Due Date' => 'Fecha límite',
|
'Due Date' => 'Fecha límite',
|
||||||
'm/d/Y' => 'd/m/Y',
|
|
||||||
'month/day/year' => 'día/mes/año',
|
|
||||||
'Invalid date' => 'Fecha no válida',
|
'Invalid date' => 'Fecha no válida',
|
||||||
'Must be done before %B %e, %Y' => 'Debe de estar hecho antes del %d/%m/%Y',
|
'Must be done before %B %e, %Y' => 'Debe de estar hecho antes del %d/%m/%Y',
|
||||||
'%B %e, %Y' => '%d/%m/%Y',
|
'%B %e, %Y' => '%d/%m/%Y',
|
||||||
|
@ -351,9 +349,9 @@ return array(
|
||||||
'estimated' => 'estimado',
|
'estimated' => 'estimado',
|
||||||
'Sub-Tasks' => 'Sub-Tareas',
|
'Sub-Tasks' => 'Sub-Tareas',
|
||||||
'Add a sub-task' => 'Añadir una sub-tarea',
|
'Add a sub-task' => 'Añadir una sub-tarea',
|
||||||
'Original Estimate' => 'Estimado Original',
|
'Original estimate' => 'Estimado Original',
|
||||||
'Create another sub-task' => 'Crear otra sub-tarea',
|
'Create another sub-task' => 'Crear otra sub-tarea',
|
||||||
'Time Spent' => 'Tiempo Transcurrido',
|
'Time spent' => 'Tiempo Transcurrido',
|
||||||
'Edit a sub-task' => 'Editar una sub-tarea',
|
'Edit a sub-task' => 'Editar una sub-tarea',
|
||||||
'Remove a sub-task' => 'Suprimir una sub-tarea',
|
'Remove a sub-task' => 'Suprimir una sub-tarea',
|
||||||
'The time must be a numeric value' => 'El tiempo debe de ser un valor numérico',
|
'The time must be a numeric value' => 'El tiempo debe de ser un valor numérico',
|
||||||
|
@ -422,8 +420,8 @@ return array(
|
||||||
'I want to receive notifications only for those projects:' => 'Quiero recibir notificaciones sólo de estos proyectos:',
|
'I want to receive notifications only for those projects:' => 'Quiero recibir notificaciones sólo de estos proyectos:',
|
||||||
'view the task on Kanboard' => 'ver la tarea en Kanboard',
|
'view the task on Kanboard' => 'ver la tarea en Kanboard',
|
||||||
'Public access' => 'Acceso público',
|
'Public access' => 'Acceso público',
|
||||||
'Categories management' => 'Gestión de Categorías',
|
'Category management' => 'Gestión de Categorías',
|
||||||
'Users management' => 'Gestión de Usuarios',
|
'User management' => 'Gestión de Usuarios',
|
||||||
'Active tasks' => 'Tareas activas',
|
'Active tasks' => 'Tareas activas',
|
||||||
'Disable public access' => 'Desactivar acceso público',
|
'Disable public access' => 'Desactivar acceso público',
|
||||||
'Enable public access' => 'Activar acceso público',
|
'Enable public access' => 'Activar acceso público',
|
||||||
|
@ -451,6 +449,7 @@ return array(
|
||||||
'Email:' => 'Correo electrónico:',
|
'Email:' => 'Correo electrónico:',
|
||||||
'Default project:' => 'Proyecto por defecto:',
|
'Default project:' => 'Proyecto por defecto:',
|
||||||
'Notifications:' => 'Notificaciones:',
|
'Notifications:' => 'Notificaciones:',
|
||||||
|
// 'Notifications' => '',
|
||||||
'Group:' => 'Grupo:',
|
'Group:' => 'Grupo:',
|
||||||
'Regular user' => 'Usuario regular:',
|
'Regular user' => 'Usuario regular:',
|
||||||
'Account type:' => 'Tipo de Cuenta:',
|
'Account type:' => 'Tipo de Cuenta:',
|
||||||
|
@ -496,11 +495,67 @@ return array(
|
||||||
'Activity' => 'Actividad',
|
'Activity' => 'Actividad',
|
||||||
'Default values are "%s"' => 'Los valores por defecto son "%s"',
|
'Default values are "%s"' => 'Los valores por defecto son "%s"',
|
||||||
'Default columns for new projects (Comma-separated)' => 'Columnas por defecto de los nuevos proyectos (Separadas mediante comas)',
|
'Default columns for new projects (Comma-separated)' => 'Columnas por defecto de los nuevos proyectos (Separadas mediante comas)',
|
||||||
// 'Task assignee change' => '',
|
'Task assignee change' => 'Cambiar persona asignada a la tarea',
|
||||||
// '%s change the assignee of the task #%d' => '',
|
// '%s change the assignee of the task #%d to %s' => '',
|
||||||
// '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '',
|
// '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to %s' => '',
|
||||||
// '[%s][Column Change] %s (#%d)' => '',
|
'[%s][Column Change] %s (#%d)' => '[%s][Cambia Columna] %s (#%d)',
|
||||||
// '[%s][Position Change] %s (#%d)' => '',
|
'[%s][Position Change] %s (#%d)' => '[%s][Cambia Posición] %s (#%d)',
|
||||||
// '[%s][Assignee Change] %s (#%d)' => '',
|
'[%s][Assignee Change] %s (#%d)' => '[%s][Cambia Persona Asignada] %s (#%d)',
|
||||||
// 'New password for the user "%s"' => '',
|
'New password for the user "%s"' => 'Nueva contraseña para el usuario "%s"',
|
||||||
|
// 'Choose an event' => '',
|
||||||
|
// 'Github commit received' => '',
|
||||||
|
// 'Github issue opened' => '',
|
||||||
|
// 'Github issue closed' => '',
|
||||||
|
// 'Github issue reopened' => '',
|
||||||
|
// 'Github issue assignee change' => '',
|
||||||
|
// 'Github issue label change' => '',
|
||||||
|
// 'Create a task from an external provider' => '',
|
||||||
|
// 'Change the assignee based on an external username' => '',
|
||||||
|
// 'Change the category based on an external label' => '',
|
||||||
|
// 'Reference' => '',
|
||||||
|
// 'Reference: %s' => '',
|
||||||
|
// 'Label' => '',
|
||||||
|
// 'Database' => '',
|
||||||
|
// 'About' => '',
|
||||||
|
// 'Database driver:' => '',
|
||||||
|
// 'Board settings' => '',
|
||||||
|
// 'URL and token' => '',
|
||||||
|
// 'Webhook settings' => '',
|
||||||
|
// 'URL for task creation:' => '',
|
||||||
|
// 'Reset token' => '',
|
||||||
|
// 'API endpoint:' => '',
|
||||||
|
// 'Refresh interval for private board' => '',
|
||||||
|
// 'Refresh interval for public board' => '',
|
||||||
|
// 'Task highlight period' => '',
|
||||||
|
// 'Period (in second) to consider a task was modified recently (0 to disable, 2 days by default)' => '',
|
||||||
|
// 'Frequency in second (60 seconds by default)' => '',
|
||||||
|
// 'Frequency in second (0 to disable this feature, 10 seconds by default)' => '',
|
||||||
|
// 'Application URL' => '',
|
||||||
|
// 'Example: http://example.kanboard.net/ (used by email notifications)' => '',
|
||||||
|
// 'Token regenerated.' => '',
|
||||||
|
// 'Date format' => '',
|
||||||
|
// 'ISO format is always accepted, example: "%s" and "%s"' => '',
|
||||||
|
// 'New private project' => '',
|
||||||
|
// 'This project is private' => '',
|
||||||
|
// 'Type here to create a new sub-task' => '',
|
||||||
|
// 'Add' => '',
|
||||||
|
// 'Estimated time: %s hours' => '',
|
||||||
|
// 'Time spent: %s hours' => '',
|
||||||
|
// 'Started on %B %e, %Y' => '',
|
||||||
|
// 'Start date' => '',
|
||||||
|
// 'Time estimated' => '',
|
||||||
|
// 'There is nothing assigned to you.' => '',
|
||||||
|
// 'My tasks' => '',
|
||||||
|
// 'Activity stream' => '',
|
||||||
|
// 'Dashboard' => '',
|
||||||
|
// 'Confirmation' => '',
|
||||||
|
// 'Allow everybody to access to this project' => '',
|
||||||
|
// 'Everybody have access to this project.' => '',
|
||||||
|
// 'Webhooks' => '',
|
||||||
|
// 'API' => '',
|
||||||
|
// 'Integration' => '',
|
||||||
|
// 'Github webhook' => '',
|
||||||
|
// 'Help on Github webhook' => '',
|
||||||
|
// 'Create a comment from an external provider' => '',
|
||||||
|
// 'Github issue comment created' => '',
|
||||||
);
|
);
|
|
@ -83,7 +83,7 @@ return array(
|
||||||
'Settings' => 'Asetukset',
|
'Settings' => 'Asetukset',
|
||||||
'Application settings' => 'Ohjelman asetukset',
|
'Application settings' => 'Ohjelman asetukset',
|
||||||
'Language' => 'Kieli',
|
'Language' => 'Kieli',
|
||||||
'Webhooks token:' => 'Webhooks avain:',
|
'Webhook token:' => 'Webhooks avain:',
|
||||||
// 'API token:' => '',
|
// 'API token:' => '',
|
||||||
'More information' => 'Lisätietoja',
|
'More information' => 'Lisätietoja',
|
||||||
'Database size:' => 'Tietokannan koko:',
|
'Database size:' => 'Tietokannan koko:',
|
||||||
|
@ -196,7 +196,7 @@ return array(
|
||||||
'revoke' => 'poista',
|
'revoke' => 'poista',
|
||||||
'List of authorized users' => 'Sallittujen käyttäjien lista',
|
'List of authorized users' => 'Sallittujen käyttäjien lista',
|
||||||
'User' => 'Käyttäjät',
|
'User' => 'Käyttäjät',
|
||||||
'Everybody have access to this project.' => 'Kaikilla on pääsy tähän projektiin.',
|
// 'Nobody have access to this project.' => '',
|
||||||
'You are not allowed to access to this project.' => 'Sinulla ei ole pääsyä tähän projektiin.',
|
'You are not allowed to access to this project.' => 'Sinulla ei ole pääsyä tähän projektiin.',
|
||||||
'Comments' => 'Kommentit',
|
'Comments' => 'Kommentit',
|
||||||
'Post comment' => 'Lisää kommentti',
|
'Post comment' => 'Lisää kommentti',
|
||||||
|
@ -209,8 +209,6 @@ return array(
|
||||||
'The description is required' => 'Kuvaus vaaditaan',
|
'The description is required' => 'Kuvaus vaaditaan',
|
||||||
'Edit this task' => 'Muokkaa tehtävää',
|
'Edit this task' => 'Muokkaa tehtävää',
|
||||||
'Due Date' => 'Deadline',
|
'Due Date' => 'Deadline',
|
||||||
'm/d/Y' => 'd.m.Y',
|
|
||||||
'month/day/year' => 'päivä.kuukausi.vuosi',
|
|
||||||
'Invalid date' => 'Virheellinen päiväys',
|
'Invalid date' => 'Virheellinen päiväys',
|
||||||
'Must be done before %B %e, %Y' => 'Täytyy suorittaa ennen %d.%m.%Y',
|
'Must be done before %B %e, %Y' => 'Täytyy suorittaa ennen %d.%m.%Y',
|
||||||
'%B %e, %Y' => '%d.%m.%Y',
|
'%B %e, %Y' => '%d.%m.%Y',
|
||||||
|
@ -351,9 +349,9 @@ return array(
|
||||||
'estimated' => 'estimoitu',
|
'estimated' => 'estimoitu',
|
||||||
'Sub-Tasks' => 'Alitehtävät',
|
'Sub-Tasks' => 'Alitehtävät',
|
||||||
'Add a sub-task' => 'Lisää alitehtävä',
|
'Add a sub-task' => 'Lisää alitehtävä',
|
||||||
'Original Estimate' => 'Alkuperäinen estimaatti',
|
'Original estimate' => 'Alkuperäinen estimaatti',
|
||||||
'Create another sub-task' => 'Lisää toinen alitehtävä',
|
'Create another sub-task' => 'Lisää toinen alitehtävä',
|
||||||
'Time Spent' => 'Käytetty aika',
|
'Time spent' => 'Käytetty aika',
|
||||||
'Edit a sub-task' => 'Muokkaa alitehtävää',
|
'Edit a sub-task' => 'Muokkaa alitehtävää',
|
||||||
'Remove a sub-task' => 'Poista alitehtävä',
|
'Remove a sub-task' => 'Poista alitehtävä',
|
||||||
'The time must be a numeric value' => 'Ajan pitää olla numero',
|
'The time must be a numeric value' => 'Ajan pitää olla numero',
|
||||||
|
@ -422,8 +420,8 @@ return array(
|
||||||
// 'I want to receive notifications only for those projects:' => '',
|
// 'I want to receive notifications only for those projects:' => '',
|
||||||
// 'view the task on Kanboard' => '',
|
// 'view the task on Kanboard' => '',
|
||||||
// 'Public access' => '',
|
// 'Public access' => '',
|
||||||
// 'Categories management' => '',
|
// 'Category management' => '',
|
||||||
// 'Users management' => '',
|
// 'User management' => '',
|
||||||
// 'Active tasks' => '',
|
// 'Active tasks' => '',
|
||||||
// 'Disable public access' => '',
|
// 'Disable public access' => '',
|
||||||
// 'Enable public access' => '',
|
// 'Enable public access' => '',
|
||||||
|
@ -451,6 +449,7 @@ return array(
|
||||||
// 'Email:' => '',
|
// 'Email:' => '',
|
||||||
// 'Default project:' => '',
|
// 'Default project:' => '',
|
||||||
// 'Notifications:' => '',
|
// 'Notifications:' => '',
|
||||||
|
// 'Notifications' => '',
|
||||||
// 'Group:' => '',
|
// 'Group:' => '',
|
||||||
// 'Regular user' => '',
|
// 'Regular user' => '',
|
||||||
// 'Account type:' => '',
|
// 'Account type:' => '',
|
||||||
|
@ -497,10 +496,66 @@ return array(
|
||||||
// 'Default values are "%s"' => '',
|
// 'Default values are "%s"' => '',
|
||||||
// 'Default columns for new projects (Comma-separated)' => '',
|
// 'Default columns for new projects (Comma-separated)' => '',
|
||||||
// 'Task assignee change' => '',
|
// 'Task assignee change' => '',
|
||||||
// '%s change the assignee of the task #%d' => '',
|
// '%s change the assignee of the task #%d to %s' => '',
|
||||||
// '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '',
|
// '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to %s' => '',
|
||||||
// '[%s][Column Change] %s (#%d)' => '',
|
// '[%s][Column Change] %s (#%d)' => '',
|
||||||
// '[%s][Position Change] %s (#%d)' => '',
|
// '[%s][Position Change] %s (#%d)' => '',
|
||||||
// '[%s][Assignee Change] %s (#%d)' => '',
|
// '[%s][Assignee Change] %s (#%d)' => '',
|
||||||
// 'New password for the user "%s"' => '',
|
// 'New password for the user "%s"' => '',
|
||||||
|
// 'Choose an event' => '',
|
||||||
|
// 'Github commit received' => '',
|
||||||
|
// 'Github issue opened' => '',
|
||||||
|
// 'Github issue closed' => '',
|
||||||
|
// 'Github issue reopened' => '',
|
||||||
|
// 'Github issue assignee change' => '',
|
||||||
|
// 'Github issue label change' => '',
|
||||||
|
// 'Create a task from an external provider' => '',
|
||||||
|
// 'Change the assignee based on an external username' => '',
|
||||||
|
// 'Change the category based on an external label' => '',
|
||||||
|
// 'Reference' => '',
|
||||||
|
// 'Reference: %s' => '',
|
||||||
|
// 'Label' => '',
|
||||||
|
// 'Database' => '',
|
||||||
|
// 'About' => '',
|
||||||
|
// 'Database driver:' => '',
|
||||||
|
// 'Board settings' => '',
|
||||||
|
// 'URL and token' => '',
|
||||||
|
// 'Webhook settings' => '',
|
||||||
|
// 'URL for task creation:' => '',
|
||||||
|
// 'Reset token' => '',
|
||||||
|
// 'API endpoint:' => '',
|
||||||
|
// 'Refresh interval for private board' => '',
|
||||||
|
// 'Refresh interval for public board' => '',
|
||||||
|
// 'Task highlight period' => '',
|
||||||
|
// 'Period (in second) to consider a task was modified recently (0 to disable, 2 days by default)' => '',
|
||||||
|
// 'Frequency in second (60 seconds by default)' => '',
|
||||||
|
// 'Frequency in second (0 to disable this feature, 10 seconds by default)' => '',
|
||||||
|
// 'Application URL' => '',
|
||||||
|
// 'Example: http://example.kanboard.net/ (used by email notifications)' => '',
|
||||||
|
// 'Token regenerated.' => '',
|
||||||
|
// 'Date format' => '',
|
||||||
|
// 'ISO format is always accepted, example: "%s" and "%s"' => '',
|
||||||
|
// 'New private project' => '',
|
||||||
|
// 'This project is private' => '',
|
||||||
|
// 'Type here to create a new sub-task' => '',
|
||||||
|
// 'Add' => '',
|
||||||
|
// 'Estimated time: %s hours' => '',
|
||||||
|
// 'Time spent: %s hours' => '',
|
||||||
|
// 'Started on %B %e, %Y' => '',
|
||||||
|
// 'Start date' => '',
|
||||||
|
// 'Time estimated' => '',
|
||||||
|
// 'There is nothing assigned to you.' => '',
|
||||||
|
// 'My tasks' => '',
|
||||||
|
// 'Activity stream' => '',
|
||||||
|
// 'Dashboard' => '',
|
||||||
|
// 'Confirmation' => '',
|
||||||
|
// 'Allow everybody to access to this project' => '',
|
||||||
|
// 'Everybody have access to this project.' => '',
|
||||||
|
// 'Webhooks' => '',
|
||||||
|
// 'API' => '',
|
||||||
|
// 'Integration' => '',
|
||||||
|
// 'Github webhook' => '',
|
||||||
|
// 'Help on Github webhook' => '',
|
||||||
|
// 'Create a comment from an external provider' => '',
|
||||||
|
// 'Github issue comment created' => '',
|
||||||
);
|
);
|
|
@ -83,7 +83,7 @@ return array(
|
||||||
'Settings' => 'Préférences',
|
'Settings' => 'Préférences',
|
||||||
'Application settings' => 'Paramètres de l\'application',
|
'Application settings' => 'Paramètres de l\'application',
|
||||||
'Language' => 'Langue',
|
'Language' => 'Langue',
|
||||||
'Webhooks token:' => 'Jeton de securité pour les webhooks :',
|
'Webhook token:' => 'Jeton de securité pour les webhooks :',
|
||||||
'API token:' => 'Jeton de securité pour l\'API :',
|
'API token:' => 'Jeton de securité pour l\'API :',
|
||||||
'More information' => 'Plus d\'informations',
|
'More information' => 'Plus d\'informations',
|
||||||
'Database size:' => 'Taille de la base de données :',
|
'Database size:' => 'Taille de la base de données :',
|
||||||
|
@ -196,7 +196,7 @@ return array(
|
||||||
'revoke' => 'révoquer',
|
'revoke' => 'révoquer',
|
||||||
'List of authorized users' => 'Liste des utilisateurs autorisés',
|
'List of authorized users' => 'Liste des utilisateurs autorisés',
|
||||||
'User' => 'Utilisateur',
|
'User' => 'Utilisateur',
|
||||||
'Everybody have access to this project.' => 'Tout le monde a accès au projet.',
|
'Nobody have access to this project.' => 'Personne n\'est autorisé à accéder au projet.',
|
||||||
'You are not allowed to access to this project.' => 'Vous n\'êtes pas autorisé à accéder à ce projet.',
|
'You are not allowed to access to this project.' => 'Vous n\'êtes pas autorisé à accéder à ce projet.',
|
||||||
'Comments' => 'Commentaires',
|
'Comments' => 'Commentaires',
|
||||||
'Post comment' => 'Commenter',
|
'Post comment' => 'Commenter',
|
||||||
|
@ -209,11 +209,9 @@ return array(
|
||||||
'The description is required' => 'La description est obligatoire',
|
'The description is required' => 'La description est obligatoire',
|
||||||
'Edit this task' => 'Modifier cette tâche',
|
'Edit this task' => 'Modifier cette tâche',
|
||||||
'Due Date' => 'Date d\'échéance',
|
'Due Date' => 'Date d\'échéance',
|
||||||
'm/d/Y' => 'd/m/Y', // Date format parsed with php
|
|
||||||
'month/day/year' => 'jour/mois/année', // Help shown to the user
|
|
||||||
'Invalid date' => 'Date invalide',
|
'Invalid date' => 'Date invalide',
|
||||||
'Must be done before %B %e, %Y' => 'Doit être fait avant le %d/%m/%Y',
|
'Must be done before %B %e, %Y' => 'Doit être fait avant le %d/%m/%Y',
|
||||||
'%B %e, %Y' => '%d/%m/%Y',
|
'%B %e, %Y' => '%d %B %Y',
|
||||||
'Automatic actions' => 'Actions automatisées',
|
'Automatic actions' => 'Actions automatisées',
|
||||||
'Your automatic action have been created successfully.' => 'Votre action automatisée a été ajouté avec succès.',
|
'Your automatic action have been created successfully.' => 'Votre action automatisée a été ajouté avec succès.',
|
||||||
'Unable to create your automatic action.' => 'Impossible de créer votre action automatisée.',
|
'Unable to create your automatic action.' => 'Impossible de créer votre action automatisée.',
|
||||||
|
@ -351,9 +349,9 @@ return array(
|
||||||
'estimated' => 'estimé',
|
'estimated' => 'estimé',
|
||||||
'Sub-Tasks' => 'Sous-Tâches',
|
'Sub-Tasks' => 'Sous-Tâches',
|
||||||
'Add a sub-task' => 'Ajouter une sous-tâche',
|
'Add a sub-task' => 'Ajouter une sous-tâche',
|
||||||
'Original Estimate' => 'Estimation originale',
|
'Original estimate' => 'Estimation originale',
|
||||||
'Create another sub-task' => 'Créer une autre sous-tâche',
|
'Create another sub-task' => 'Créer une autre sous-tâche',
|
||||||
'Time Spent' => 'Temps passé',
|
'Time spent' => 'Temps passé',
|
||||||
'Edit a sub-task' => 'Modifier une sous-tâche',
|
'Edit a sub-task' => 'Modifier une sous-tâche',
|
||||||
'Remove a sub-task' => 'Supprimer une sous-tâche',
|
'Remove a sub-task' => 'Supprimer une sous-tâche',
|
||||||
'The time must be a numeric value' => 'Le temps doit-être une valeur numérique',
|
'The time must be a numeric value' => 'Le temps doit-être une valeur numérique',
|
||||||
|
@ -422,8 +420,8 @@ return array(
|
||||||
'I want to receive notifications only for those projects:' => 'Je souhaite reçevoir les notifications uniquement pour les projets sélectionnés :',
|
'I want to receive notifications only for those projects:' => 'Je souhaite reçevoir les notifications uniquement pour les projets sélectionnés :',
|
||||||
'view the task on Kanboard' => 'voir la tâche sur Kanboard',
|
'view the task on Kanboard' => 'voir la tâche sur Kanboard',
|
||||||
'Public access' => 'Accès public',
|
'Public access' => 'Accès public',
|
||||||
'Categories management' => 'Gestion des catégories',
|
'Category management' => 'Gestion des catégories',
|
||||||
'Users management' => 'Gestion des utilisateurs',
|
'User management' => 'Gestion des utilisateurs',
|
||||||
'Active tasks' => 'Tâches actives',
|
'Active tasks' => 'Tâches actives',
|
||||||
'Disable public access' => 'Désactiver l\'accès public',
|
'Disable public access' => 'Désactiver l\'accès public',
|
||||||
'Enable public access' => 'Activer l\'accès public',
|
'Enable public access' => 'Activer l\'accès public',
|
||||||
|
@ -451,10 +449,11 @@ return array(
|
||||||
'Email:' => 'Email :',
|
'Email:' => 'Email :',
|
||||||
'Default project:' => 'Projet par défaut :',
|
'Default project:' => 'Projet par défaut :',
|
||||||
'Notifications:' => 'Notifications :',
|
'Notifications:' => 'Notifications :',
|
||||||
|
'Notifications' => 'Notifications',
|
||||||
'Group:' => 'Groupe :',
|
'Group:' => 'Groupe :',
|
||||||
'Regular user' => 'Utilisateur normal',
|
'Regular user' => 'Utilisateur normal',
|
||||||
'Account type:' => 'Type de compte :',
|
'Account type:' => 'Type de compte :',
|
||||||
'Edit profile' => 'Modifier le profile',
|
'Edit profile' => 'Modifier le profil',
|
||||||
'Change password' => 'Changer le mot de passe',
|
'Change password' => 'Changer le mot de passe',
|
||||||
'Password modification' => 'Changement de mot de passe',
|
'Password modification' => 'Changement de mot de passe',
|
||||||
'External authentications' => 'Authentifications externe',
|
'External authentications' => 'Authentifications externe',
|
||||||
|
@ -497,10 +496,66 @@ return array(
|
||||||
'Default values are "%s"' => 'Les valeurs par défaut sont « %s »',
|
'Default values are "%s"' => 'Les valeurs par défaut sont « %s »',
|
||||||
'Default columns for new projects (Comma-separated)' => 'Colonnes par défaut pour les nouveaux projets (séparé par des virgules)',
|
'Default columns for new projects (Comma-separated)' => 'Colonnes par défaut pour les nouveaux projets (séparé par des virgules)',
|
||||||
'Task assignee change' => 'Modification de la personne assignée sur une tâche',
|
'Task assignee change' => 'Modification de la personne assignée sur une tâche',
|
||||||
'%s change the assignee of the task #%d' => '%s a changé la personne assignée sur la tâche #%d',
|
'%s change the assignee of the task #%d to %s' => '%s a changé la personne assignée sur la tâche #%d pour %s',
|
||||||
'%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s a changé la personne assignée sur la tâche <a href="?controller=task&action=show&task_id=%d">n°%d</a>',
|
'%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to %s' => '%s a changé la personne assignée sur la tâche <a href="?controller=task&action=show&task_id=%d">n°%d</a> pour %s',
|
||||||
'[%s][Column Change] %s (#%d)' => '[%s][Changement de colonne] %s (#%d)',
|
'[%s][Column Change] %s (#%d)' => '[%s][Changement de colonne] %s (#%d)',
|
||||||
'[%s][Position Change] %s (#%d)' => '[%s][Changement de position] %s (#%d)',
|
'[%s][Position Change] %s (#%d)' => '[%s][Changement de position] %s (#%d)',
|
||||||
'[%s][Assignee Change] %s (#%d)' => '[%s][Changement d\'assigné] %s (#%d)',
|
'[%s][Assignee Change] %s (#%d)' => '[%s][Changement d\'assigné] %s (#%d)',
|
||||||
'New password for the user "%s"' => 'Nouveau mot de passe pour l\'utilisateur « %s »',
|
'New password for the user "%s"' => 'Nouveau mot de passe pour l\'utilisateur « %s »',
|
||||||
|
'Choose an event' => 'Choisir un événement',
|
||||||
|
'Github commit received' => '« Commit » reçu via Github',
|
||||||
|
'Github issue opened' => 'Ouverture d\'un ticket sur Github',
|
||||||
|
'Github issue closed' => 'Fermeture d\'un ticket sur Github',
|
||||||
|
'Github issue reopened' => 'Réouverture d\'un ticket sur Github',
|
||||||
|
'Github issue assignee change' => 'Changement d\'assigné sur un ticket Github',
|
||||||
|
'Github issue label change' => 'Changement de libellé sur un ticket Github',
|
||||||
|
'Create a task from an external provider' => 'Créer une tâche depuis un fournisseur externe',
|
||||||
|
'Change the assignee based on an external username' => 'Changer l\'assigné en fonction d\'un utilisateur externe',
|
||||||
|
'Change the category based on an external label' => 'Changer la catégorie en fonction d\'un libellé externe',
|
||||||
|
'Reference' => 'Référence',
|
||||||
|
'Reference: %s' => 'Référence : %s',
|
||||||
|
'Label' => 'Libellé',
|
||||||
|
'Database' => 'Base de données',
|
||||||
|
'About' => 'A propos',
|
||||||
|
'Database driver:' => 'Type de base de données :',
|
||||||
|
'Board settings' => 'Paramètres du tableau',
|
||||||
|
'URL and token' => 'URL et jeton de sécurité',
|
||||||
|
'Webhook settings' => 'Paramètres pour les webhooks',
|
||||||
|
'URL for task creation:' => 'URL pour la création de tâche :',
|
||||||
|
'Reset token' => 'Regénérer le jeton de sécurité',
|
||||||
|
'API endpoint:' => 'URL de l\'API :',
|
||||||
|
'Refresh interval for private board' => 'Intervalle pour rafraîchir un tableau privé',
|
||||||
|
'Refresh interval for public board' => 'Intervalle pour rafraîchir un tableau public',
|
||||||
|
'Task highlight period' => 'Durée pour mettre une tâche en évidence',
|
||||||
|
'Period (in second) to consider a task was modified recently (0 to disable, 2 days by default)' => 'Durée en seconde pour considérer une tâche comme récemment modifiée (0 pour désactiver, 2 jours par défaut)',
|
||||||
|
'Frequency in second (60 seconds by default)' => 'Fréquence en seconde (60 secondes par défaut)',
|
||||||
|
'Frequency in second (0 to disable this feature, 10 seconds by default)' => 'Fréquence en seconde (0 pour désactiver, 10 secondes par défaut)',
|
||||||
|
'Application URL' => 'URL de l\'application',
|
||||||
|
'Example: http://example.kanboard.net/ (used by email notifications)' => 'Exemple : http://exemple.kanboard.net/ (utilisé pour les notifications)',
|
||||||
|
'Token regenerated.' => 'Jeton de sécurité regénéré.',
|
||||||
|
'Date format' => 'Format des dates',
|
||||||
|
'ISO format is always accepted, example: "%s" and "%s"' => 'Le format ISO est toujours accepté, exemple : « %s » et « %s »',
|
||||||
|
'New private project' => 'Nouveau projet privé',
|
||||||
|
'This project is private' => 'Ce projet est privé',
|
||||||
|
'Type here to create a new sub-task' => 'Créer une sous-tâche en écrivant le titre ici',
|
||||||
|
'Add' => 'Ajouter',
|
||||||
|
'Estimated time: %s hours' => 'Temps estimé: %s hours',
|
||||||
|
'Time spent: %s hours' => 'Temps passé : %s heures',
|
||||||
|
'Started on %B %e, %Y' => 'Commençé le %d/%m/%Y',
|
||||||
|
'Start date' => 'Date de début',
|
||||||
|
'Time estimated' => 'Temps estimé',
|
||||||
|
'There is nothing assigned to you.' => 'Aucune tâche assignée pour vous.',
|
||||||
|
'My tasks' => 'Mes tâches',
|
||||||
|
'Activity stream' => 'Flux d\'activité',
|
||||||
|
'Dashboard' => 'Tableau de bord',
|
||||||
|
'Confirmation' => 'Confirmation',
|
||||||
|
'Allow everybody to access to this project' => 'Autoriser tout le monde à accéder à ce projet',
|
||||||
|
'Everybody have access to this project.' => 'Tout le monde a acccès à ce projet.',
|
||||||
|
'Webhooks' => 'Webhooks',
|
||||||
|
'API' => 'API',
|
||||||
|
'Integration' => 'Intégration',
|
||||||
|
'Github webhook' => 'Webhook Github',
|
||||||
|
'Help on Github webhook' => 'Aide sur les webhooks Github',
|
||||||
|
'Create a comment from an external provider' => 'Créer un commentaire depuis un fournisseur externe',
|
||||||
|
'Github issue comment created' => 'Commentaire créé sur un ticket Github',
|
||||||
);
|
);
|
|
@ -14,13 +14,13 @@ return array(
|
||||||
'Yellow' => 'Giallo',
|
'Yellow' => 'Giallo',
|
||||||
'Blue' => 'Blu',
|
'Blue' => 'Blu',
|
||||||
'Green' => 'Verde',
|
'Green' => 'Verde',
|
||||||
'Purple' => 'Porpora',
|
'Purple' => 'Viola',
|
||||||
'Red' => 'Rosso',
|
'Red' => 'Rosso',
|
||||||
'Orange' => 'Arancione',
|
'Orange' => 'Arancione',
|
||||||
'Grey' => 'Grigio',
|
'Grey' => 'Grigio',
|
||||||
'Save' => 'Salvare',
|
'Save' => 'Salvare',
|
||||||
'Login' => 'Entra',
|
'Login' => 'Entra',
|
||||||
'Official website:' => 'Sito web ufficiale :',
|
'Official website:' => 'Sito web ufficiale:',
|
||||||
'Unassigned' => 'Non assegnato',
|
'Unassigned' => 'Non assegnato',
|
||||||
'View this task' => 'Vedere questo compito',
|
'View this task' => 'Vedere questo compito',
|
||||||
'Remove user' => 'Cancellare un utente',
|
'Remove user' => 'Cancellare un utente',
|
||||||
|
@ -39,7 +39,7 @@ return array(
|
||||||
'Only administrators can access to this page.' => 'Solo gli amministratori possono accedere a questa pagina.',
|
'Only administrators can access to this page.' => 'Solo gli amministratori possono accedere a questa pagina.',
|
||||||
'Edit user' => 'Modificare un utente',
|
'Edit user' => 'Modificare un utente',
|
||||||
'Logout' => 'Uscire',
|
'Logout' => 'Uscire',
|
||||||
'Bad username or password' => 'Utente o password sbagliato',
|
'Bad username or password' => 'Utente o password errati',
|
||||||
'users' => 'utenti',
|
'users' => 'utenti',
|
||||||
'projects' => 'progetti',
|
'projects' => 'progetti',
|
||||||
'Edit project' => 'Modificare progetto',
|
'Edit project' => 'Modificare progetto',
|
||||||
|
@ -63,7 +63,7 @@ return array(
|
||||||
'Disable' => 'Disattivare',
|
'Disable' => 'Disattivare',
|
||||||
'Enable' => 'Attivare',
|
'Enable' => 'Attivare',
|
||||||
'New project' => 'Nuovo progetto',
|
'New project' => 'Nuovo progetto',
|
||||||
'Do you really want to remove this project: "%s"?' => 'Vuoi veramente eliminare questo progetto: « %s » ?',
|
'Do you really want to remove this project: "%s"?' => 'Veramente vuoi eliminare questo progetto: « %s » ?',
|
||||||
'Remove project' => 'Cancellare il progetto',
|
'Remove project' => 'Cancellare il progetto',
|
||||||
'Boards' => 'Bacheche',
|
'Boards' => 'Bacheche',
|
||||||
'Edit the board for "%s"' => 'Modificare la bacheca per « %s »',
|
'Edit the board for "%s"' => 'Modificare la bacheca per « %s »',
|
||||||
|
@ -76,25 +76,25 @@ return array(
|
||||||
'Nobody assigned' => 'Nessuno assegnato',
|
'Nobody assigned' => 'Nessuno assegnato',
|
||||||
'Assigned to %s' => 'Assegnato a %s',
|
'Assigned to %s' => 'Assegnato a %s',
|
||||||
'Remove a column' => 'Cancellare questa colonna',
|
'Remove a column' => 'Cancellare questa colonna',
|
||||||
'Remove a column from a board' => 'Cancellare una colonna di una bacheca',
|
'Remove a column from a board' => 'Cancellare una colonna da una bacheca',
|
||||||
'Unable to remove this column.' => 'Non si può cancellare questa colonna.',
|
'Unable to remove this column.' => 'Non si può cancellare questa colonna.',
|
||||||
'Do you really want to remove this column: "%s"?' => 'Veramente desideri cancellare questa colonna : « %s » ?',
|
'Do you really want to remove this column: "%s"?' => 'Veramente desideri cancellare questa colonna : « %s » ?',
|
||||||
'This action will REMOVE ALL TASKS associated to this column!' => 'Questa azione cancellerà TUTTI I COMPITI legati a questa colonna!',
|
'This action will REMOVE ALL TASKS associated to this column!' => 'Questa azione cancellerà TUTTI I COMPITI legati a questa colonna!',
|
||||||
'Settings' => 'Impostazioni',
|
'Settings' => 'Impostazioni',
|
||||||
'Application settings' => 'Impostazioni dell\'applicazione',
|
'Application settings' => 'Impostazioni dell\'applicazione',
|
||||||
'Language' => 'Lingua',
|
'Language' => 'Lingua',
|
||||||
'Webhooks token:' => 'Identificatore (token) per i webhooks :',
|
'Webhook token:' => 'Identificatore (token) per i webhooks :',
|
||||||
// 'API token:' => '',
|
// 'API token:' => '',
|
||||||
'More information' => 'Più informazione',
|
'More information' => 'Più informazioni',
|
||||||
'Database size:' => 'Dimensioni della base dati:',
|
'Database size:' => 'Dimensioni della base dati:',
|
||||||
'Download the database' => 'Scaricare la base dati',
|
'Download the database' => 'Scaricare la base dati',
|
||||||
'Optimize the database' => 'Ottimizare la base dati',
|
'Optimize the database' => 'Ottimizare la base dati',
|
||||||
'(VACUUM command)' => '(Comando VACUUM)',
|
'(VACUUM command)' => '(Comando VACUUM)',
|
||||||
'(Gzip compressed Sqlite file)' => '(File Sqlite compresso in Gzip)',
|
'(Gzip compressed Sqlite file)' => '(File Sqlite compresso in Gzip)',
|
||||||
'User settings' => 'Impostazioni di utente',
|
'User settings' => 'Impostazioni di utente',
|
||||||
'My default project:' => 'Il mio progetto predefinito: ',
|
'My default project:' => 'Il mio progetto predefinito:',
|
||||||
'Close a task' => 'Chiudere un compito',
|
'Close a task' => 'Chiudere un compito',
|
||||||
'Do you really want to close this task: "%s"?' => 'Veramente desidera chiudere questo compito: « %s » ?',
|
'Do you really want to close this task: "%s"?' => 'Veramente desideri chiudere questo compito: « %s » ?',
|
||||||
'Edit a task' => 'Modificare un compito',
|
'Edit a task' => 'Modificare un compito',
|
||||||
'Column' => 'colonna',
|
'Column' => 'colonna',
|
||||||
// 'Color' => '',
|
// 'Color' => '',
|
||||||
|
@ -102,7 +102,7 @@ return array(
|
||||||
'Create another task' => 'Creare un nuovo compito',
|
'Create another task' => 'Creare un nuovo compito',
|
||||||
'New task' => 'Nuovo compito',
|
'New task' => 'Nuovo compito',
|
||||||
'Open a task' => 'Aprire un compito',
|
'Open a task' => 'Aprire un compito',
|
||||||
'Do you really want to open this task: "%s"?' => 'Veramente desidera aprire questo compito: « %s » ?',
|
'Do you really want to open this task: "%s"?' => 'Veramente desideri aprire questo compito: « %s » ?',
|
||||||
'Back to the board' => 'Tornare alla bacheca',
|
'Back to the board' => 'Tornare alla bacheca',
|
||||||
// 'Created on %B %e, %Y at %k:%M %p' => '',
|
// 'Created on %B %e, %Y at %k:%M %p' => '',
|
||||||
'There is nobody assigned' => 'Non c\'è nessuno assegnato a questo compito',
|
'There is nobody assigned' => 'Non c\'è nessuno assegnato a questo compito',
|
||||||
|
@ -134,9 +134,9 @@ return array(
|
||||||
'The language is required' => 'Si richiede una lingua',
|
'The language is required' => 'Si richiede una lingua',
|
||||||
'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.',
|
'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.',
|
'Settings saved successfully.' => 'Impostazioni salvate correttamente.',
|
||||||
'Unable to save your settings.' => 'Non si possono salvare gli impostazioni.',
|
'Unable to save your settings.' => 'Non si possono salvare le impostazioni.',
|
||||||
'Database optimization done.' => 'Ottimizzazione della base dati conclusa.',
|
'Database optimization done.' => 'Ottimizzazione della base dati conclusa.',
|
||||||
'Your project have been created successfully.' => 'Il suo progetto è stato creato correttamente.',
|
'Your project have been created successfully.' => 'Il tuo progetto è stato creato correttamente.',
|
||||||
'Unable to create your project.' => 'Non si può creare il progetto.',
|
'Unable to create your project.' => 'Non si può creare il progetto.',
|
||||||
'Project updated successfully.' => 'Progetto aggiornato correttamente.',
|
'Project updated successfully.' => 'Progetto aggiornato correttamente.',
|
||||||
'Unable to update this project.' => 'Non si può aggiornare il progetto.',
|
'Unable to update this project.' => 'Non si può aggiornare il progetto.',
|
||||||
|
@ -183,7 +183,7 @@ return array(
|
||||||
'Change assignee for the task "%s"' => 'Cambiare la persona assegnata per il compito « %s »',
|
'Change assignee for the task "%s"' => 'Cambiare la persona assegnata per il compito « %s »',
|
||||||
'Timezone' => 'Fuso orario',
|
'Timezone' => 'Fuso orario',
|
||||||
'Sorry, I didn\'t found this information in my database!' => 'Mi dispiace, non ho trovato questa informazione sulla base dati!',
|
'Sorry, I didn\'t found this information in my database!' => 'Mi dispiace, non ho trovato questa informazione sulla base dati!',
|
||||||
'Page not found' => 'Página non trovata',
|
'Page not found' => 'Pagina non trovata',
|
||||||
// 'Complexity' => '',
|
// 'Complexity' => '',
|
||||||
'limit' => 'limite',
|
'limit' => 'limite',
|
||||||
'Task limit' => 'Numero massimo di compiti',
|
'Task limit' => 'Numero massimo di compiti',
|
||||||
|
@ -196,7 +196,7 @@ return array(
|
||||||
'revoke' => 'revocare',
|
'revoke' => 'revocare',
|
||||||
'List of authorized users' => 'Lista di utenti autorizzati',
|
'List of authorized users' => 'Lista di utenti autorizzati',
|
||||||
'User' => 'Utente',
|
'User' => 'Utente',
|
||||||
'Everybody have access to this project.' => 'Tutti hanno accesso a questo progetto.',
|
// 'Nobody have access to this project.' => '',
|
||||||
'You are not allowed to access to this project.' => 'Non hai l\'accesso a questo progetto.',
|
'You are not allowed to access to this project.' => 'Non hai l\'accesso a questo progetto.',
|
||||||
'Comments' => 'Commenti',
|
'Comments' => 'Commenti',
|
||||||
'Post comment' => 'Mandare commento',
|
'Post comment' => 'Mandare commento',
|
||||||
|
@ -209,8 +209,6 @@ return array(
|
||||||
'The description is required' => 'Si richiede una descrizione',
|
'The description is required' => 'Si richiede una descrizione',
|
||||||
'Edit this task' => 'Modificare questo compito',
|
'Edit this task' => 'Modificare questo compito',
|
||||||
'Due Date' => 'Data di scadenza',
|
'Due Date' => 'Data di scadenza',
|
||||||
'm/d/Y' => 'd/m/Y',
|
|
||||||
'month/day/year' => 'giorno/mese/anno',
|
|
||||||
'Invalid date' => 'Data sbagliata',
|
'Invalid date' => 'Data sbagliata',
|
||||||
// 'Must be done before %B %e, %Y' => '',
|
// 'Must be done before %B %e, %Y' => '',
|
||||||
// '%B %e, %Y' => '',
|
// '%B %e, %Y' => '',
|
||||||
|
@ -238,8 +236,8 @@ return array(
|
||||||
'Assign the task to a specific user' => 'Assegnare questo compito a un utente specifico',
|
'Assign the task to a specific user' => 'Assegnare questo compito a un utente specifico',
|
||||||
'Assign the task to the person who does the action' => 'Assegnare il compito all\'utente che svolge l\'azione',
|
'Assign the task to the person who does the action' => 'Assegnare il compito all\'utente che svolge l\'azione',
|
||||||
'Duplicate the task to another project' => 'Duplicare il compito in altro progetto',
|
'Duplicate the task to another project' => 'Duplicare il compito in altro progetto',
|
||||||
'Move a task to another column' => 'Muovere un compito ad un altra colonna',
|
'Move a task to another column' => 'Muovere un compito in un\'altra colonna',
|
||||||
'Move a task to another position in the same column' => 'Muovere un compito ad altra posizione sulla stessa colonna',
|
'Move a task to another position in the same column' => 'Muovere un compito in un\'altra posizione sulla stessa colonna',
|
||||||
'Task modification' => 'Modifica di un compito',
|
'Task modification' => 'Modifica di un compito',
|
||||||
'Task creation' => 'Creazione di un compito',
|
'Task creation' => 'Creazione di un compito',
|
||||||
'Open a closed task' => 'Riaprire un compito',
|
'Open a closed task' => 'Riaprire un compito',
|
||||||
|
@ -272,34 +270,34 @@ return array(
|
||||||
'Authentication method' => 'Metodo di autenticazzione',
|
'Authentication method' => 'Metodo di autenticazzione',
|
||||||
'IP address' => 'Indirizzo IP',
|
'IP address' => 'Indirizzo IP',
|
||||||
'User agent' => 'Navigatore',
|
'User agent' => 'Navigatore',
|
||||||
'Persistent connections' => 'Conessioni persistenti',
|
'Persistent connections' => 'Connessioni persistenti',
|
||||||
'No session.' => 'Non essiste sessione.',
|
'No session.' => 'Non esiste sessione.',
|
||||||
'Expiration date' => 'Data di scadenza',
|
'Expiration date' => 'Data di scadenza',
|
||||||
'Remember Me' => 'Riccordami',
|
'Remember Me' => 'Ricordami',
|
||||||
'Creation date' => 'Data di creazione',
|
'Creation date' => 'Data di creazione',
|
||||||
'Filter by user' => 'Filtrado mediante utente',
|
'Filter by user' => 'Filtrato mediante utente',
|
||||||
'Filter by due date' => 'Filtrare attraverso data di scadenza',
|
'Filter by due date' => 'Filtrare attraverso data di scadenza',
|
||||||
'Everybody' => 'Tutti',
|
'Everybody' => 'Tutti',
|
||||||
'Open' => 'Aperto',
|
'Open' => 'Aperto',
|
||||||
'Closed' => 'Chiuso',
|
'Closed' => 'Chiuso',
|
||||||
'Search' => 'Cercare',
|
'Search' => 'Cercare',
|
||||||
'Nothing found.' => 'Non si è trovato nulla.',
|
'Nothing found.' => 'Non si è trovato nulla.',
|
||||||
'Search in the project "%s"' => 'Cercare sul progetto "%s"',
|
'Search in the project "%s"' => 'Cercare nel progetto "%s"',
|
||||||
'Due date' => 'Data di scadenza',
|
'Due date' => 'Data di scadenza',
|
||||||
'Others formats accepted: %s and %s' => 'Altri formati accettati: %s y %s',
|
'Others formats accepted: %s and %s' => 'Altri formati accettati: %s y %s',
|
||||||
'Description' => 'Descrizione',
|
'Description' => 'Descrizione',
|
||||||
'%d comments' => '%d commenti',
|
'%d comments' => '%d commenti',
|
||||||
'%d comment' => '%d commento',
|
'%d comment' => '%d commento',
|
||||||
'Email address invalid' => 'Indirizzo e-mail sbagliato',
|
'Email address invalid' => 'Indirizzo e-mail sbagliato',
|
||||||
'Your Google Account is not linked anymore to your profile.' => 'Il suo account Google non i più collegato col suo profilo',
|
'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.',
|
'Unable to unlink your Google Account.' => 'Non si può svincolare l\'account di Google.',
|
||||||
'Google authentication failed' => 'Non si è riuscito ad ingressare su Google',
|
'Google authentication failed' => 'Autenticazione con Google non riuscita',
|
||||||
'Unable to link your Google Account.' => 'Non si può collegare con il suo account di Google.',
|
'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 suo account di Google è stato collegato correttamente al suo profilo.',
|
'Your Google Account is linked to your profile successfully.' => 'Il tuo account di Google è stato collegato correttamente al tuo profilo.',
|
||||||
'Email' => 'E-mail',
|
'Email' => 'E-mail',
|
||||||
'Link my Google Account' => 'Collegare con il mio Account di Google',
|
'Link my Google Account' => 'Collegare il mio Account di Google',
|
||||||
'Unlink my Google Account' => 'Svincolare con il mio account di Google',
|
'Unlink my Google Account' => 'Scollegare il mio account di Google',
|
||||||
'Login with my Google Account' => 'Ingressa con il mio Account di Google',
|
'Login with my Google Account' => 'Entra con il mio Account di Google',
|
||||||
'Project not found.' => 'progetto non trovato.',
|
'Project not found.' => 'progetto non trovato.',
|
||||||
'Task #%d' => 'Compito numero %d',
|
'Task #%d' => 'Compito numero %d',
|
||||||
'Task removed successfully.' => 'Compito cancellato correttamente.',
|
'Task removed successfully.' => 'Compito cancellato correttamente.',
|
||||||
|
@ -308,15 +306,15 @@ return array(
|
||||||
'Do you really want to remove this task: "%s"?' => 'Veramente vuoi cancellare questo compito: "%s"?',
|
'Do you really want to remove this task: "%s"?' => 'Veramente vuoi cancellare questo compito: "%s"?',
|
||||||
'Assign automatically a color based on a category' => 'Assegnare un colore in modo automatico basandosi sulla categoria',
|
'Assign automatically a color based on a category' => 'Assegnare un colore in modo automatico basandosi sulla categoria',
|
||||||
'Assign automatically a category based on a color' => 'Assegnare una categoria in modo automatico basandosi sul colore',
|
'Assign automatically a category based on a color' => 'Assegnare una categoria in modo automatico basandosi sul colore',
|
||||||
'Task creation or modification' => 'Creazione o Modifica di compito',
|
'Task creation or modification' => 'Creazione o modifica di compito',
|
||||||
'Category' => 'Categoria',
|
'Category' => 'Categoria',
|
||||||
'Category:' => 'Categoria:',
|
'Category:' => 'Categoria:',
|
||||||
'Categories' => 'Categorie',
|
'Categories' => 'Categorie',
|
||||||
'Category not found.' => 'Categoria non trovata.',
|
'Category not found.' => 'Categoria non trovata.',
|
||||||
'Your category have been created successfully.' => 'La sua categoria è stata creata correttamente.',
|
'Your category have been created successfully.' => 'La tua categoria è stata creata correttamente.',
|
||||||
'Unable to create your category.' => 'Non si può creare la sua categoria.',
|
'Unable to create your category.' => 'Non si può creare la tua categoria.',
|
||||||
'Your category have been updated successfully.' => 'La sua categoria è stata aggiornata correttamente.',
|
'Your category have been updated successfully.' => 'La tua categoria è stata aggiornata correttamente.',
|
||||||
'Unable to update your category.' => 'Non si può aggiornare la sua categoria.',
|
'Unable to update your category.' => 'Non si può aggiornare la tua categoria.',
|
||||||
'Remove a category' => 'Cancellare una categoria',
|
'Remove a category' => 'Cancellare una categoria',
|
||||||
'Category removed successfully.' => 'Categoria cancellata correttamente.',
|
'Category removed successfully.' => 'Categoria cancellata correttamente.',
|
||||||
'Unable to remove this category.' => 'Non si può cancellare questa categoria.',
|
'Unable to remove this category.' => 'Non si può cancellare questa categoria.',
|
||||||
|
@ -344,45 +342,45 @@ return array(
|
||||||
'Time tracking' => 'Time tracking',
|
'Time tracking' => 'Time tracking',
|
||||||
'Estimate:' => 'Stimato:',
|
'Estimate:' => 'Stimato:',
|
||||||
'Spent:' => 'Trascorso:',
|
'Spent:' => 'Trascorso:',
|
||||||
'Do you really want to remove this sub-task?' => 'Vuoi veramente cancellare questo sub-compito?',
|
'Do you really want to remove this sub-task?' => 'Vuoi veramente cancellare questo sotto-compito?',
|
||||||
'Remaining:' => 'Rimangono',
|
'Remaining:' => 'Rimangono',
|
||||||
'hours' => 'ore',
|
'hours' => 'ore',
|
||||||
'spent' => 'trascorse',
|
'spent' => 'trascorse',
|
||||||
'estimated' => 'stimate',
|
'estimated' => 'stimate',
|
||||||
'Sub-Tasks' => 'Sub-Compiti',
|
'Sub-Tasks' => 'Sotto-compiti',
|
||||||
'Add a sub-task' => 'Aggiungere un sub-compito',
|
'Add a sub-task' => 'Aggiungere un sotto-compito',
|
||||||
'Original Estimate' => 'Stima originale',
|
'Original estimate' => 'Stima originale',
|
||||||
'Create another sub-task' => 'Crear un altro sub-compito',
|
'Create another sub-task' => 'Creare un altro sotto-compito',
|
||||||
'Time Spent' => 'Tempo Trascorso',
|
'Time spent' => 'Tempo Trascorso',
|
||||||
'Edit a sub-task' => 'Modificare un sub-compito',
|
'Edit a sub-task' => 'Modificare un sotto-compito',
|
||||||
'Remove a sub-task' => 'Cancellare un sub-compito',
|
'Remove a sub-task' => 'Cancellare un sotto-compito',
|
||||||
'The time must be a numeric value' => 'Il tempo deve essere un valore numerico',
|
'The time must be a numeric value' => 'Il tempo deve essere un valore numerico',
|
||||||
'Todo' => 'Da fare',
|
'Todo' => 'Da fare',
|
||||||
'In progress' => 'In corso',
|
'In progress' => 'In corso',
|
||||||
'Sub-task removed successfully.' => 'Sub-compito cancellato correttamente.',
|
'Sub-task removed successfully.' => 'Sotto-compito cancellato correttamente.',
|
||||||
'Unable to remove this sub-task.' => 'Non si può cancellare questo sub-compito.',
|
'Unable to remove this sub-task.' => 'Non si può cancellare questo sotto-compito.',
|
||||||
'Sub-task updated successfully.' => 'Sub-compito aggiornato correttamente.',
|
'Sub-task updated successfully.' => 'Sotto-compito aggiornato correttamente.',
|
||||||
'Unable to update your sub-task.' => 'Non si può aggiornare il suo sub-compito.',
|
'Unable to update your sub-task.' => 'Non si può aggiornare il tuo sotto-compito.',
|
||||||
'Unable to create your sub-task.' => 'Non si può creare il suo sub-compito.',
|
'Unable to create your sub-task.' => 'Non si può creare il tuo sotto-compito.',
|
||||||
'Sub-task added successfully.' => 'Sub-compito aggiunto correttamente.',
|
'Sub-task added successfully.' => 'Sotto-compito aggiunto correttamente.',
|
||||||
'Maximum size: ' => 'Dimensioni massime',
|
'Maximum size: ' => 'Dimensioni massime',
|
||||||
'Unable to upload the file.' => 'Non si può caricare il file.',
|
'Unable to upload the file.' => 'Non si può caricare il file.',
|
||||||
'Display another project' => 'Mostrare un altro progetto',
|
'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 suo profilo.',
|
'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 col suo account di Github.',
|
'Unable to link your GitHub Account.' => 'Non si può collegarre il tuo account di Github.',
|
||||||
'GitHub authentication failed' => 'L\'autenticazione non è stata possibile',
|
'GitHub authentication failed' => 'Autenticazione con GitHub non riuscita',
|
||||||
'Your GitHub account is no longer linked to your profile.' => 'Il suo account di Github non è più vincolato al suo profilo.',
|
'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ò svincolare il suo account di Github.',
|
'Unable to unlink your GitHub Account.' => 'Non si può collegare il tuo account di Github.',
|
||||||
'Login with my GitHub Account' => 'Ingressare col suo account di Github',
|
'Login with my GitHub Account' => 'Entrare col tuo account di Github',
|
||||||
'Link my GitHub Account' => 'Lier mon compte Github',
|
'Link my GitHub Account' => 'Collegare il mio account Github',
|
||||||
'Unlink my GitHub Account' => 'Non impiegare più l\'account di Github',
|
'Unlink my GitHub Account' => 'Scollegare il mio account di Github',
|
||||||
'Created by %s' => 'Creato da %s',
|
'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',
|
'Last modified on %B %e, %Y at %k:%M %p' => 'Ultima modifica il %d/%m/%Y alle %H:%M',
|
||||||
'Tasks Export' => 'Esportazione di compiti',
|
'Tasks Export' => 'Esportazione di compiti',
|
||||||
'Tasks exportation for "%s"' => 'Esportazione di compiti per « %s »',
|
'Tasks exportation for "%s"' => 'Esportazione di compiti per « %s »',
|
||||||
'Start Date' => 'Data d\'inizio',
|
'Start Date' => 'Data d\'inizio',
|
||||||
'End Date' => 'Data di fine',
|
'End Date' => 'Data di fine',
|
||||||
'Execute' => 'Essecutare',
|
'Execute' => 'Eseguire',
|
||||||
'Task Id' => 'Identificatore del compito',
|
'Task Id' => 'Identificatore del compito',
|
||||||
'Creator' => 'Creatore',
|
'Creator' => 'Creatore',
|
||||||
'Modification date' => 'Data di modifica',
|
'Modification date' => 'Data di modifica',
|
||||||
|
@ -411,19 +409,19 @@ return array(
|
||||||
'[%s][New attachment] %s (#%d)' => '[%s][Nuovo allegato] %s (#%d)',
|
'[%s][New attachment] %s (#%d)' => '[%s][Nuovo allegato] %s (#%d)',
|
||||||
'[%s][New comment] %s (#%d)' => '[%s][Nuovo commento] %s (#%d)',
|
'[%s][New comment] %s (#%d)' => '[%s][Nuovo commento] %s (#%d)',
|
||||||
'[%s][Comment updated] %s (#%d)' => '[%s][Commento aggiornato] %s (#%d)',
|
'[%s][Comment updated] %s (#%d)' => '[%s][Commento aggiornato] %s (#%d)',
|
||||||
'[%s][New subtask] %s (#%d)' => '[%s][Nuovo sub-compito] %s (#%d)',
|
'[%s][New subtask] %s (#%d)' => '[%s][Nuovo sotto-compito] %s (#%d)',
|
||||||
'[%s][Subtask updated] %s (#%d)' => '[%s][Sub-compito aggiornato] %s (#%d)',
|
'[%s][Subtask updated] %s (#%d)' => '[%s][Sotto-compito aggiornato] %s (#%d)',
|
||||||
'[%s][New task] %s (#%d)' => '[%s][Nuovo compito] %s (#%d)',
|
'[%s][New task] %s (#%d)' => '[%s][Nuovo compito] %s (#%d)',
|
||||||
'[%s][Task updated] %s (#%d)' => '[%s][Compito aggiornato] %s (#%d)',
|
'[%s][Task updated] %s (#%d)' => '[%s][Compito aggiornato] %s (#%d)',
|
||||||
'[%s][Task closed] %s (#%d)' => '[%s][Compito chiuso] %s (#%d)',
|
'[%s][Task closed] %s (#%d)' => '[%s][Compito chiuso] %s (#%d)',
|
||||||
'[%s][Task opened] %s (#%d)' => '[%s][Compito aperto] %s (#%d)',
|
'[%s][Task opened] %s (#%d)' => '[%s][Compito aperto] %s (#%d)',
|
||||||
'[%s][Due tasks]' => '[%s][Compiti scaduti]',
|
'[%s][Due tasks]' => '[%s][Compiti scaduti]',
|
||||||
'[Kanboard] Notification' => '[Kanboard] Notification',
|
'[Kanboard] Notification' => '[Kanboard] Notifica',
|
||||||
'I want to receive notifications only for those projects:' => 'Vorrei ricevere le notifiche solo da questi progetti:',
|
'I want to receive notifications only for those projects:' => 'Vorrei ricevere le notifiche solo da questi progetti:',
|
||||||
'view the task on Kanboard' => 'vedi il compito su Kanboard',
|
'view the task on Kanboard' => 'vedi il compito su Kanboard',
|
||||||
// 'Public access' => '',
|
// 'Public access' => '',
|
||||||
// 'Categories management' => '',
|
// 'Category management' => '',
|
||||||
// 'Users management' => '',
|
// 'User management' => '',
|
||||||
// 'Active tasks' => '',
|
// 'Active tasks' => '',
|
||||||
// 'Disable public access' => '',
|
// 'Disable public access' => '',
|
||||||
// 'Enable public access' => '',
|
// 'Enable public access' => '',
|
||||||
|
@ -451,6 +449,7 @@ return array(
|
||||||
// 'Email:' => '',
|
// 'Email:' => '',
|
||||||
// 'Default project:' => '',
|
// 'Default project:' => '',
|
||||||
// 'Notifications:' => '',
|
// 'Notifications:' => '',
|
||||||
|
// 'Notifications' => '',
|
||||||
// 'Group:' => '',
|
// 'Group:' => '',
|
||||||
// 'Regular user' => '',
|
// 'Regular user' => '',
|
||||||
// 'Account type:' => '',
|
// 'Account type:' => '',
|
||||||
|
@ -497,10 +496,66 @@ return array(
|
||||||
// 'Default values are "%s"' => '',
|
// 'Default values are "%s"' => '',
|
||||||
// 'Default columns for new projects (Comma-separated)' => '',
|
// 'Default columns for new projects (Comma-separated)' => '',
|
||||||
// 'Task assignee change' => '',
|
// 'Task assignee change' => '',
|
||||||
// '%s change the assignee of the task #%d' => '',
|
// '%s change the assignee of the task #%d to %s' => '',
|
||||||
// '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '',
|
// '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to %s' => '',
|
||||||
// '[%s][Column Change] %s (#%d)' => '',
|
// '[%s][Column Change] %s (#%d)' => '',
|
||||||
// '[%s][Position Change] %s (#%d)' => '',
|
// '[%s][Position Change] %s (#%d)' => '',
|
||||||
// '[%s][Assignee Change] %s (#%d)' => '',
|
// '[%s][Assignee Change] %s (#%d)' => '',
|
||||||
// 'New password for the user "%s"' => '',
|
// 'New password for the user "%s"' => '',
|
||||||
|
// 'Choose an event' => '',
|
||||||
|
// 'Github commit received' => '',
|
||||||
|
// 'Github issue opened' => '',
|
||||||
|
// 'Github issue closed' => '',
|
||||||
|
// 'Github issue reopened' => '',
|
||||||
|
// 'Github issue assignee change' => '',
|
||||||
|
// 'Github issue label change' => '',
|
||||||
|
// 'Create a task from an external provider' => '',
|
||||||
|
// 'Change the assignee based on an external username' => '',
|
||||||
|
// 'Change the category based on an external label' => '',
|
||||||
|
// 'Reference' => '',
|
||||||
|
// 'Reference: %s' => '',
|
||||||
|
// 'Label' => '',
|
||||||
|
// 'Database' => '',
|
||||||
|
// 'About' => '',
|
||||||
|
// 'Database driver:' => '',
|
||||||
|
// 'Board settings' => '',
|
||||||
|
// 'URL and token' => '',
|
||||||
|
// 'Webhook settings' => '',
|
||||||
|
// 'URL for task creation:' => '',
|
||||||
|
// 'Reset token' => '',
|
||||||
|
// 'API endpoint:' => '',
|
||||||
|
// 'Refresh interval for private board' => '',
|
||||||
|
// 'Refresh interval for public board' => '',
|
||||||
|
// 'Task highlight period' => '',
|
||||||
|
// 'Period (in second) to consider a task was modified recently (0 to disable, 2 days by default)' => '',
|
||||||
|
// 'Frequency in second (60 seconds by default)' => '',
|
||||||
|
// 'Frequency in second (0 to disable this feature, 10 seconds by default)' => '',
|
||||||
|
// 'Application URL' => '',
|
||||||
|
// 'Example: http://example.kanboard.net/ (used by email notifications)' => '',
|
||||||
|
// 'Token regenerated.' => '',
|
||||||
|
// 'Date format' => '',
|
||||||
|
// 'ISO format is always accepted, example: "%s" and "%s"' => '',
|
||||||
|
// 'New private project' => '',
|
||||||
|
// 'This project is private' => '',
|
||||||
|
// 'Type here to create a new sub-task' => '',
|
||||||
|
// 'Add' => '',
|
||||||
|
// 'Estimated time: %s hours' => '',
|
||||||
|
// 'Time spent: %s hours' => '',
|
||||||
|
// 'Started on %B %e, %Y' => '',
|
||||||
|
// 'Start date' => '',
|
||||||
|
// 'Time estimated' => '',
|
||||||
|
// 'There is nothing assigned to you.' => '',
|
||||||
|
// 'My tasks' => '',
|
||||||
|
// 'Activity stream' => '',
|
||||||
|
// 'Dashboard' => '',
|
||||||
|
// 'Confirmation' => '',
|
||||||
|
// 'Allow everybody to access to this project' => '',
|
||||||
|
// 'Everybody have access to this project.' => '',
|
||||||
|
// 'Webhooks' => '',
|
||||||
|
// 'API' => '',
|
||||||
|
// 'Integration' => '',
|
||||||
|
// 'Github webhook' => '',
|
||||||
|
// 'Help on Github webhook' => '',
|
||||||
|
// 'Create a comment from an external provider' => '',
|
||||||
|
// 'Github issue comment created' => '',
|
||||||
);
|
);
|
561
sources/app/Locale/ja_JP/translations.php
Normal file
561
sources/app/Locale/ja_JP/translations.php
Normal file
|
@ -0,0 +1,561 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'None' => 'なし',
|
||||||
|
'edit' => '変更',
|
||||||
|
'Edit' => '変更',
|
||||||
|
'remove' => '削除する',
|
||||||
|
'Remove' => '削除する',
|
||||||
|
'Update' => '変更',
|
||||||
|
'Yes' => 'はい',
|
||||||
|
'No' => 'いいえ',
|
||||||
|
'cancel' => 'キャンセル',
|
||||||
|
'or' => 'または',
|
||||||
|
'Yellow' => 'イエロー',
|
||||||
|
'Blue' => 'ブルー',
|
||||||
|
'Green' => 'グリーン',
|
||||||
|
'Purple' => 'パープル',
|
||||||
|
'Red' => 'レッド',
|
||||||
|
'Orange' => 'オレンジ',
|
||||||
|
'Grey' => 'グレー',
|
||||||
|
'Save' => '保存',
|
||||||
|
'Login' => 'ログイン',
|
||||||
|
'Official website:' => '公式 Web サイト:',
|
||||||
|
'Unassigned' => '担当なし',
|
||||||
|
'View this task' => 'このタクスを見る',
|
||||||
|
'Remove user' => 'ユーザの削除',
|
||||||
|
'Do you really want to remove this user: "%s"?' => 'ユーザ「%s」を本当に削除しますか?',
|
||||||
|
'New user' => 'ユーザを追加する',
|
||||||
|
'All users' => 'すべてのユーザ',
|
||||||
|
'Username' => 'ユーザ名',
|
||||||
|
'Password' => 'パスワード',
|
||||||
|
'Default project' => 'デフォルトプロジェクト',
|
||||||
|
'Administrator' => '管理者',
|
||||||
|
'Sign in' => 'ログイン',
|
||||||
|
'Users' => 'ユーザ',
|
||||||
|
'No user' => 'ユーザがいません',
|
||||||
|
'Forbidden' => 'アクセス拒否',
|
||||||
|
'Access Forbidden' => 'アクセスが拒否されました',
|
||||||
|
'Only administrators can access to this page.' => '管理者のみがこのページにアクセスできます。',
|
||||||
|
'Edit user' => 'ユーザを変更する',
|
||||||
|
'Logout' => 'ログアウト',
|
||||||
|
'Bad username or password' => 'ユーザ名またはパスワードが違います。',
|
||||||
|
'users' => 'ユーザ',
|
||||||
|
'projects' => 'プロジェクト',
|
||||||
|
'Edit project' => 'プロジェクトを変更する',
|
||||||
|
'Name' => '名前',
|
||||||
|
'Activated' => '有効',
|
||||||
|
'Projects' => 'プロジェクト',
|
||||||
|
'No project' => 'プロジェクトがありません',
|
||||||
|
'Project' => 'プロジェクト',
|
||||||
|
'Status' => 'ステータス',
|
||||||
|
'Tasks' => 'タスク',
|
||||||
|
'Board' => 'ボード',
|
||||||
|
'Actions' => 'アクション',
|
||||||
|
'Inactive' => '無効',
|
||||||
|
'Active' => '有効',
|
||||||
|
'Column %d' => 'カラム %d',
|
||||||
|
'Add this column' => 'カラムを追加する',
|
||||||
|
'%d tasks on the board' => '%d 個のタスク',
|
||||||
|
'%d tasks in total' => '合計 %d 個のタスク',
|
||||||
|
'Unable to update this board.' => 'ボードを更新できませんでした',
|
||||||
|
'Edit board' => 'ボードを変更する',
|
||||||
|
'Disable' => '無効にする',
|
||||||
|
'Enable' => '有効にする',
|
||||||
|
'New project' => 'プロジェクトを作る',
|
||||||
|
'Do you really want to remove this project: "%s"?' => 'プロジェクト「%s」を本当に削除しますか?',
|
||||||
|
'Remove project' => 'プロジェクトの削除',
|
||||||
|
'Boards' => 'ボード',
|
||||||
|
'Edit the board for "%s"' => 'ボード「%s」を変更する',
|
||||||
|
'All projects' => 'すべてのプロジェクト',
|
||||||
|
'Change columns' => 'カラムの変更',
|
||||||
|
'Add a new column' => 'カラムの追加',
|
||||||
|
'Title' => 'タイトル',
|
||||||
|
'Add Column' => 'カラムの追加',
|
||||||
|
'Project "%s"' => 'プロジェクト「%s」',
|
||||||
|
'Nobody assigned' => '担当なし',
|
||||||
|
'Assigned to %s' => '%sが担当',
|
||||||
|
'Remove a column' => 'カラムの削除',
|
||||||
|
'Remove a column from a board' => 'ボードからカラムの削除',
|
||||||
|
'Unable to remove this column.' => 'カラムを削除できませんでした。',
|
||||||
|
'Do you really want to remove this column: "%s"?' => 'カラム「%s」を削除しますか?',
|
||||||
|
'This action will REMOVE ALL TASKS associated to this column!' => 'この操作はこのカラムに割当てられた『全てのタスクを削除』します!',
|
||||||
|
'Settings' => '設定',
|
||||||
|
'Application settings' => 'アプリケーションの設定',
|
||||||
|
'Language' => '言語',
|
||||||
|
'Webhook token:' => 'Webhook トークン:',
|
||||||
|
'API token:' => 'API トークン:',
|
||||||
|
'More information' => '詳細',
|
||||||
|
'Database size:' => 'データベースのサイズ:',
|
||||||
|
'Download the database' => 'データベースのダウンロード',
|
||||||
|
'Optimize the database' => 'データベースの最適化',
|
||||||
|
'(VACUUM command)' => '(VACUUM コマンド)',
|
||||||
|
'(Gzip compressed Sqlite file)' => '(GZip コマンドで圧縮された Sqlite ファイル)',
|
||||||
|
'User settings' => 'ユーザ設定',
|
||||||
|
'My default project:' => '自分のデフォルトプロジェクト:',
|
||||||
|
'Close a task' => 'タスクをクロースする',
|
||||||
|
'Do you really want to close this task: "%s"?' => 'タスク「%s」をクローズしますか?',
|
||||||
|
'Edit a task' => 'タスクを変更する',
|
||||||
|
'Column' => 'カラム',
|
||||||
|
'Color' => '色',
|
||||||
|
'Assignee' => '担当',
|
||||||
|
'Create another task' => '続けて別のタスクを追加する',
|
||||||
|
'New task' => 'タスクを追加する',
|
||||||
|
'Open a task' => 'タスクをオープンする',
|
||||||
|
'Do you really want to open this task: "%s"?' => 'タスク「%s」をオープンしますか?',
|
||||||
|
'Back to the board' => 'ボードに戻る',
|
||||||
|
'Created on %B %e, %Y at %k:%M %p' => '%Y/%m/%d %H:%M に作成',
|
||||||
|
'There is nobody assigned' => '担当者がいません',
|
||||||
|
'Column on the board:' => 'カラム: ',
|
||||||
|
'Status is open' => 'ステータスはオープンです',
|
||||||
|
'Status is closed' => 'ステータスはクローズです',
|
||||||
|
'Close this task' => 'タスクをクローズする',
|
||||||
|
'Open this task' => 'タスクをオープンする',
|
||||||
|
'There is no description.' => '説明がありません',
|
||||||
|
'Add a new task' => 'タスクを追加する',
|
||||||
|
'The username is required' => 'ユーザ名が必要です',
|
||||||
|
'The maximum length is %d characters' => '最大 %d 文字です',
|
||||||
|
'The minimum length is %d characters' => '最小 %d 文字必要です',
|
||||||
|
'The password is required' => 'パスワードが必要です',
|
||||||
|
'This value must be an integer' => '整数で入力してください',
|
||||||
|
'The username must be unique' => 'ユーザ名がすでに使用されています',
|
||||||
|
'The username must be alphanumeric' => 'ユーザ名は英数字で入力してください',
|
||||||
|
'The user id is required' => 'ユーザ ID が必要です',
|
||||||
|
'Passwords don\'t match' => 'パスワードが一致しません',
|
||||||
|
'The confirmation is required' => '確認用のパスワードを入力してください',
|
||||||
|
'The column is required' => 'カラムが必要です',
|
||||||
|
'The project is required' => 'プロジェクトが必要です',
|
||||||
|
'The color is required' => '色が必要です',
|
||||||
|
'The id is required' => 'ID が必要です',
|
||||||
|
'The project id is required' => 'プロジェクト ID が必要です',
|
||||||
|
'The project name is required' => 'プロジェクト名が必要です',
|
||||||
|
'This project must be unique' => 'プロジェクト名がすでに使われています',
|
||||||
|
'The title is required' => 'タイトルが必要です',
|
||||||
|
'The language 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.' => 'データベースの最適化が終わりました。',
|
||||||
|
'Your project have been created successfully.' => 'プロジェクトを作成しました。',
|
||||||
|
'Unable to create your project.' => 'プロジェクトの作成に失敗しました。',
|
||||||
|
'Project updated successfully.' => 'プロジェクトを更新しました。',
|
||||||
|
'Unable to update this project.' => 'プロジェクトの更新に失敗しました。',
|
||||||
|
'Unable to remove this project.' => 'プロジェクトの削除に失敗しました。',
|
||||||
|
'Project removed successfully.' => 'プロジェクトを削除しました。',
|
||||||
|
'Project activated successfully.' => 'プロジェクトを有効にしました。',
|
||||||
|
'Unable to activate this project.' => 'プロジェクトの有効にできませんでした。',
|
||||||
|
'Project disabled successfully.' => 'プロジェクトを無効にしました。',
|
||||||
|
'Unable to disable this project.' => 'プロジェクトの無効にできませんでした。',
|
||||||
|
'Unable to open this task.' => 'タスクのオープンに失敗しました。',
|
||||||
|
'Task opened successfully.' => 'タスクをオープンしました。',
|
||||||
|
'Unable to close this task.' => 'タスクのクローズに失敗しました。',
|
||||||
|
'Task closed successfully.' => 'タスクをクローズしました。',
|
||||||
|
'Unable to update your task.' => 'タスクの更新に失敗しました。',
|
||||||
|
'Task updated successfully.' => 'タスクを更新しました。',
|
||||||
|
'Unable to create your task.' => 'タスクの追加に失敗しました。',
|
||||||
|
'Task created successfully.' => 'タスクを追加しました。',
|
||||||
|
'User created successfully.' => 'ユーザを追加しました。',
|
||||||
|
'Unable to create your user.' => 'ユーザの追加に失敗しました。',
|
||||||
|
'User updated successfully.' => 'ユーザを更新しました。',
|
||||||
|
'Unable to update your user.' => 'ユーザの更新に失敗しました。',
|
||||||
|
'User removed successfully.' => 'ユーザを削除しました。',
|
||||||
|
'Unable to remove this user.' => 'ユーザの削除に失敗しました。',
|
||||||
|
'Board updated successfully.' => 'ボードを更新しました。',
|
||||||
|
'Ready' => 'Ready',
|
||||||
|
'Backlog' => 'Backlog',
|
||||||
|
'Work in progress' => 'Work in progress',
|
||||||
|
'Done' => 'Done',
|
||||||
|
'Application version:' => 'アプリケーションのバージョン:',
|
||||||
|
'Completed on %B %e, %Y at %k:%M %p' => '%Y/%m/%d %H:%M に完了',
|
||||||
|
'%B %e, %Y at %k:%M %p' => '%Y/%m/%d %H:%M',
|
||||||
|
'Date created' => '作成日',
|
||||||
|
'Date completed' => '完了日',
|
||||||
|
'Id' => 'ID',
|
||||||
|
'No task' => 'タスクなし',
|
||||||
|
'Completed tasks' => '完了したタスク',
|
||||||
|
'List of projects' => 'プロジェクトの一覧',
|
||||||
|
'Completed tasks for "%s"' => '「%s」の完了したタスク',
|
||||||
|
'%d closed tasks' => '%d 個のクローズしたタスク',
|
||||||
|
'No task for this project' => 'このプロジェクトにタスクがありません',
|
||||||
|
'Public link' => '公開アクセス用リンク',
|
||||||
|
'There is no column in your project!' => 'カラムにプロジェクトがありません!',
|
||||||
|
'Change assignee' => '担当を変更する',
|
||||||
|
'Change assignee for the task "%s"' => 'タスク「%s」の担当を変更する',
|
||||||
|
'Timezone' => 'タイムゾーン',
|
||||||
|
'Sorry, I didn\'t found this information in my database!' => 'データベース上で情報が見つかりませんでした!',
|
||||||
|
'Page not found' => 'ページが見つかりません',
|
||||||
|
'Complexity' => '複雑さ',
|
||||||
|
'limit' => '制限',
|
||||||
|
'Task limit' => 'タスク数制限',
|
||||||
|
'This value must be greater than %d' => '%d より大きな値を入力してください',
|
||||||
|
'Edit project access list' => 'プロジェクトのアクセス許可を変更',
|
||||||
|
'Edit users access' => 'ユーザのアクセス許可を変更',
|
||||||
|
'Allow this user' => 'このユーザを許可する',
|
||||||
|
'Only those users have access to this project:' => 'これらのユーザのみがプロジェクトにアクセスできます:',
|
||||||
|
'Don\'t forget that administrators have access to everything.' => '管理者には全ての権限が与えられます。',
|
||||||
|
'revoke' => '許可を取り下げる',
|
||||||
|
'List of authorized users' => '許可されたユーザ',
|
||||||
|
'User' => 'ユーザ',
|
||||||
|
'Nobody have access to this project.' => 'だれもプロジェクトにアクセスできません。',
|
||||||
|
'You are not allowed to access to this project.' => 'プロジェクトへのアクセスが許可されていません。',
|
||||||
|
'Comments' => 'コメント',
|
||||||
|
'Post comment' => 'コメントを書く',
|
||||||
|
'Write your text in Markdown' => 'Markdown 記法で書く',
|
||||||
|
'Leave a comment' => 'コメントを書く',
|
||||||
|
'Comment is required' => 'コメントを入力してください',
|
||||||
|
'Leave a description' => '説明を書く',
|
||||||
|
'Comment added successfully.' => 'コメントを追加しました。',
|
||||||
|
'Unable to create your comment.' => 'コメントの追加に失敗しました。',
|
||||||
|
'The description is required' => '説明を入力してください',
|
||||||
|
'Edit this task' => 'タスクを変更する',
|
||||||
|
'Due Date' => '期限',
|
||||||
|
'Invalid date' => '日付が無効です',
|
||||||
|
'Must be done before %B %e, %Y' => '%Y/%m/%d までに完了',
|
||||||
|
'%B %e, %Y' => '%d %B %Y',
|
||||||
|
'Automatic actions' => '自動アクションを管理する',
|
||||||
|
'Your automatic action have been created successfully.' => '自動アクションを作成しました。',
|
||||||
|
'Unable to create your automatic action.' => '自動アクションの作成に失敗しました。',
|
||||||
|
'Remove an action' => '自動アクションの削除',
|
||||||
|
'Unable to remove this action.' => '自動アクションの削除に失敗しました。',
|
||||||
|
'Action removed successfully.' => '自動アクションの削除に成功しました。',
|
||||||
|
'Automatic actions for the project "%s"' => 'プロジェクト「%s」の自動アクション',
|
||||||
|
'Defined actions' => '定義された自動アクション',
|
||||||
|
'Add an action' => '自動アクションの追加',
|
||||||
|
'Event name' => 'イベント名',
|
||||||
|
'Action name' => 'アクション名',
|
||||||
|
'Action parameters' => 'アクションのパラメーター',
|
||||||
|
'Action' => 'アクション',
|
||||||
|
'Event' => 'イベント',
|
||||||
|
'When the selected event occurs execute the corresponding action.' => '選択されたイベントが発生した時、対応するアクションを実行する。',
|
||||||
|
'Next step' => '次のステップ',
|
||||||
|
'Define action parameters' => 'アクションのパラメーター',
|
||||||
|
'Save this action' => 'このアクションを保存する',
|
||||||
|
'Do you really want to remove this action: "%s"?' => '自動アクション「%s」を削除しますか?',
|
||||||
|
'Remove an automatic action' => '自動アクションの削除',
|
||||||
|
'Close the task' => 'タスクのクローズ',
|
||||||
|
'Assign the task to a specific user' => 'タスクの担当者を割り当てる',
|
||||||
|
'Assign the task to the person who does the action' => 'アクションを起こしたユーザを担当者にする',
|
||||||
|
'Duplicate the task to another project' => '別のプロジェクトにタスクを複製する',
|
||||||
|
'Move a task to another column' => 'タスクを別のカラムに移動する',
|
||||||
|
'Move a task to another position in the same column' => 'カラム上でのタスクの順序を変える',
|
||||||
|
'Task modification' => 'タスクの変更',
|
||||||
|
'Task creation' => 'タスクを作る',
|
||||||
|
'Open a closed task' => 'タスクを再オープンする',
|
||||||
|
'Closing a task' => 'タスクをクローズする',
|
||||||
|
'Assign a color to a specific user' => '色をユーザに割り当てる',
|
||||||
|
'Column title' => 'カラムのタイトル',
|
||||||
|
'Position' => '位置',
|
||||||
|
'Move Up' => '上に動かす',
|
||||||
|
'Move Down' => '下に動かす',
|
||||||
|
'Duplicate to another project' => '別のプロジェクトに複製する',
|
||||||
|
'Duplicate' => '複製する',
|
||||||
|
'link' => 'リンク',
|
||||||
|
'Update this comment' => 'コメントを更新する',
|
||||||
|
'Comment updated successfully.' => 'コメントを更新しました。',
|
||||||
|
'Unable to update your comment.' => 'コメントの更新に失敗しました。',
|
||||||
|
'Remove a comment' => 'コメントを削除する',
|
||||||
|
'Comment removed successfully.' => 'コメントを削除しました。',
|
||||||
|
'Unable to remove this comment.' => 'コメントの削除に失敗しました。',
|
||||||
|
'Do you really want to remove this comment?' => 'コメントを削除しますか?',
|
||||||
|
'Only administrators or the creator of the comment can access to this page.' => '管理者かコメントの作成者のみがこのページアクセスできます。',
|
||||||
|
'Details' => '詳細',
|
||||||
|
'Current password for the user "%s"' => 'ユーザ「%s」の現在のパスワード',
|
||||||
|
'The current password is required' => '現在のパスワードを入力してください',
|
||||||
|
'Wrong password' => 'パスワードが違います',
|
||||||
|
'Reset all tokens' => '全てのトークンを再生成する',
|
||||||
|
'All tokens have been regenerated.' => '全てのトークンが再生成されました',
|
||||||
|
'Unknown' => '不明',
|
||||||
|
'Last logins' => 'ログインの一覧',
|
||||||
|
'Login date' => 'ログイン日時',
|
||||||
|
'Authentication method' => '認証方法',
|
||||||
|
'IP address' => 'IP アドレス',
|
||||||
|
'User agent' => 'ユーザエージェント',
|
||||||
|
'Persistent connections' => '既存のコネクション',
|
||||||
|
'No session.' => 'セッションなし。',
|
||||||
|
'Expiration date' => '有効期限',
|
||||||
|
'Remember Me' => '次回から自動的にログインする',
|
||||||
|
'Creation date' => '作成日',
|
||||||
|
'Filter by user' => 'ユーザでフィルタリング',
|
||||||
|
'Filter by due date' => '期限でフィルタリング',
|
||||||
|
'Everybody' => '全員',
|
||||||
|
'Open' => 'オープン',
|
||||||
|
'Closed' => 'クローズ',
|
||||||
|
'Search' => '検索',
|
||||||
|
'Nothing found.' => '結果なし。',
|
||||||
|
'Search in the project "%s"' => 'プロジェクト「%s」で検索',
|
||||||
|
'Due date' => '期限',
|
||||||
|
'Others formats accepted: %s and %s' => '他の書式: %s または %s',
|
||||||
|
'Description' => '説明',
|
||||||
|
'%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 アカウントとリンクしました',
|
||||||
|
'Email' => 'Email',
|
||||||
|
'Link my Google Account' => 'Google アカウントをリンクする',
|
||||||
|
'Unlink my Google Account' => 'Google アカウントのリンクを解除する',
|
||||||
|
'Login with my Google Account' => 'Google アカウントでログインする',
|
||||||
|
'Project not found.' => 'プロジェクトが見つかりません。',
|
||||||
|
'Task #%d' => 'タスク #%d',
|
||||||
|
'Task removed successfully.' => 'タスクを削除しました。',
|
||||||
|
'Unable to remove this task.' => 'タスクの削除に失敗しました。',
|
||||||
|
'Remove a task' => 'タスクの削除',
|
||||||
|
'Do you really want to remove this task: "%s"?' => 'タスク「%s」を削除しますか?',
|
||||||
|
'Assign automatically a color based on a category' => 'カテゴリに基いて色を変える',
|
||||||
|
'Assign automatically a category based on a color' => '色に基いてカテゴリを変える',
|
||||||
|
'Task creation or modification' => 'タスクの作成または変更',
|
||||||
|
'Category' => 'カテゴリ',
|
||||||
|
'Category:' => 'カテゴリ:',
|
||||||
|
'Categories' => 'カテゴリ',
|
||||||
|
'Category not found.' => 'カテゴリが見つかりません',
|
||||||
|
'Your category have been created successfully.' => 'カテゴリを作成しました。',
|
||||||
|
'Unable to create your category.' => 'カテゴリの作成に失敗しました。',
|
||||||
|
'Your category have been updated successfully.' => 'カテゴリを更新しました。',
|
||||||
|
'Unable to update your category.' => 'カテゴリの更新に失敗しました。',
|
||||||
|
'Remove a category' => 'カテゴリの削除',
|
||||||
|
'Category removed successfully.' => 'カテゴリを削除しました。',
|
||||||
|
'Unable to remove this category.' => 'カテゴリを削除できませんでした。',
|
||||||
|
'Category modification for the project "%s"' => 'プロジェクト「%s」のカテゴリの変更',
|
||||||
|
'Category Name' => 'カテゴリ名',
|
||||||
|
'Categories for the project "%s"' => 'プロジェクト「%s」のカテゴリ',
|
||||||
|
'Add a new category' => 'カテゴリの追加',
|
||||||
|
'Do you really want to remove this category: "%s"?' => 'カテゴリ「%s」を削除しますか?',
|
||||||
|
'Filter by category' => 'カテゴリでフィルタリング',
|
||||||
|
'All categories' => 'すべてのカテゴリ',
|
||||||
|
'No category' => 'カテゴリなし',
|
||||||
|
'The name is required' => '名前を入力してください',
|
||||||
|
'Remove a file' => 'ファイルの削除',
|
||||||
|
'Unable to remove this file.' => 'ファイルの削除に失敗しました。',
|
||||||
|
'File removed successfully.' => 'ファイルを削除しました。',
|
||||||
|
'Attach a document' => 'ドキュメントを添付する',
|
||||||
|
'Do you really want to remove this file: "%s"?' => 'ファイル「%s」を削除しますか?',
|
||||||
|
'open' => 'オープン',
|
||||||
|
'Attachments' => '添付',
|
||||||
|
'Edit the task' => 'タスクを変更する',
|
||||||
|
'Edit the description' => '説明を変更する',
|
||||||
|
'Add a comment' => 'コメントの追加',
|
||||||
|
'Edit a comment' => 'コメントを変更する',
|
||||||
|
'Summary' => '概要',
|
||||||
|
'Time tracking' => '時間の計測',
|
||||||
|
'Estimate:' => '予測:',
|
||||||
|
'Spent:' => '経過:',
|
||||||
|
'Do you really want to remove this sub-task?' => 'サブタスクを削除しますか?',
|
||||||
|
'Remaining:' => '残り:',
|
||||||
|
'hours' => '時間',
|
||||||
|
'spent' => '経過',
|
||||||
|
'estimated' => '予測',
|
||||||
|
'Sub-Tasks' => 'サブタスク',
|
||||||
|
'Add a sub-task' => 'サブタスクを追加する',
|
||||||
|
'Original estimate' => '初期の予測',
|
||||||
|
'Create another sub-task' => '続けて別のサブタスクを追加する',
|
||||||
|
'Time spent' => '経過時間',
|
||||||
|
'Edit a sub-task' => 'サブタスクを変更する',
|
||||||
|
'Remove a sub-task' => 'サブタスクを削除する',
|
||||||
|
'The time must be a numeric value' => '時間は数字で入力してください',
|
||||||
|
'Todo' => '作業予定',
|
||||||
|
'In progress' => '作業中',
|
||||||
|
'Sub-task removed successfully.' => 'サブタスクを削除しました。',
|
||||||
|
'Unable to remove this sub-task.' => 'サブタスクの削除に失敗しました。',
|
||||||
|
'Sub-task updated successfully.' => 'サブタスクを更新しました。',
|
||||||
|
'Unable to update your sub-task.' => 'サブタスクの更新に失敗しました。',
|
||||||
|
'Unable to create your sub-task.' => 'サブタスクの追加に失敗しました。',
|
||||||
|
'Sub-task added successfully.' => 'サブタスクを追加しました。',
|
||||||
|
'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 アカウントとのリンクを解除する',
|
||||||
|
'Created by %s' => '%s が作成',
|
||||||
|
'Last modified on %B %e, %Y at %k:%M %p' => ' %Y/%m/%d %H:%M に変更',
|
||||||
|
'Tasks Export' => 'タスクの出力',
|
||||||
|
'Tasks exportation for "%s"' => '「%s」のタスク出力',
|
||||||
|
'Start Date' => '開始日',
|
||||||
|
'End Date' => '終了日',
|
||||||
|
'Execute' => '実行',
|
||||||
|
'Task Id' => 'タスク ID',
|
||||||
|
'Creator' => '作成者',
|
||||||
|
'Modification date' => '変更日',
|
||||||
|
'Completion date' => '完了日',
|
||||||
|
'Webhook URL for task creation' => 'タスク作成の Webhook URL',
|
||||||
|
'Webhook URL for task modification' => 'タスク変更の Webhook URL',
|
||||||
|
'Clone' => '複製',
|
||||||
|
'Clone Project' => 'プロジェクトの複製',
|
||||||
|
'Project cloned successfully.' => 'プロジェクトを複製しました。',
|
||||||
|
'Unable to clone this project.' => 'プロジェクトの複製に失敗しました。',
|
||||||
|
'Email notifications' => 'メール通知',
|
||||||
|
'Enable email notifications' => 'メール通知を設定',
|
||||||
|
'Task position:' => 'タスクの位置:',
|
||||||
|
'The task #%d have been opened.' => 'タスク #%d をオープンしました。',
|
||||||
|
'The task #%d have been closed.' => 'タスク #%d をクローズしました。',
|
||||||
|
'Sub-task updated' => 'サブタスクの更新',
|
||||||
|
'Title:' => 'タイトル:',
|
||||||
|
'Status:' => 'ステータス:',
|
||||||
|
'Assignee:' => '担当:',
|
||||||
|
'Time tracking:' => '時間計測:',
|
||||||
|
'New sub-task' => '新しいサブタスク',
|
||||||
|
'New attachment added "%s"' => '添付ファイル「%s」が追加されました',
|
||||||
|
'Comment updated' => 'コメントが更新されました',
|
||||||
|
'New comment posted by %s' => '「%s」の新しいコメントが追加されました',
|
||||||
|
'List of due tasks for the project "%s"' => 'プロジェクト「%s」の期限切れのタスク',
|
||||||
|
'[%s][New attachment] %s (#%d)' => '[%s][新規添付ファイル] %s (#%d)',
|
||||||
|
'[%s][New comment] %s (#%d)' => '[%s][新規コメント] %s (#%d)',
|
||||||
|
'[%s][Comment updated] %s (#%d)' => '[%s][コメント更新] %s (#%d)',
|
||||||
|
'[%s][New subtask] %s (#%d)' => '[%s][新規サブタスク] %s (#%d)',
|
||||||
|
'[%s][Subtask updated] %s (#%d)' => '[%s][サブタスク更新] %s (#%d)',
|
||||||
|
'[%s][New task] %s (#%d)' => '[%s][新規タスク] %s (#%d)',
|
||||||
|
'[%s][Task updated] %s (#%d)' => '[%s][タスク更新] %s (#%d)',
|
||||||
|
'[%s][Task closed] %s (#%d)' => '[%s][タスククローズ] %s (#%d)',
|
||||||
|
'[%s][Task opened] %s (#%d)' => '[%s][タスクオープン] %s (#%d)',
|
||||||
|
'[%s][Due tasks]' => '[%s][タスク期限切れ]',
|
||||||
|
'[Kanboard] Notification' => '[Kanboard] 通知',
|
||||||
|
'I want to receive notifications only for those projects:' => '以下のプロジェクトにのみ通知を受け取る:',
|
||||||
|
'view the task on Kanboard' => 'Kanboard でタスクを見る',
|
||||||
|
'Public access' => '公開アクセス設定',
|
||||||
|
'Category management' => 'カテゴリを管理する',
|
||||||
|
'User management' => 'ユーザを管理する',
|
||||||
|
'Active tasks' => 'アクティブなタスク',
|
||||||
|
'Disable public access' => '公開アクセスを無効にする',
|
||||||
|
'Enable public access' => '公開アクセスを有効にする',
|
||||||
|
'Active projects' => 'プロジェクト',
|
||||||
|
'Inactive projects' => '無効化されたプロジェクト',
|
||||||
|
'Public access disabled' => '公開アクセスは無効化されています',
|
||||||
|
'Do you really want to disable this project: "%s"?' => '「%s」を無効にしますか?',
|
||||||
|
'Do you really want to duplicate this project: "%s"?' => '「%s」を複製しますか?',
|
||||||
|
'Do you really want to enable this project: "%s"?' => '「%s」を有効にしますか?',
|
||||||
|
'Project activation' => 'プロジェクトのアクティベーション',
|
||||||
|
'Move the task to another project' => 'タスクを別プロジェクトに移す',
|
||||||
|
'Move to another project' => '別プロジェクトに移す',
|
||||||
|
'Do you really want to duplicate this task?' => 'タスクを複製しますか?',
|
||||||
|
'Duplicate a task' => 'タスクの複製',
|
||||||
|
'External accounts' => '外部アカウント',
|
||||||
|
'Account type' => 'アカウントの種類',
|
||||||
|
'Local' => 'ローカル',
|
||||||
|
'Remote' => 'リモート',
|
||||||
|
'Enabled' => '有効',
|
||||||
|
'Disabled' => '無効',
|
||||||
|
'Google account linked' => 'Google アカウントがリンク',
|
||||||
|
'Github account linked' => 'GitHub のアカウントがリンク',
|
||||||
|
'Username:' => 'ユーザ名:',
|
||||||
|
'Name:' => '名前:',
|
||||||
|
'Email:' => 'Email:',
|
||||||
|
'Default project:' => 'デフォルトプロジェクト:',
|
||||||
|
'Notifications:' => '通知:',
|
||||||
|
// 'Notifications' => '',
|
||||||
|
'Group:' => 'グループ:',
|
||||||
|
'Regular user' => '通常のユーザ',
|
||||||
|
'Account type:' => 'アカウントの種類:',
|
||||||
|
'Edit profile' => 'プロフィールの変更',
|
||||||
|
'Change password' => 'パスワードの変更',
|
||||||
|
'Password modification' => 'パスワードの変更',
|
||||||
|
'External authentications' => '外部認証',
|
||||||
|
'Google Account' => 'Google アカウント',
|
||||||
|
'Github Account' => 'GitHub アカウント',
|
||||||
|
'Never connected.' => '未接続。',
|
||||||
|
'No account linked.' => 'アカウントがリンクしていません。',
|
||||||
|
'Account linked.' => 'アカウントがリンクしました。',
|
||||||
|
'No external authentication enabled.' => '外部認証が設定されていません。',
|
||||||
|
'Password modified successfully.' => 'パスワードを変更しました。',
|
||||||
|
'Unable to change the password.' => 'パスワードが変更できませんでした。',
|
||||||
|
'Change category for the task "%s"' => 'タスク「%s」のカテゴリの変更',
|
||||||
|
'Change category' => 'カテゴリの変更',
|
||||||
|
'%s updated the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s がタスク <a href="?controller=task&action=show&task_id=%d">#%d</a> をアップデートしました',
|
||||||
|
'%s open the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s がタスク <a href="?controller=task&action=show&task_id=%d">#%d</a> をオープンしました',
|
||||||
|
'%s moved the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to the position #%d in the column "%s"' => '%s がタスク <a href="?controller=task&action=show&task_id=%d">#%d</a> をポジション #%d カラム %s に移動しました',
|
||||||
|
'%s moved the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to the column "%s"' => '%s がタスク <a href="?controller=task&action=show&task_id=%d">#%d</a> をカラム「%s」に移動しました',
|
||||||
|
'%s created the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s がタスク <a href="?controller=task&action=show&task_id=%d">#%d</a> を作成しました',
|
||||||
|
'%s closed the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s がタスク <a href="?controller=task&action=show&task_id=%d">#%d</a> をクローズしました',
|
||||||
|
'%s created a subtask for the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s がタスク <a href="?controller=task&action=show&task_id=%d">#%d</a> のサブタスクを追加しました',
|
||||||
|
'%s updated a subtask for the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s がタスク <a href="?controller=task&action=show&task_id=%d">#%d</a> のサブタスクを更新しました',
|
||||||
|
'Assigned to %s with an estimate of %s/%sh' => '担当者 %s に予想 %s/%sh に変更されました',
|
||||||
|
'Not assigned, estimate of %sh' => '担当者無しで予想 %sh に変更されました',
|
||||||
|
'%s updated a comment on the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s がタスク <a href="?controller=task&action=show&task_id=%d">#%d</a> のコメントを更新しました',
|
||||||
|
'%s commented the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s がタスク <a href="?controller=task&action=show&task_id=%d">#%d</a> にコメントしました',
|
||||||
|
'%s\'s activity' => '%s のアクティビティ',
|
||||||
|
'No activity.' => 'アクティビティなし。',
|
||||||
|
'RSS feed' => 'RSS フィード',
|
||||||
|
'%s updated a comment on the task #%d' => '%s がタスク #%d のコメントを更新しました',
|
||||||
|
'%s commented on the task #%d' => '%s がタスク #%d にコメントしました',
|
||||||
|
'%s updated a subtask for the task #%d' => '%s がタスク #%d のサブタスクを更新しました',
|
||||||
|
'%s created a subtask for the task #%d' => '%s がタスク #%d のサブタスクを追加しました',
|
||||||
|
'%s updated the task #%d' => '%s がタスク #%d を更新しました',
|
||||||
|
'%s created the task #%d' => '%s がタスク #%d を追加しました',
|
||||||
|
'%s closed the task #%d' => '%s がタスク #%d をクローズしました',
|
||||||
|
'%s open the task #%d' => '%s がタスク #%d をオープンしました',
|
||||||
|
'%s moved the task #%d to the column "%s"' => '%s がタスク #%d をカラム「%s」に移動しました',
|
||||||
|
'%s moved the task #%d to the position %d in the column "%s"' => '%s がタスク #%d を位置 %d カラム「%s」移動しました',
|
||||||
|
'Activity' => 'アクティビティ',
|
||||||
|
'Default values are "%s"' => 'デフォルト値は「%s」',
|
||||||
|
'Default columns for new projects (Comma-separated)' => '新規プロジェクトのデフォルトカラム (コンマで区切って入力)',
|
||||||
|
'Task assignee change' => '担当者の変更',
|
||||||
|
'%s change the assignee of the task #%d to %s' => '%s がタスク #%d の担当を %s に変更しました',
|
||||||
|
'%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to %s' => '%s がタスク <a href="?controller=task&action=show&task_id=%d">#%d</a> の担当を %s に変更しました',
|
||||||
|
'[%s][Column Change] %s (#%d)' => '[%s][カラムの変更] %s (#%d)',
|
||||||
|
'[%s][Position Change] %s (#%d)' => '[%s][位置の変更] %s (#%d)',
|
||||||
|
'[%s][Assignee Change] %s (#%d)' => '[%s][担当者変更] %s (#%d)',
|
||||||
|
'New password for the user "%s"' => 'ユーザ「%s」の新しいパスワード',
|
||||||
|
'Choose an event' => 'イベントの選択',
|
||||||
|
'Github commit received' => 'Github のコミットを受け取った',
|
||||||
|
'Github issue opened' => 'Github Issue がオープンされた',
|
||||||
|
'Github issue closed' => 'Github Issue がクローズされた',
|
||||||
|
'Github issue reopened' => 'Github Issue が再オープンされた',
|
||||||
|
'Github issue assignee change' => 'Github Issue の担当が変更された',
|
||||||
|
'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' => 'カテゴリを外部サービスに基いて変更する',
|
||||||
|
'Reference' => '参照',
|
||||||
|
'Reference: %s' => '参照: %s',
|
||||||
|
'Label' => 'ラベル',
|
||||||
|
'Database' => 'データベース',
|
||||||
|
'About' => '情報',
|
||||||
|
'Database driver:' => 'データベースドライバ:',
|
||||||
|
'Board settings' => '基本設定',
|
||||||
|
'URL and token' => 'URL とトークン',
|
||||||
|
'Webhook settings' => 'Webhook の設定',
|
||||||
|
'URL for task creation:' => 'Task 作成の URL:',
|
||||||
|
'Reset token' => 'トークンのリセット',
|
||||||
|
'API endpoint:' => 'API エンドポイント:',
|
||||||
|
'Refresh interval for private board' => '非公開ボードの更新頻度',
|
||||||
|
'Refresh interval for public board' => '公開ボードの更新頻度',
|
||||||
|
'Task highlight period' => 'タスクのハイライト期間',
|
||||||
|
'Period (in second) to consider a task was modified recently (0 to disable, 2 days by default)' => 'タスクが最近更新されたとみなす期間(0 はハイライト無効、デフォルト 2 日)',
|
||||||
|
'Frequency in second (60 seconds by default)' => '秒数 (デフォルト 60 秒)',
|
||||||
|
'Frequency in second (0 to disable this feature, 10 seconds by default)' => '秒数 (0 は機能を無効化、デフォルト 10 秒)',
|
||||||
|
'Application URL' => 'アプリケーションの URL',
|
||||||
|
'Example: http://example.kanboard.net/ (used by email notifications)' => 'Exemple : http://exemple.kanboard.net/ (Email 通知に利用)',
|
||||||
|
'Token regenerated.' => 'トークンが再生成されました。',
|
||||||
|
'Date format' => 'データのフォーマット',
|
||||||
|
'ISO format is always accepted, example: "%s" and "%s"' => 'ISO フォーマットが入力できます(例: %s または %s)',
|
||||||
|
'New private project' => '非公開プロジェクトを作る',
|
||||||
|
'This project is private' => 'このプロジェクトは非公開です',
|
||||||
|
'Type here to create a new sub-task' => 'サブタスクを追加するにはここに入力してください',
|
||||||
|
'Add' => '追加',
|
||||||
|
'Estimated time: %s hours' => '予想時間: %s 時間',
|
||||||
|
'Time spent: %s hours' => '経過: %s 時間',
|
||||||
|
'Started on %B %e, %Y' => '開始 %Y/%m/%d',
|
||||||
|
'Start date' => '開始時間',
|
||||||
|
'Time estimated' => '予想時間',
|
||||||
|
// 'There is nothing assigned to you.' => '',
|
||||||
|
// 'My tasks' => '',
|
||||||
|
// 'Activity stream' => '',
|
||||||
|
// 'Dashboard' => '',
|
||||||
|
// 'Confirmation' => '',
|
||||||
|
// 'Allow everybody to access to this project' => '',
|
||||||
|
// 'Everybody have access to this project.' => '',
|
||||||
|
// 'Webhooks' => '',
|
||||||
|
// 'API' => '',
|
||||||
|
// 'Integration' => '',
|
||||||
|
// 'Github webhook' => '',
|
||||||
|
// 'Help on Github webhook' => '',
|
||||||
|
// 'Create a comment from an external provider' => '',
|
||||||
|
// 'Github issue comment created' => '',
|
||||||
|
);
|
|
@ -83,7 +83,7 @@ return array(
|
||||||
'Settings' => 'Ustawienia',
|
'Settings' => 'Ustawienia',
|
||||||
'Application settings' => 'Ustawienia aplikacji',
|
'Application settings' => 'Ustawienia aplikacji',
|
||||||
'Language' => 'Język',
|
'Language' => 'Język',
|
||||||
'Webhooks token:' => 'Token :',
|
'Webhook token:' => 'Token :',
|
||||||
// 'API token:' => '',
|
// 'API token:' => '',
|
||||||
'More information' => 'Więcej informacji',
|
'More information' => 'Więcej informacji',
|
||||||
'Database size:' => 'Rozmiar bazy danych :',
|
'Database size:' => 'Rozmiar bazy danych :',
|
||||||
|
@ -196,7 +196,7 @@ return array(
|
||||||
'revoke' => 'odbierz dostęp',
|
'revoke' => 'odbierz dostęp',
|
||||||
'List of authorized users' => 'Lista użytkowników mających dostęp',
|
'List of authorized users' => 'Lista użytkowników mających dostęp',
|
||||||
'User' => 'Użytkownik',
|
'User' => 'Użytkownik',
|
||||||
'Everybody have access to this project.' => 'Każdy ma dostęp do tego projektu.',
|
// 'Nobody have access to this project.' => '',
|
||||||
'You are not allowed to access to this project.' => 'Nie masz dostępu do tego projektu.',
|
'You are not allowed to access to this project.' => 'Nie masz dostępu do tego projektu.',
|
||||||
'Comments' => 'Komentarze',
|
'Comments' => 'Komentarze',
|
||||||
'Post comment' => 'Dodaj komentarz',
|
'Post comment' => 'Dodaj komentarz',
|
||||||
|
@ -209,8 +209,6 @@ return array(
|
||||||
'The description is required' => 'Opis jest wymagany',
|
'The description is required' => 'Opis jest wymagany',
|
||||||
'Edit this task' => 'Edytuj zadanie',
|
'Edit this task' => 'Edytuj zadanie',
|
||||||
'Due Date' => 'Termin',
|
'Due Date' => 'Termin',
|
||||||
'm/d/Y' => 'd/m/Y',
|
|
||||||
'month/day/year' => 'dzień/miesiąc/rok',
|
|
||||||
'Invalid date' => 'Błędna data',
|
'Invalid date' => 'Błędna data',
|
||||||
'Must be done before %B %e, %Y' => 'Termin do %e %B %Y',
|
'Must be done before %B %e, %Y' => 'Termin do %e %B %Y',
|
||||||
'%B %e, %Y' => '%e %B %Y',
|
'%B %e, %Y' => '%e %B %Y',
|
||||||
|
@ -351,9 +349,9 @@ return array(
|
||||||
// 'estimated' => '',
|
// 'estimated' => '',
|
||||||
// 'Sub-Tasks' => '',
|
// 'Sub-Tasks' => '',
|
||||||
// 'Add a sub-task' => '',
|
// 'Add a sub-task' => '',
|
||||||
// 'Original Estimate' => '',
|
// 'Original estimate' => '',
|
||||||
// 'Create another sub-task' => '',
|
// 'Create another sub-task' => '',
|
||||||
// 'Time Spent' => '',
|
// 'Time spent' => '',
|
||||||
// 'Edit a sub-task' => '',
|
// 'Edit a sub-task' => '',
|
||||||
// 'Remove a sub-task' => '',
|
// 'Remove a sub-task' => '',
|
||||||
// 'The time must be a numeric value' => '',
|
// 'The time must be a numeric value' => '',
|
||||||
|
@ -422,8 +420,8 @@ return array(
|
||||||
// 'I want to receive notifications only for those projects:' => '',
|
// 'I want to receive notifications only for those projects:' => '',
|
||||||
// 'view the task on Kanboard' => '',
|
// 'view the task on Kanboard' => '',
|
||||||
// 'Public access' => '',
|
// 'Public access' => '',
|
||||||
// 'Categories management' => '',
|
// 'Category management' => '',
|
||||||
// 'Users management' => '',
|
// 'User management' => '',
|
||||||
// 'Active tasks' => '',
|
// 'Active tasks' => '',
|
||||||
// 'Disable public access' => '',
|
// 'Disable public access' => '',
|
||||||
// 'Enable public access' => '',
|
// 'Enable public access' => '',
|
||||||
|
@ -451,6 +449,7 @@ return array(
|
||||||
// 'Email:' => '',
|
// 'Email:' => '',
|
||||||
// 'Default project:' => '',
|
// 'Default project:' => '',
|
||||||
// 'Notifications:' => '',
|
// 'Notifications:' => '',
|
||||||
|
// 'Notifications' => '',
|
||||||
// 'Group:' => '',
|
// 'Group:' => '',
|
||||||
// 'Regular user' => '',
|
// 'Regular user' => '',
|
||||||
// 'Account type:' => '',
|
// 'Account type:' => '',
|
||||||
|
@ -497,10 +496,66 @@ return array(
|
||||||
// 'Default values are "%s"' => '',
|
// 'Default values are "%s"' => '',
|
||||||
// 'Default columns for new projects (Comma-separated)' => '',
|
// 'Default columns for new projects (Comma-separated)' => '',
|
||||||
// 'Task assignee change' => '',
|
// 'Task assignee change' => '',
|
||||||
// '%s change the assignee of the task #%d' => '',
|
// '%s change the assignee of the task #%d to %s' => '',
|
||||||
// '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '',
|
// '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to %s' => '',
|
||||||
// '[%s][Column Change] %s (#%d)' => '',
|
// '[%s][Column Change] %s (#%d)' => '',
|
||||||
// '[%s][Position Change] %s (#%d)' => '',
|
// '[%s][Position Change] %s (#%d)' => '',
|
||||||
// '[%s][Assignee Change] %s (#%d)' => '',
|
// '[%s][Assignee Change] %s (#%d)' => '',
|
||||||
// 'New password for the user "%s"' => '',
|
// 'New password for the user "%s"' => '',
|
||||||
|
// 'Choose an event' => '',
|
||||||
|
// 'Github commit received' => '',
|
||||||
|
// 'Github issue opened' => '',
|
||||||
|
// 'Github issue closed' => '',
|
||||||
|
// 'Github issue reopened' => '',
|
||||||
|
// 'Github issue assignee change' => '',
|
||||||
|
// 'Github issue label change' => '',
|
||||||
|
// 'Create a task from an external provider' => '',
|
||||||
|
// 'Change the assignee based on an external username' => '',
|
||||||
|
// 'Change the category based on an external label' => '',
|
||||||
|
// 'Reference' => '',
|
||||||
|
// 'Reference: %s' => '',
|
||||||
|
// 'Label' => '',
|
||||||
|
// 'Database' => '',
|
||||||
|
// 'About' => '',
|
||||||
|
// 'Database driver:' => '',
|
||||||
|
// 'Board settings' => '',
|
||||||
|
// 'URL and token' => '',
|
||||||
|
// 'Webhook settings' => '',
|
||||||
|
// 'URL for task creation:' => '',
|
||||||
|
// 'Reset token' => '',
|
||||||
|
// 'API endpoint:' => '',
|
||||||
|
// 'Refresh interval for private board' => '',
|
||||||
|
// 'Refresh interval for public board' => '',
|
||||||
|
// 'Task highlight period' => '',
|
||||||
|
// 'Period (in second) to consider a task was modified recently (0 to disable, 2 days by default)' => '',
|
||||||
|
// 'Frequency in second (60 seconds by default)' => '',
|
||||||
|
// 'Frequency in second (0 to disable this feature, 10 seconds by default)' => '',
|
||||||
|
// 'Application URL' => '',
|
||||||
|
// 'Example: http://example.kanboard.net/ (used by email notifications)' => '',
|
||||||
|
// 'Token regenerated.' => '',
|
||||||
|
// 'Date format' => '',
|
||||||
|
// 'ISO format is always accepted, example: "%s" and "%s"' => '',
|
||||||
|
// 'New private project' => '',
|
||||||
|
// 'This project is private' => '',
|
||||||
|
// 'Type here to create a new sub-task' => '',
|
||||||
|
// 'Add' => '',
|
||||||
|
// 'Estimated time: %s hours' => '',
|
||||||
|
// 'Time spent: %s hours' => '',
|
||||||
|
// 'Started on %B %e, %Y' => '',
|
||||||
|
// 'Start date' => '',
|
||||||
|
// 'Time estimated' => '',
|
||||||
|
// 'There is nothing assigned to you.' => '',
|
||||||
|
// 'My tasks' => '',
|
||||||
|
// 'Activity stream' => '',
|
||||||
|
// 'Dashboard' => '',
|
||||||
|
// 'Confirmation' => '',
|
||||||
|
// 'Allow everybody to access to this project' => '',
|
||||||
|
// 'Everybody have access to this project.' => '',
|
||||||
|
// 'Webhooks' => '',
|
||||||
|
// 'API' => '',
|
||||||
|
// 'Integration' => '',
|
||||||
|
// 'Github webhook' => '',
|
||||||
|
// 'Help on Github webhook' => '',
|
||||||
|
// 'Create a comment from an external provider' => '',
|
||||||
|
// 'Github issue comment created' => '',
|
||||||
);
|
);
|
|
@ -83,7 +83,7 @@ return array(
|
||||||
'Settings' => 'Preferências',
|
'Settings' => 'Preferências',
|
||||||
'Application settings' => 'Preferências da aplicação',
|
'Application settings' => 'Preferências da aplicação',
|
||||||
'Language' => 'Idioma',
|
'Language' => 'Idioma',
|
||||||
'Webhooks token:' => 'Token de webhooks:',
|
'Webhook token:' => 'Token de webhooks:',
|
||||||
'API token:' => 'API Token:',
|
'API token:' => 'API Token:',
|
||||||
'More information' => 'Mais informação',
|
'More information' => 'Mais informação',
|
||||||
'Database size:' => 'Tamanho do banco de dados:',
|
'Database size:' => 'Tamanho do banco de dados:',
|
||||||
|
@ -196,7 +196,7 @@ return array(
|
||||||
'revoke' => 'revogar',
|
'revoke' => 'revogar',
|
||||||
'List of authorized users' => 'Lista de usuários autorizados',
|
'List of authorized users' => 'Lista de usuários autorizados',
|
||||||
'User' => 'Usuário',
|
'User' => 'Usuário',
|
||||||
'Everybody have access to this project.' => 'Todos têm acesso a este projeto.',
|
// 'Nobody have access to this project.' => '',
|
||||||
'You are not allowed to access to this project.' => 'Você não está autorizado a acessar este projeto.',
|
'You are not allowed to access to this project.' => 'Você não está autorizado a acessar este projeto.',
|
||||||
'Comments' => 'Comentários',
|
'Comments' => 'Comentários',
|
||||||
'Post comment' => 'Postar comentário',
|
'Post comment' => 'Postar comentário',
|
||||||
|
@ -209,8 +209,6 @@ return array(
|
||||||
'The description is required' => 'A descrição é obrigatória',
|
'The description is required' => 'A descrição é obrigatória',
|
||||||
'Edit this task' => 'Editar esta tarefa',
|
'Edit this task' => 'Editar esta tarefa',
|
||||||
'Due Date' => 'Data de vencimento',
|
'Due Date' => 'Data de vencimento',
|
||||||
'm/d/Y' => 'd/m/Y',
|
|
||||||
'month/day/year' => 'dia/mês/ano',
|
|
||||||
'Invalid date' => 'Data inválida',
|
'Invalid date' => 'Data inválida',
|
||||||
'Must be done before %B %e, %Y' => 'Deve ser feito antes de %d %B %Y',
|
'Must be done before %B %e, %Y' => 'Deve ser feito antes de %d %B %Y',
|
||||||
'%B %e, %Y' => '%d %B %Y',
|
'%B %e, %Y' => '%d %B %Y',
|
||||||
|
@ -351,9 +349,9 @@ return array(
|
||||||
'estimated' => 'estimada',
|
'estimated' => 'estimada',
|
||||||
'Sub-Tasks' => 'Sub-tarefas',
|
'Sub-Tasks' => 'Sub-tarefas',
|
||||||
'Add a sub-task' => 'Adicionar uma sub-tarefa',
|
'Add a sub-task' => 'Adicionar uma sub-tarefa',
|
||||||
'Original Estimate' => 'Estimativa original',
|
'Original estimate' => 'Estimativa original',
|
||||||
'Create another sub-task' => 'Criar uma outra sub-tarefa',
|
'Create another sub-task' => 'Criar uma outra sub-tarefa',
|
||||||
'Time Spent' => 'Tempo gasto',
|
'Time spent' => 'Tempo gasto',
|
||||||
'Edit a sub-task' => 'Editar uma sub-tarefa',
|
'Edit a sub-task' => 'Editar uma sub-tarefa',
|
||||||
'Remove a sub-task' => 'Remover uma sub-tarefa',
|
'Remove a sub-task' => 'Remover uma sub-tarefa',
|
||||||
'The time must be a numeric value' => 'O tempo deve ser um valor numérico',
|
'The time must be a numeric value' => 'O tempo deve ser um valor numérico',
|
||||||
|
@ -422,8 +420,8 @@ return array(
|
||||||
// 'I want to receive notifications only for those projects:' => '',
|
// 'I want to receive notifications only for those projects:' => '',
|
||||||
// 'view the task on Kanboard' => '',
|
// 'view the task on Kanboard' => '',
|
||||||
// 'Public access' => '',
|
// 'Public access' => '',
|
||||||
// 'Categories management' => '',
|
// 'Category management' => '',
|
||||||
// 'Users management' => '',
|
// 'User management' => '',
|
||||||
// 'Active tasks' => '',
|
// 'Active tasks' => '',
|
||||||
// 'Disable public access' => '',
|
// 'Disable public access' => '',
|
||||||
// 'Enable public access' => '',
|
// 'Enable public access' => '',
|
||||||
|
@ -451,6 +449,7 @@ return array(
|
||||||
// 'Email:' => '',
|
// 'Email:' => '',
|
||||||
// 'Default project:' => '',
|
// 'Default project:' => '',
|
||||||
// 'Notifications:' => '',
|
// 'Notifications:' => '',
|
||||||
|
// 'Notifications' => '',
|
||||||
// 'Group:' => '',
|
// 'Group:' => '',
|
||||||
// 'Regular user' => '',
|
// 'Regular user' => '',
|
||||||
// 'Account type:' => '',
|
// 'Account type:' => '',
|
||||||
|
@ -497,10 +496,66 @@ return array(
|
||||||
// 'Default values are "%s"' => '',
|
// 'Default values are "%s"' => '',
|
||||||
// 'Default columns for new projects (Comma-separated)' => '',
|
// 'Default columns for new projects (Comma-separated)' => '',
|
||||||
// 'Task assignee change' => '',
|
// 'Task assignee change' => '',
|
||||||
// '%s change the assignee of the task #%d' => '',
|
// '%s change the assignee of the task #%d to %s' => '',
|
||||||
// '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '',
|
// '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to %s' => '',
|
||||||
// '[%s][Column Change] %s (#%d)' => '',
|
// '[%s][Column Change] %s (#%d)' => '',
|
||||||
// '[%s][Position Change] %s (#%d)' => '',
|
// '[%s][Position Change] %s (#%d)' => '',
|
||||||
// '[%s][Assignee Change] %s (#%d)' => '',
|
// '[%s][Assignee Change] %s (#%d)' => '',
|
||||||
// 'New password for the user "%s"' => '',
|
// 'New password for the user "%s"' => '',
|
||||||
|
// 'Choose an event' => '',
|
||||||
|
// 'Github commit received' => '',
|
||||||
|
// 'Github issue opened' => '',
|
||||||
|
// 'Github issue closed' => '',
|
||||||
|
// 'Github issue reopened' => '',
|
||||||
|
// 'Github issue assignee change' => '',
|
||||||
|
// 'Github issue label change' => '',
|
||||||
|
// 'Create a task from an external provider' => '',
|
||||||
|
// 'Change the assignee based on an external username' => '',
|
||||||
|
// 'Change the category based on an external label' => '',
|
||||||
|
// 'Reference' => '',
|
||||||
|
// 'Reference: %s' => '',
|
||||||
|
// 'Label' => '',
|
||||||
|
// 'Database' => '',
|
||||||
|
// 'About' => '',
|
||||||
|
// 'Database driver:' => '',
|
||||||
|
// 'Board settings' => '',
|
||||||
|
// 'URL and token' => '',
|
||||||
|
// 'Webhook settings' => '',
|
||||||
|
// 'URL for task creation:' => '',
|
||||||
|
// 'Reset token' => '',
|
||||||
|
// 'API endpoint:' => '',
|
||||||
|
// 'Refresh interval for private board' => '',
|
||||||
|
// 'Refresh interval for public board' => '',
|
||||||
|
// 'Task highlight period' => '',
|
||||||
|
// 'Period (in second) to consider a task was modified recently (0 to disable, 2 days by default)' => '',
|
||||||
|
// 'Frequency in second (60 seconds by default)' => '',
|
||||||
|
// 'Frequency in second (0 to disable this feature, 10 seconds by default)' => '',
|
||||||
|
// 'Application URL' => '',
|
||||||
|
// 'Example: http://example.kanboard.net/ (used by email notifications)' => '',
|
||||||
|
// 'Token regenerated.' => '',
|
||||||
|
// 'Date format' => '',
|
||||||
|
// 'ISO format is always accepted, example: "%s" and "%s"' => '',
|
||||||
|
// 'New private project' => '',
|
||||||
|
// 'This project is private' => '',
|
||||||
|
// 'Type here to create a new sub-task' => '',
|
||||||
|
// 'Add' => '',
|
||||||
|
// 'Estimated time: %s hours' => '',
|
||||||
|
// 'Time spent: %s hours' => '',
|
||||||
|
// 'Started on %B %e, %Y' => '',
|
||||||
|
// 'Start date' => '',
|
||||||
|
// 'Time estimated' => '',
|
||||||
|
// 'There is nothing assigned to you.' => '',
|
||||||
|
// 'My tasks' => '',
|
||||||
|
// 'Activity stream' => '',
|
||||||
|
// 'Dashboard' => '',
|
||||||
|
// 'Confirmation' => '',
|
||||||
|
// 'Allow everybody to access to this project' => '',
|
||||||
|
// 'Everybody have access to this project.' => '',
|
||||||
|
// 'Webhooks' => '',
|
||||||
|
// 'API' => '',
|
||||||
|
// 'Integration' => '',
|
||||||
|
// 'Github webhook' => '',
|
||||||
|
// 'Help on Github webhook' => '',
|
||||||
|
// 'Create a comment from an external provider' => '',
|
||||||
|
// 'Github issue comment created' => '',
|
||||||
);
|
);
|
|
@ -83,7 +83,7 @@ return array(
|
||||||
'Settings' => 'Настройки',
|
'Settings' => 'Настройки',
|
||||||
'Application settings' => 'Настройки приложения',
|
'Application settings' => 'Настройки приложения',
|
||||||
'Language' => 'Язык',
|
'Language' => 'Язык',
|
||||||
'Webhooks token:' => 'Webhooks токен :',
|
'Webhook token:' => 'Webhooks токен :',
|
||||||
'API token:' => 'API токен :',
|
'API token:' => 'API токен :',
|
||||||
'More information' => 'Подробнее',
|
'More information' => 'Подробнее',
|
||||||
'Database size:' => 'Размер базы данных :',
|
'Database size:' => 'Размер базы данных :',
|
||||||
|
@ -164,7 +164,7 @@ return array(
|
||||||
'Ready' => 'Готовые',
|
'Ready' => 'Готовые',
|
||||||
'Backlog' => 'Ожидающие',
|
'Backlog' => 'Ожидающие',
|
||||||
'Work in progress' => 'В процессе',
|
'Work in progress' => 'В процессе',
|
||||||
'Done' => 'Завершенные',
|
'Done' => 'Выполнена',
|
||||||
'Application version:' => 'Версия приложения :',
|
'Application version:' => 'Версия приложения :',
|
||||||
'Completed on %B %e, %Y at %k:%M %p' => 'Завершен %d/%m/%Y в %H:%M',
|
'Completed on %B %e, %Y at %k:%M %p' => 'Завершен %d/%m/%Y в %H:%M',
|
||||||
'%B %e, %Y at %k:%M %p' => '%d/%m/%Y в %H:%M',
|
'%B %e, %Y at %k:%M %p' => '%d/%m/%Y в %H:%M',
|
||||||
|
@ -192,11 +192,11 @@ return array(
|
||||||
'Edit users access' => 'Изменить доступ пользователей',
|
'Edit users access' => 'Изменить доступ пользователей',
|
||||||
'Allow this user' => 'Разрешить этого пользователя',
|
'Allow this user' => 'Разрешить этого пользователя',
|
||||||
'Only those users have access to this project:' => 'Только эти пользователи имеют доступ к проекту :',
|
'Only those users have access to this project:' => 'Только эти пользователи имеют доступ к проекту :',
|
||||||
'Don\'t forget that administrators have access to everything.' => 'Помните, администратор имеет доступ всюду.',
|
'Don\'t forget that administrators have access to everything.' => 'Помните, администратор имеет доступ ко всему.',
|
||||||
'revoke' => 'отозвать',
|
'revoke' => 'отозвать',
|
||||||
'List of authorized users' => 'Список авторизованных пользователей',
|
'List of authorized users' => 'Список авторизованных пользователей',
|
||||||
'User' => 'Пользователь',
|
'User' => 'Пользователь',
|
||||||
'Everybody have access to this project.' => 'Кто угодно имеет доступ к этому проекту.',
|
'Nobody have access to this project.' => 'Ни у кого нет доступа к этому проекту',
|
||||||
'You are not allowed to access to this project.' => 'Вам запрешен доступ к этому проекту.',
|
'You are not allowed to access to this project.' => 'Вам запрешен доступ к этому проекту.',
|
||||||
'Comments' => 'Комментарии',
|
'Comments' => 'Комментарии',
|
||||||
'Post comment' => 'Оставить комментарий',
|
'Post comment' => 'Оставить комментарий',
|
||||||
|
@ -208,9 +208,7 @@ return array(
|
||||||
'Unable to create your comment.' => 'Невозможно создать комментарий.',
|
'Unable to create your comment.' => 'Невозможно создать комментарий.',
|
||||||
'The description is required' => 'Требуется описание',
|
'The description is required' => 'Требуется описание',
|
||||||
'Edit this task' => 'Изменить задачу',
|
'Edit this task' => 'Изменить задачу',
|
||||||
'Due Date' => 'Срок',
|
'Due Date' => 'Сделать до',
|
||||||
'm/d/Y' => 'м/д/Г',
|
|
||||||
'month/day/year' => 'месяц/день/год',
|
|
||||||
'Invalid date' => 'Неверная дата',
|
'Invalid date' => 'Неверная дата',
|
||||||
'Must be done before %B %e, %Y' => 'Должно быть сделано до %d/%m/%Y',
|
'Must be done before %B %e, %Y' => 'Должно быть сделано до %d/%m/%Y',
|
||||||
'%B %e, %Y' => '%d/%m/%Y',
|
'%B %e, %Y' => '%d/%m/%Y',
|
||||||
|
@ -251,7 +249,7 @@ return array(
|
||||||
'Move Down' => 'Сдвинуть вниз',
|
'Move Down' => 'Сдвинуть вниз',
|
||||||
'Duplicate to another project' => 'Клонировать в другой проект',
|
'Duplicate to another project' => 'Клонировать в другой проект',
|
||||||
'Duplicate' => 'Клонировать',
|
'Duplicate' => 'Клонировать',
|
||||||
'link' => 'связь',
|
'link' => 'ссылка',
|
||||||
'Update this comment' => 'Обновить комментарий',
|
'Update this comment' => 'Обновить комментарий',
|
||||||
'Comment updated successfully.' => 'Комментарий обновлен.',
|
'Comment updated successfully.' => 'Комментарий обновлен.',
|
||||||
'Unable to update your comment.' => 'Не удалось обновить ваш комментарий.',
|
'Unable to update your comment.' => 'Не удалось обновить ваш комментарий.',
|
||||||
|
@ -351,13 +349,13 @@ return array(
|
||||||
'estimated' => 'расчетное',
|
'estimated' => 'расчетное',
|
||||||
'Sub-Tasks' => 'Подзадачи',
|
'Sub-Tasks' => 'Подзадачи',
|
||||||
'Add a sub-task' => 'Добавить подзадачу',
|
'Add a sub-task' => 'Добавить подзадачу',
|
||||||
'Original Estimate' => 'Начальная оценка',
|
'Original estimate' => 'Первичная оценка',
|
||||||
'Create another sub-task' => 'Создать другую подзадачу',
|
'Create another sub-task' => 'Создать другую подзадачу',
|
||||||
'Time Spent' => 'Времени затрачено',
|
'Time spent' => 'Времени затрачено',
|
||||||
'Edit a sub-task' => 'Изменить подзадачу',
|
'Edit a sub-task' => 'Изменить подзадачу',
|
||||||
'Remove a sub-task' => 'Удалить подзадачу',
|
'Remove a sub-task' => 'Удалить подзадачу',
|
||||||
'The time must be a numeric value' => 'Время должно быть числом!',
|
'The time must be a numeric value' => 'Время должно быть числом!',
|
||||||
'Todo' => 'TODO',
|
'Todo' => 'К исполнению',
|
||||||
'In progress' => 'В процессе',
|
'In progress' => 'В процессе',
|
||||||
'Sub-task removed successfully.' => 'Подзадача удалена.',
|
'Sub-task removed successfully.' => 'Подзадача удалена.',
|
||||||
'Unable to remove this sub-task.' => 'Не удалось удалить подзадачу.',
|
'Unable to remove this sub-task.' => 'Не удалось удалить подзадачу.',
|
||||||
|
@ -422,8 +420,8 @@ return array(
|
||||||
'I want to receive notifications only for those projects:' => 'Я хочу получать уведомления только по этим проектам :',
|
'I want to receive notifications only for those projects:' => 'Я хочу получать уведомления только по этим проектам :',
|
||||||
'view the task on Kanboard' => 'посмотреть задачу на Kanboard',
|
'view the task on Kanboard' => 'посмотреть задачу на Kanboard',
|
||||||
'Public access' => 'Общий доступ',
|
'Public access' => 'Общий доступ',
|
||||||
'Categories management' => 'Управление категориями',
|
'Category management' => 'Управление категориями',
|
||||||
'Users management' => 'Управление пользователями',
|
'User management' => 'Управление пользователями',
|
||||||
'Active tasks' => 'Активные задачи',
|
'Active tasks' => 'Активные задачи',
|
||||||
'Disable public access' => 'Отключить общий доступ',
|
'Disable public access' => 'Отключить общий доступ',
|
||||||
'Enable public access' => 'Включить общий доступ',
|
'Enable public access' => 'Включить общий доступ',
|
||||||
|
@ -451,10 +449,11 @@ return array(
|
||||||
'Email:' => 'Email:',
|
'Email:' => 'Email:',
|
||||||
'Default project:' => 'Проект по умолчанию:',
|
'Default project:' => 'Проект по умолчанию:',
|
||||||
'Notifications:' => 'Уведомления:',
|
'Notifications:' => 'Уведомления:',
|
||||||
|
'Notifications' => 'Уведомления',
|
||||||
'Group:' => 'Группа:',
|
'Group:' => 'Группа:',
|
||||||
'Regular user' => 'Обычный пользователь',
|
'Regular user' => 'Обычный пользователь',
|
||||||
'Account type:' => 'Тип профиля:',
|
'Account type:' => 'Тип профиля:',
|
||||||
'Edit profile' => 'Редактировать профиль:',
|
'Edit profile' => 'Редактировать профиль',
|
||||||
'Change password' => 'Сменить пароль',
|
'Change password' => 'Сменить пароль',
|
||||||
'Password modification' => 'Изменение пароля',
|
'Password modification' => 'Изменение пароля',
|
||||||
'External authentications' => 'Внешняя аутентификация',
|
'External authentications' => 'Внешняя аутентификация',
|
||||||
|
@ -496,11 +495,67 @@ return array(
|
||||||
'Activity' => 'Активность',
|
'Activity' => 'Активность',
|
||||||
'Default values are "%s"' => 'Колонки по умолчанию: "%s"',
|
'Default values are "%s"' => 'Колонки по умолчанию: "%s"',
|
||||||
'Default columns for new projects (Comma-separated)' => 'Колонки по умолчанию для новых проектов (разделять запятой)',
|
'Default columns for new projects (Comma-separated)' => 'Колонки по умолчанию для новых проектов (разделять запятой)',
|
||||||
// 'Task assignee change' => '',
|
'Task assignee change' => 'Изменен назначенный',
|
||||||
// '%s change the assignee of the task #%d' => '',
|
'%s change the assignee of the task #%d to %s' => '%s сменил назначенного для задачи #%d на %s',
|
||||||
// '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '',
|
'%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to %s' => '%s сменил назначенного для задачи <a href="?controller=task&action=show&task_id=%d">#%d</a> на %s',
|
||||||
// '[%s][Column Change] %s (#%d)' => '',
|
'[%s][Column Change] %s (#%d)' => '[%s][Изменение колонки] %s (#%d)',
|
||||||
// '[%s][Position Change] %s (#%d)' => '',
|
'[%s][Position Change] %s (#%d)' => '[%s][Изменение позиции] %s (#%d)',
|
||||||
// '[%s][Assignee Change] %s (#%d)' => '',
|
'[%s][Assignee Change] %s (#%d)' => '[%s][Изменение назначеного] %s (#%d)',
|
||||||
// 'New password for the user "%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: ярлык проблемы изменен',
|
||||||
|
'Create a task from an external provider' => 'Создать задачу из внешнего источника',
|
||||||
|
'Change the assignee based on an external username' => 'Изменить назначенного основываясь на внешнем имени пользователя',
|
||||||
|
'Change the category based on an external label' => 'Изменить категорию основываясь на внешнем ярлыке',
|
||||||
|
'Reference' => 'Ссылка',
|
||||||
|
'Reference: %s' => 'Ссылка: %s',
|
||||||
|
'Label' => 'Ярлык',
|
||||||
|
'Database' => 'База данных',
|
||||||
|
'About' => 'Информация',
|
||||||
|
'Database driver:' => 'Драйвер базы данных',
|
||||||
|
'Board settings' => 'Настройки доски',
|
||||||
|
'URL and token' => 'URL и токен',
|
||||||
|
'Webhook settings' => 'Параметры Webhook',
|
||||||
|
'URL for task creation:' => 'URL для создания задачи:',
|
||||||
|
'Reset token' => 'Перезагрузить токен',
|
||||||
|
'API endpoint:' => 'API endpoint:',
|
||||||
|
'Refresh interval for private board' => 'Период обновления для частных досок',
|
||||||
|
'Refresh interval for public board' => 'Период обновления для публичных досок',
|
||||||
|
'Task highlight period' => 'Время подсвечивания задачи',
|
||||||
|
'Period (in second) to consider a task was modified recently (0 to disable, 2 days by default)' => 'Период (в секундах) в течении которого задача считается недавно измененной (0 для выключения, 2 дня по умолчанию)',
|
||||||
|
'Frequency in second (60 seconds by default)' => 'Частота в секундах (60 секунд по умолчанию)',
|
||||||
|
'Frequency in second (0 to disable this feature, 10 seconds by default)' => 'Частота в секундах (0 для выключения, 10 секунд по умолчанию)',
|
||||||
|
'Application URL' => 'URL приложения',
|
||||||
|
'Example: http://example.kanboard.net/ (used by email notifications)' => 'Пример: http://example.kanboard.net (используется в email уведомлениях)',
|
||||||
|
'Token regenerated.' => 'Токен пересоздан',
|
||||||
|
'Date format' => 'Формат даты',
|
||||||
|
'ISO format is always accepted, example: "%s" and "%s"' => 'Время должно быть в ISO-формате, например: "%s" или "%s"',
|
||||||
|
'New private project' => 'Новый проект с ограниченным доступом',
|
||||||
|
'This project is private' => 'Это проект с ограниченным доступом',
|
||||||
|
'Type here to create a new sub-task' => 'Печатайте сюда чтобы создать подзадачу',
|
||||||
|
'Add' => 'Добавить',
|
||||||
|
'Estimated time: %s hours' => 'Планируемое время: %s часов',
|
||||||
|
'Time spent: %s hours' => 'Потрачено времени: %s часов',
|
||||||
|
'Started on %B %e, %Y' => 'Начато %B %e, %Y',
|
||||||
|
'Start date' => 'Дата начала',
|
||||||
|
'Time estimated' => 'Планируемое время',
|
||||||
|
'There is nothing assigned to you.' => 'Вам ничего не назначено',
|
||||||
|
'My tasks' => 'Мои задачи',
|
||||||
|
'Activity stream' => 'Текущая активность',
|
||||||
|
'Dashboard' => 'Инфопанель',
|
||||||
|
'Confirmation' => 'Подтверждение пароля',
|
||||||
|
// 'Allow everybody to access to this project' => '',
|
||||||
|
// 'Everybody have access to this project.' => '',
|
||||||
|
// 'Webhooks' => '',
|
||||||
|
// 'API' => '',
|
||||||
|
// 'Integration' => '',
|
||||||
|
// 'Github webhook' => '',
|
||||||
|
// 'Help on Github webhook' => '',
|
||||||
|
// 'Create a comment from an external provider' => '',
|
||||||
|
// 'Github issue comment created' => '',
|
||||||
);
|
);
|
|
@ -83,7 +83,7 @@ return array(
|
||||||
'Settings' => 'Inställningar',
|
'Settings' => 'Inställningar',
|
||||||
'Application settings' => 'Applikationsinställningar',
|
'Application settings' => 'Applikationsinställningar',
|
||||||
'Language' => 'Språk',
|
'Language' => 'Språk',
|
||||||
'Webhooks token:' => 'Token för webhooks:',
|
'Webhook token:' => 'Token för webhooks:',
|
||||||
'API token:' => 'API token:',
|
'API token:' => 'API token:',
|
||||||
'More information' => 'Mer information',
|
'More information' => 'Mer information',
|
||||||
'Database size:' => 'Databasstorlek:',
|
'Database size:' => 'Databasstorlek:',
|
||||||
|
@ -196,7 +196,7 @@ return array(
|
||||||
'revoke' => 'Dra tillbaka behörighet',
|
'revoke' => 'Dra tillbaka behörighet',
|
||||||
'List of authorized users' => 'Lista med behöriga användare',
|
'List of authorized users' => 'Lista med behöriga användare',
|
||||||
'User' => 'Användare',
|
'User' => 'Användare',
|
||||||
'Everybody have access to this project.' => 'Alla har tillgång till detta projekt.',
|
'Nobody have access to this project.' => 'Ingen har tillgång till detta projekt.',
|
||||||
'You are not allowed to access to this project.' => 'Du har inte tillgång till detta projekt.',
|
'You are not allowed to access to this project.' => 'Du har inte tillgång till detta projekt.',
|
||||||
'Comments' => 'Kommentarer',
|
'Comments' => 'Kommentarer',
|
||||||
'Post comment' => 'Ladda upp kommentar',
|
'Post comment' => 'Ladda upp kommentar',
|
||||||
|
@ -209,8 +209,6 @@ return array(
|
||||||
'The description is required' => 'En beskrivning måste lämnas',
|
'The description is required' => 'En beskrivning måste lämnas',
|
||||||
'Edit this task' => 'Ändra denna uppgift',
|
'Edit this task' => 'Ändra denna uppgift',
|
||||||
'Due Date' => 'Måldatum',
|
'Due Date' => 'Måldatum',
|
||||||
'm/d/Y' => 'd/m/Y',
|
|
||||||
'month/day/year' => 'dag/månad/år',
|
|
||||||
'Invalid date' => 'Ej tillåtet datum',
|
'Invalid date' => 'Ej tillåtet datum',
|
||||||
'Must be done before %B %e, %Y' => 'Måste vara klart innan %B %e, %Y',
|
'Must be done before %B %e, %Y' => 'Måste vara klart innan %B %e, %Y',
|
||||||
'%B %e, %Y' => '%d %B %Y',
|
'%B %e, %Y' => '%d %B %Y',
|
||||||
|
@ -351,9 +349,9 @@ return array(
|
||||||
'estimated' => 'uppskattat',
|
'estimated' => 'uppskattat',
|
||||||
'Sub-Tasks' => 'Deluppgifter',
|
'Sub-Tasks' => 'Deluppgifter',
|
||||||
'Add a sub-task' => 'Lägg till deluppgift',
|
'Add a sub-task' => 'Lägg till deluppgift',
|
||||||
'Original Estimate' => 'Ursprunglig uppskattning',
|
'Original estimate' => 'Ursprunglig uppskattning',
|
||||||
'Create another sub-task' => 'Skapa en till deluppgift',
|
'Create another sub-task' => 'Skapa en till deluppgift',
|
||||||
'Time Spent' => 'Nedlagd tid',
|
'Time spent' => 'Nedlagd tid',
|
||||||
'Edit a sub-task' => 'Ändra en deluppgift',
|
'Edit a sub-task' => 'Ändra en deluppgift',
|
||||||
'Remove a sub-task' => 'Ta bort en deluppgift',
|
'Remove a sub-task' => 'Ta bort en deluppgift',
|
||||||
'The time must be a numeric value' => 'Tiden måste ha ett numeriskt värde',
|
'The time must be a numeric value' => 'Tiden måste ha ett numeriskt värde',
|
||||||
|
@ -408,99 +406,156 @@ return array(
|
||||||
'Comment updated' => 'Kommentaren har uppdaterats',
|
'Comment updated' => 'Kommentaren har uppdaterats',
|
||||||
'New comment posted by %s' => 'Ny kommentar postad av %s',
|
'New comment posted by %s' => 'Ny kommentar postad av %s',
|
||||||
'List of due tasks for the project "%s"' => 'Lista med uppgifter för projektet "%s"',
|
'List of due tasks for the project "%s"' => 'Lista med uppgifter för projektet "%s"',
|
||||||
// '[%s][New attachment] %s (#%d)' => '',
|
'[%s][New attachment] %s (#%d)' => '[%s][Ny bifogning] %s (#%d)',
|
||||||
// '[%s][New comment] %s (#%d)' => '',
|
'[%s][New comment] %s (#%d)' => '[%s][Ny kommentar] %s (#%d)',
|
||||||
// '[%s][Comment updated] %s (#%d)' => '',
|
'[%s][Comment updated] %s (#%d)' => '[%s][Uppdaterad kommentar] %s (#%d)',
|
||||||
// '[%s][New subtask] %s (#%d)' => '',
|
'[%s][New subtask] %s (#%d)' => '[%s][Ny deluppgift] %s (#%d)',
|
||||||
// '[%s][Subtask updated] %s (#%d)' => '',
|
'[%s][Subtask updated] %s (#%d)' => '[%s][Deluppgiften uppdaterad] %s (#%d)',
|
||||||
// '[%s][New task] %s (#%d)' => '',
|
'[%s][New task] %s (#%d)' => '[%s][Ny uppgift] %s (#%d)',
|
||||||
// '[%s][Task updated] %s (#%d)' => '',
|
'[%s][Task updated] %s (#%d)' => '[%s][Uppgiften uppdaterad] %s (#%d)',
|
||||||
// '[%s][Task closed] %s (#%d)' => '',
|
'[%s][Task closed] %s (#%d)' => '[%s][Uppgiften stängd] %s (#%d)',
|
||||||
// '[%s][Task opened] %s (#%d)' => '',
|
'[%s][Task opened] %s (#%d)' => '[%s][Uppgiften öppnad] %s (#%d)',
|
||||||
// '[%s][Due tasks]' => '',
|
'[%s][Due tasks]' => '[%s][Förfallen uppgift]',
|
||||||
'[Kanboard] Notification' => '[Kanboard] Notis',
|
'[Kanboard] Notification' => '[Kanboard] Notis',
|
||||||
'I want to receive notifications only for those projects:' => 'Jag vill endast få notiser för dessa projekt:',
|
'I want to receive notifications only for those projects:' => 'Jag vill endast få notiser för dessa projekt:',
|
||||||
'view the task on Kanboard' => 'Visa uppgiften på Kanboard',
|
'view the task on Kanboard' => 'Visa uppgiften på Kanboard',
|
||||||
// 'Public access' => '',
|
'Public access' => 'Publik åtkomst',
|
||||||
// 'Categories management' => '',
|
'Category management' => 'Hantera kategorier',
|
||||||
// 'Users management' => '',
|
'User management' => 'Hantera användare',
|
||||||
// 'Active tasks' => '',
|
'Active tasks' => 'Aktiva uppgifter',
|
||||||
// 'Disable public access' => '',
|
'Disable public access' => 'Inaktivera publik åtkomst',
|
||||||
// 'Enable public access' => '',
|
'Enable public access' => 'Aktivera publik åtkomst',
|
||||||
// 'Active projects' => '',
|
'Active projects' => 'Aktiva projekt',
|
||||||
// 'Inactive projects' => '',
|
'Inactive projects' => 'Inaktiva projekt',
|
||||||
// 'Public access disabled' => '',
|
'Public access disabled' => 'Publik åtkomst har inaktiverats',
|
||||||
// 'Do you really want to disable this project: "%s"?' => '',
|
'Do you really want to disable this project: "%s"?' => 'Vill du verkligen inaktivera detta projekt: "%s"?',
|
||||||
// 'Do you really want to duplicate this project: "%s"?' => '',
|
'Do you really want to duplicate this project: "%s"?' => 'Vill du verkligen kopiera detta projekt: "%s"?',
|
||||||
// 'Do you really want to enable this project: "%s"?' => '',
|
'Do you really want to enable this project: "%s"?' => 'Vill du verkligen aktivera detta projekt: "%s"?',
|
||||||
// 'Project activation' => '',
|
'Project activation' => 'Projektaktivering',
|
||||||
// 'Move the task to another project' => '',
|
'Move the task to another project' => 'Flytta uppgiften till ett annat projekt',
|
||||||
// 'Move to another project' => '',
|
'Move to another project' => 'Flytta till ett annat projekt',
|
||||||
// 'Do you really want to duplicate this task?' => '',
|
'Do you really want to duplicate this task?' => 'Vill du verkligen kopiera denna uppgift?',
|
||||||
// 'Duplicate a task' => '',
|
'Duplicate a task' => 'Kopiera en uppgift',
|
||||||
// 'External accounts' => '',
|
'External accounts' => 'Externa konton',
|
||||||
// 'Account type' => '',
|
'Account type' => 'Kontotyp',
|
||||||
// 'Local' => '',
|
'Local' => 'Lokal',
|
||||||
// 'Remote' => '',
|
'Remote' => 'Fjärr',
|
||||||
// 'Enabled' => '',
|
'Enabled' => 'Aktiverad',
|
||||||
// 'Disabled' => '',
|
'Disabled' => 'Inaktiverad',
|
||||||
// 'Google account linked' => '',
|
'Google account linked' => 'Googlekonto länkat',
|
||||||
// 'Github account linked' => '',
|
'Github account linked' => 'Githubkonto länkat',
|
||||||
// 'Username:' => '',
|
'Username:' => 'Användarnam:',
|
||||||
// 'Name:' => '',
|
'Name:' => 'Namn:',
|
||||||
// 'Email:' => '',
|
'Email:' => 'E-post:',
|
||||||
// 'Default project:' => '',
|
'Default project:' => 'Standardprojekt',
|
||||||
// 'Notifications:' => '',
|
'Notifications:' => 'Notiser:',
|
||||||
// 'Group:' => '',
|
'Notifications' => 'Notiser',
|
||||||
// 'Regular user' => '',
|
'Group:' => 'Grupp:',
|
||||||
// 'Account type:' => '',
|
'Regular user' => 'Normal användare',
|
||||||
// 'Edit profile' => '',
|
'Account type:' => 'Kontotyp:',
|
||||||
// 'Change password' => '',
|
'Edit profile' => 'Ändra profil',
|
||||||
// 'Password modification' => '',
|
'Change password' => 'Byt lösenord',
|
||||||
// 'External authentications' => '',
|
'Password modification' => 'Ändra lösenord',
|
||||||
// 'Google Account' => '',
|
'External authentications' => 'Extern autentisering',
|
||||||
// 'Github Account' => '',
|
'Google Account' => 'Googlekonto',
|
||||||
// 'Never connected.' => '',
|
'Github Account' => 'Githubkonto',
|
||||||
// 'No account linked.' => '',
|
'Never connected.' => 'Inte ansluten.',
|
||||||
// 'Account linked.' => '',
|
'No account linked.' => 'Inget konto länkat.',
|
||||||
// 'No external authentication enabled.' => '',
|
'Account linked.' => 'Konto länkat.',
|
||||||
// 'Password modified successfully.' => '',
|
'No external authentication enabled.' => 'Ingen extern autentisering aktiverad.',
|
||||||
// 'Unable to change the password.' => '',
|
'Password modified successfully.' => 'Lösenordet har ändrats.',
|
||||||
// 'Change category for the task "%s"' => '',
|
'Unable to change the password.' => 'Kunde inte byta lösenord.',
|
||||||
// 'Change category' => '',
|
'Change category for the task "%s"' => 'Byt kategori för uppgiften "%s"',
|
||||||
// '%s updated the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '',
|
'Change category' => 'Byt kategori',
|
||||||
// '%s open the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '',
|
'%s updated the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s uppdaterade uppgiften <a href="?controller=task&action=show&task_id=%d">#%d</a>',
|
||||||
// '%s moved the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to the position #%d in the column "%s"' => '',
|
'%s open the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s öppna uppgiften <a href="?controller=task&action=show&task_id=%d">#%d</a>',
|
||||||
// '%s moved the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to the column "%s"' => '',
|
'%s moved the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to the position #%d in the column "%s"' => '%s flyttade uppgiften <a href="?controller=task&action=show&task_id=%d">#%d</a> till positionen #%d i kolumnen "%s"',
|
||||||
// '%s created the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '',
|
'%s moved the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to the column "%s"' => '%s flyttade uppgiften <a href="?controller=task&action=show&task_id=%d">#%d</a> till kolumnen "%s"',
|
||||||
// '%s closed the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '',
|
'%s created the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s skapade uppgiften <a href="?controller=task&action=show&task_id=%d">#%d</a>',
|
||||||
// '%s created a subtask for the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '',
|
'%s closed the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s stängde uppgiften <a href="?controller=task&action=show&task_id=%d">#%d</a>',
|
||||||
// '%s updated a subtask for the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '',
|
'%s created a subtask for the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s skapade en deluppgift för uppgiften <a href="?controller=task&action=show&task_id=%d">#%d</a>',
|
||||||
// 'Assigned to %s with an estimate of %s/%sh' => '',
|
'%s updated a subtask for the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s uppdaterade en deluppgift för uppgiften <a href="?controller=task&action=show&task_id=%d">#%d</a>',
|
||||||
// 'Not assigned, estimate of %sh' => '',
|
'Assigned to %s with an estimate of %s/%sh' => 'Tilldelades %s med en uppskattning på %s/%sh',
|
||||||
// '%s updated a comment on the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '',
|
'Not assigned, estimate of %sh' => 'Inte tilldelade, uppskattat %sh',
|
||||||
// '%s commented the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '',
|
'%s updated a comment on the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s uppdaterade en kommentar till uppgiften <a href="?controller=task&action=show&task_id=%d">#%d</a>',
|
||||||
// '%s\'s activity' => '',
|
'%s commented the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s kommenterade uppgiften <a href="?controller=task&action=show&task_id=%d">#%d</a>',
|
||||||
// 'No activity.' => '',
|
'%s\'s activity' => '%s\'s aktivitet',
|
||||||
// 'RSS feed' => '',
|
'No activity.' => 'Ingen aktivitet.',
|
||||||
// '%s updated a comment on the task #%d' => '',
|
'RSS feed' => 'RSS flöde',
|
||||||
// '%s commented on the task #%d' => '',
|
'%s updated a comment on the task #%d' => '%s uppdaterade en kommentar på uppgiften #%d',
|
||||||
// '%s updated a subtask for the task #%d' => '',
|
'%s commented on the task #%d' => '%s kommenterade uppgiften #%d',
|
||||||
// '%s created a subtask for the task #%d' => '',
|
'%s updated a subtask for the task #%d' => '%s uppdaterade en deluppgift för uppgiften #%d',
|
||||||
// '%s updated the task #%d' => '',
|
'%s created a subtask for the task #%d' => '%s skapade en deluppgift för uppgiften #%d',
|
||||||
// '%s created the task #%d' => '',
|
'%s updated the task #%d' => '%s uppdaterade uppgiften #%d',
|
||||||
// '%s closed the task #%d' => '',
|
'%s created the task #%d' => '%s skapade uppgiften #%d',
|
||||||
// '%s open the task #%d' => '',
|
'%s closed the task #%d' => '%s stängde uppgiften #%d',
|
||||||
// '%s moved the task #%d to the column "%s"' => '',
|
'%s open the task #%d' => '%s öppnade uppgiften #%d',
|
||||||
// '%s moved the task #%d to the position %d in the column "%s"' => '',
|
'%s moved the task #%d to the column "%s"' => '%s flyttade uppgiften #%d till kolumnen "%s"',
|
||||||
// 'Activity' => '',
|
'%s moved the task #%d to the position %d in the column "%s"' => '%s flyttade uppgiften #%d till positionen %d i kolumnen "%s"',
|
||||||
// 'Default values are "%s"' => '',
|
'Activity' => 'Aktivitet',
|
||||||
// 'Default columns for new projects (Comma-separated)' => '',
|
'Default values are "%s"' => 'Standardvärden är "%s"',
|
||||||
// 'Task assignee change' => '',
|
'Default columns for new projects (Comma-separated)' => 'Standardkolumner för nya projekt (kommaseparerade)',
|
||||||
// '%s change the assignee of the task #%d' => '',
|
'Task assignee change' => 'Ändra tilldelning av uppgiften',
|
||||||
// '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '',
|
'%s change the assignee of the task #%d to %s' => '%s byt tilldelning av uppgiften #%d till %s',
|
||||||
// '[%s][Column Change] %s (#%d)' => '',
|
'%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to %s' => '%s byt tilldelning av uppgiften <a href="?controller=task&action=show&task_id=%d">#%d</a> till %s',
|
||||||
// '[%s][Position Change] %s (#%d)' => '',
|
'[%s][Column Change] %s (#%d)' => '[%s][Byt kolumn] %s (#%d)',
|
||||||
// '[%s][Assignee Change] %s (#%d)' => '',
|
'[%s][Position Change] %s (#%d)' => '[%s][Byt position] %s (#%d)',
|
||||||
// 'New password for the user "%s"' => '',
|
'[%s][Assignee Change] %s (#%d)' => '[%s][Byt tilldelning] %s (#%d)',
|
||||||
|
'New password for the user "%s"' => 'Nytt lösenord för användaren "%s"',
|
||||||
|
'Choose an event' => 'Välj en händelse',
|
||||||
|
'Github commit received' => 'Github-bidrag mottaget',
|
||||||
|
'Github issue opened' => 'Github-fråga öppnad',
|
||||||
|
'Github issue closed' => 'Github-fråga stängd',
|
||||||
|
'Github issue reopened' => 'Github-fråga öppnad på nytt',
|
||||||
|
'Github issue assignee change' => 'Github-fråga ny tilldelning',
|
||||||
|
'Github issue label change' => 'Github-fråga etikettförändring',
|
||||||
|
'Create a task from an external provider' => 'Skapa en uppgift från en extern leverantör',
|
||||||
|
'Change the assignee based on an external username' => 'Ändra tilldelning baserat på ett externt användarnamn',
|
||||||
|
'Change the category based on an external label' => 'Ändra kategori baserat på en extern etikett',
|
||||||
|
'Reference' => 'Referens',
|
||||||
|
'Reference: %s' => 'Referens: %s',
|
||||||
|
'Label' => 'Etikett',
|
||||||
|
'Database' => 'Databas',
|
||||||
|
'About' => 'Om',
|
||||||
|
'Database driver:' => 'Databasdrivrutin:',
|
||||||
|
'Board settings' => 'Inställningar för tavla',
|
||||||
|
'URL and token' => 'URL och token',
|
||||||
|
'Webhook settings' => 'Webhook inställningar',
|
||||||
|
'URL for task creation:' => 'URL för att skapa uppgift:',
|
||||||
|
'Reset token' => 'Nollställ token',
|
||||||
|
'API endpoint:' => 'API ändpunkt:',
|
||||||
|
'Refresh interval for private board' => 'Uppdateringsintervall för privat tavla',
|
||||||
|
'Refresh interval for public board' => 'Uppdateringsintervall för publik tavla',
|
||||||
|
'Task highlight period' => 'Period att framhäva ny uppgift',
|
||||||
|
'Period (in second) to consider a task was modified recently (0 to disable, 2 days by default)' => 'Period (i sekunder) att betrakta en uppgifts ändring som ny (ange 0 för att inaktivera, 2 dagar är standard)',
|
||||||
|
'Frequency in second (60 seconds by default)' => 'Frekvens i sekunder (60 sekunder är standard)',
|
||||||
|
'Frequency in second (0 to disable this feature, 10 seconds by default)' => 'Frekvens i sekunder (ange 0 för att inaktivera, 10 sekunder är standard)',
|
||||||
|
'Application URL' => 'Applikations-URL',
|
||||||
|
'Example: http://example.kanboard.net/ (used by email notifications)' => 'Exempel: http://example.kanboard.net/ (används för e-postnotiser)',
|
||||||
|
'Token regenerated.' => 'Token nyskapad.',
|
||||||
|
'Date format' => 'Datumformat',
|
||||||
|
'ISO format is always accepted, example: "%s" and "%s"' => 'ISO-format är alltid tillåtet, exempel: "%s" och "%s"',
|
||||||
|
'New private project' => 'Nytt privat projekt',
|
||||||
|
'This project is private' => 'Det här projektet är privat',
|
||||||
|
'Type here to create a new sub-task' => 'Skriv här för att skapa en ny deluppgift',
|
||||||
|
'Add' => 'Lägg till',
|
||||||
|
'Estimated time: %s hours' => 'Uppskattad tid: %s timmar',
|
||||||
|
'Time spent: %s hours' => 'Nedlaggd tid: %s timmar',
|
||||||
|
'Started on %B %e, %Y' => 'Startad den %B %e, %Y',
|
||||||
|
'Start date' => 'Startdatum',
|
||||||
|
'Time estimated' => 'Uppskattad tid',
|
||||||
|
'There is nothing assigned to you.' => 'Du har inget tilldelat till dig.',
|
||||||
|
'My tasks' => 'Mina uppgifte',
|
||||||
|
'Activity stream' => 'Aktivitetsström',
|
||||||
|
'Dashboard' => 'Instrumentpanel',
|
||||||
|
'Confirmation' => 'Bekräftelse',
|
||||||
|
// 'Allow everybody to access to this project' => '',
|
||||||
|
// 'Everybody have access to this project.' => '',
|
||||||
|
// 'Webhooks' => '',
|
||||||
|
// 'API' => '',
|
||||||
|
// 'Integration' => '',
|
||||||
|
// 'Github webhook' => '',
|
||||||
|
// 'Help on Github webhook' => '',
|
||||||
|
// 'Create a comment from an external provider' => '',
|
||||||
|
// 'Github issue comment created' => '',
|
||||||
);
|
);
|
561
sources/app/Locale/th_TH/translations.php
Normal file
561
sources/app/Locale/th_TH/translations.php
Normal file
|
@ -0,0 +1,561 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'None' => 'ไม่มี',
|
||||||
|
'edit' => 'แก้ไข',
|
||||||
|
'Edit' => 'แก้ไข',
|
||||||
|
'remove' => 'ลบ',
|
||||||
|
'Remove' => 'ลบ',
|
||||||
|
'Update' => 'ปรับปรุง',
|
||||||
|
'Yes' => 'ใช่',
|
||||||
|
'No' => 'ไม่',
|
||||||
|
'cancel' => 'ยกเลิก',
|
||||||
|
'or' => 'หรือ',
|
||||||
|
'Yellow' => 'สีเหลือง',
|
||||||
|
'Blue' => 'สีน้ำเงิน',
|
||||||
|
'Green' => 'สีเขียว',
|
||||||
|
'Purple' => 'สีม่วง',
|
||||||
|
'Red' => 'สีแดง',
|
||||||
|
'Orange' => 'สีส้ม',
|
||||||
|
'Grey' => 'สีเทา',
|
||||||
|
'Save' => 'บันทึก',
|
||||||
|
'Login' => 'เข้าสู่ระบบ',
|
||||||
|
'Official website:' => 'เวบไซต์อย่างเป็นทางการ:',
|
||||||
|
'Unassigned' => 'ไม่กำหนด',
|
||||||
|
'View this task' => 'รายละเอียดงานนี้',
|
||||||
|
'Remove user' => 'เอาผู้ใช้ออก',
|
||||||
|
'Do you really want to remove this user: "%s"?' => 'คุณต้องการเอาผู้ใช้ « %s » ออกใช่หรือไม่?',
|
||||||
|
'New user' => 'ผู้ใช้ใหม่',
|
||||||
|
'All users' => 'ผู้ใช้ทั้งหมด',
|
||||||
|
'Username' => 'ชื่อผู้ใช้',
|
||||||
|
'Password' => 'รหัสผ่าน',
|
||||||
|
'Default project' => 'โปรเจคเริ่มต้น',
|
||||||
|
'Administrator' => 'ผู้ดูแลระบบ',
|
||||||
|
'Sign in' => 'เข้าสู่ระบบ',
|
||||||
|
'Users' => 'ผู้ใช้',
|
||||||
|
'No user' => 'ไม่มีผู้ใช้',
|
||||||
|
'Forbidden' => 'ไม่อนุญาติ',
|
||||||
|
'Access Forbidden' => 'ไม่อนุญาติให้เข้า',
|
||||||
|
'Only administrators can access to this page.' => 'หน้าสำหรับผู้ดูแลระบบเท่านั้น',
|
||||||
|
'Edit user' => 'แก้ไขผู้ใช้',
|
||||||
|
'Logout' => 'ออกจากระบบ',
|
||||||
|
'Bad username or password' => 'ชื่อผู้ใช่หรือรหัสผ่านผิด',
|
||||||
|
'users' => 'ผู้ใช้',
|
||||||
|
'projects' => 'โปรเจค',
|
||||||
|
'Edit project' => 'แก้ไขโปรเจค',
|
||||||
|
'Name' => 'ชื่อ',
|
||||||
|
'Activated' => 'เปิดใช้งาน',
|
||||||
|
'Projects' => 'โปรเจค',
|
||||||
|
'No project' => 'ไม่มีโปรเจค',
|
||||||
|
'Project' => 'โปรเจค',
|
||||||
|
'Status' => 'สถานะ',
|
||||||
|
'Tasks' => 'งาน',
|
||||||
|
'Board' => 'บอร์ด',
|
||||||
|
'Actions' => 'การกระทำ',
|
||||||
|
'Inactive' => 'ไม่เปิดใช้งาน',
|
||||||
|
'Active' => 'เปิดใช้งาน',
|
||||||
|
'Column %d' => 'คอลัมน์ %d',
|
||||||
|
'Add this column' => 'เพิ่มคอลัมน์',
|
||||||
|
'%d tasks on the board' => '%d งานบนบอร์ด',
|
||||||
|
'%d tasks in total' => '%d งานทั้งหมด',
|
||||||
|
'Unable to update this board.' => 'ไม่สามารถปรับปรุงบอร์ดได้.',
|
||||||
|
'Edit board' => 'แก้ไขบอร์ด',
|
||||||
|
'Disable' => 'ปิด',
|
||||||
|
'Enable' => 'เปิด',
|
||||||
|
'New project' => 'โปรเจคใหม่',
|
||||||
|
'Do you really want to remove this project: "%s"?' => 'คุณต้องการเอาโปรเจค « %s » ออกใช่หรือไม่?',
|
||||||
|
'Remove project' => 'ลบโปรเจค',
|
||||||
|
'Boards' => 'บอร์ด',
|
||||||
|
'Edit the board for "%s"' => 'แก้ไขบอร์ดสำหรับ « %s »',
|
||||||
|
'All projects' => 'โปรเจคทั้งหมด',
|
||||||
|
'Change columns' => 'เปลี่ยนคอลัมน์',
|
||||||
|
'Add a new column' => 'เพิ่มคอลัมน์ใหม่',
|
||||||
|
'Title' => 'หัวเรื่อง',
|
||||||
|
'Add Column' => 'เพิ่มคอลัมน์',
|
||||||
|
'Project "%s"' => 'โปรเจค « %s »',
|
||||||
|
'Nobody assigned' => 'ไม่กำหนดใคร',
|
||||||
|
'Assigned to %s' => 'กำหนดให้ %s',
|
||||||
|
'Remove a column' => 'ลบคอลัมน์',
|
||||||
|
'Remove a column from a board' => 'ลบคอลัมน์ออกจากบอร์ด',
|
||||||
|
'Unable to remove this column.' => 'ไม่สามารถลบคอลัมน์นี้',
|
||||||
|
'Do you really want to remove this column: "%s"?' => 'คุณต้องการลบคอลัมน์ « %s » ออกใช่หรือไม่?',
|
||||||
|
'This action will REMOVE ALL TASKS associated to this column!' => 'การกระทำนี้จะลบงานที่เกี่ยวข้องกับคอลัมน์นี้',
|
||||||
|
'Settings' => 'ตั้งค่า',
|
||||||
|
'Application settings' => 'ตั้งค่าการทำงาน',
|
||||||
|
'Language' => 'ภาษา',
|
||||||
|
// 'Webhook token:' => '',
|
||||||
|
'API token:' => 'API token:',
|
||||||
|
'More information' => 'ข้อมูลเพิ่มเติม',
|
||||||
|
'Database size:' => 'ขนาดฐานข้อมูล:',
|
||||||
|
'Download the database' => 'ดาวน์โหลดฐานข้อมูล',
|
||||||
|
'Optimize the database' => 'ปรับปรุงฐานข้อมูล',
|
||||||
|
'(VACUUM command)' => '(VACUUM command)',
|
||||||
|
'(Gzip compressed Sqlite file)' => '(Gzip compressed Sqlite file)',
|
||||||
|
'User settings' => 'ตั้งค่าผู้ใช้',
|
||||||
|
'My default project:' => 'โปรเจคเริ่มต้นของฉัน:',
|
||||||
|
'Close a task' => 'ปิดงาน',
|
||||||
|
'Do you really want to close this task: "%s"?' => 'คุณต้องการปิดงาน « %s » ใช่หรือไม่?',
|
||||||
|
'Edit a task' => 'แก้ไขงาน',
|
||||||
|
'Column' => 'คอลัมน์',
|
||||||
|
'Color' => 'สี',
|
||||||
|
'Assignee' => 'กำหนดให้',
|
||||||
|
'Create another task' => 'สร้างงานอื่น',
|
||||||
|
'New task' => 'งานใหม่',
|
||||||
|
'Open a task' => 'เปิดงาน',
|
||||||
|
'Do you really want to open this task: "%s"?' => 'คุณต้องการเปิดงาน: « %s » ใช่หรือไม่?',
|
||||||
|
'Back to the board' => 'กลับไปที่บอร์ด',
|
||||||
|
'Created on %B %e, %Y at %k:%M %p' => 'สร้างวันที่ %d/%m/%Y เวลา %H:%M',
|
||||||
|
'There is nobody assigned' => 'ไม่มีใครถูกกำหนด',
|
||||||
|
'Column on the board:' => 'คอลัมน์บนบอร์ด:',
|
||||||
|
'Status is open' => 'สถานะเปิด',
|
||||||
|
'Status is closed' => 'สถานะปิด',
|
||||||
|
'Close this task' => 'ปิดงานนี้',
|
||||||
|
'Open this task' => 'เปิดงานนี้',
|
||||||
|
'There is no description.' => 'ไม่มีคำอธิบาย',
|
||||||
|
'Add a new task' => 'เพิ่มงานใหม่',
|
||||||
|
'The username is required' => 'ต้องการชื่อผู้ใช้',
|
||||||
|
'The maximum length is %d characters' => 'จำนวนตัวอักษรสูงสุด %d ตัวอักษร',
|
||||||
|
'The minimum length is %d characters' => 'จำนวนตัวอักษรน้อยสุด %d ตัวอักษร',
|
||||||
|
'The password is required' => 'ต้องการรหัสผ่าน',
|
||||||
|
'This value must be an integer' => 'ต้องเป็นตัวเลข',
|
||||||
|
'The username must be unique' => 'ชื่อผู้ใช้ต้องไม่ซ้ำ',
|
||||||
|
'The username must be alphanumeric' => 'ชื่อผู้ใช้ต้องเป็นตัวอักษรหรือตัวเลข',
|
||||||
|
'The user id is required' => 'ต้องการไอดีผู้ใช้',
|
||||||
|
'Passwords don\'t match' => 'รหัสผ่านไม่ถูกต้อง',
|
||||||
|
'The confirmation is required' => 'ต้องการการยืนยัน',
|
||||||
|
'The column is required' => 'ต้องการคอลัมน์',
|
||||||
|
'The project is required' => 'ต้องการโปรเจค',
|
||||||
|
'The color is required' => 'ต้องการสี',
|
||||||
|
'The id is required' => 'ต้องการไอดี',
|
||||||
|
'The project id is required' => 'ต้องการไอดีโปรเจค',
|
||||||
|
'The project name is required' => 'ต้องการชื่อโปรเจค',
|
||||||
|
'This project must be unique' => 'ชื่อโปรเจคต้องไม่ซ้ำ',
|
||||||
|
'The title is required' => 'ต้องการหัวเรื่อง',
|
||||||
|
'The language 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.' => 'ปรับปรุงฐานข้อมูลเรียบร้อยแล้ว',
|
||||||
|
'Your project have been created successfully.' => 'สร้างโปรเจคเรียบร้อยแล้ว',
|
||||||
|
'Unable to create your project.' => 'ไม่สามารถสร้างโปรเจคได้',
|
||||||
|
'Project updated successfully.' => 'ปรับปรุงโปรเจคเรียบร้อยแล้ว',
|
||||||
|
'Unable to update this project.' => 'ไม่สามารถปรับปรุงโปรเจคได้',
|
||||||
|
'Unable to remove this project.' => 'ไม่สามารถลบโปรเจคได้',
|
||||||
|
'Project removed successfully.' => 'ลบโปรเจคเรียบร้อยแล้ว',
|
||||||
|
'Project activated successfully.' => 'เปิดใช้งานโปรเจคเรียบร้อยแล้ว',
|
||||||
|
'Unable to activate this project.' => 'ไม่สามารถเปิดใช้งานโปรเจคได้',
|
||||||
|
'Project disabled successfully.' => 'ปิดโปรเจคเรียบร้อยแล้ว',
|
||||||
|
'Unable to disable this project.' => 'ไม่สามารถปิดโปรเจคได้',
|
||||||
|
'Unable to open this task.' => 'ไม่สามารถเปิดงานนี้',
|
||||||
|
'Task opened successfully.' => 'เปิดงานเรียบร้อยแล้ว',
|
||||||
|
'Unable to close this task.' => 'ไม่สามารถปิดงานนี้',
|
||||||
|
'Task closed successfully.' => 'ปิดงานเรียบร้อยแล้ว',
|
||||||
|
'Unable to update your task.' => 'ไม่สามารถปรับปรุงงานได้',
|
||||||
|
'Task updated successfully.' => 'ปรับปรุงงานเรียบร้อยแล้ว',
|
||||||
|
'Unable to create your task.' => 'ไม่สามารถสร้างงานได้',
|
||||||
|
'Task created successfully.' => 'สร้างงานเรียบร้อยแล้ว',
|
||||||
|
'User created successfully.' => 'สร้างผู้ใช้เรียบร้อยแล้ว',
|
||||||
|
'Unable to create your user.' => 'ไม่สามารถสร้างผู้ใช้ได้',
|
||||||
|
'User updated successfully.' => 'ปรับปรุงผู้ใช้เรียบร้อยแล้ว',
|
||||||
|
'Unable to update your user.' => 'ไม่สามารถปรับปรุงผู้ใช้ได้',
|
||||||
|
'User removed successfully.' => 'ลบผู้ใช้เรียบร้อยแล้ว',
|
||||||
|
'Unable to remove this user.' => 'ไม่สามารถลบผู้ใช้ได้',
|
||||||
|
'Board updated successfully.' => 'ปรับปรุงบอร์ดเรียบร้อยแล้ว',
|
||||||
|
'Ready' => 'พร้อม',
|
||||||
|
'Backlog' => 'งานค้าง',
|
||||||
|
'Work in progress' => 'กำลังทำ',
|
||||||
|
'Done' => 'เสร็จ',
|
||||||
|
'Application version:' => 'แอพเวอร์ชัน:',
|
||||||
|
'Completed on %B %e, %Y at %k:%M %p' => 'เรียบร้อยวันที่ %d/%m/%Y เวลา %H:%M',
|
||||||
|
'%B %e, %Y at %k:%M %p' => '%d/%m/%Y เวลา %H:%M',
|
||||||
|
'Date created' => 'สร้างวันที่',
|
||||||
|
'Date completed' => 'เรียบร้อยวันที่',
|
||||||
|
'Id' => 'ไอดี',
|
||||||
|
'No task' => 'ไม่มีงาน',
|
||||||
|
'Completed tasks' => 'งานที่เสร็จแล้ว',
|
||||||
|
'List of projects' => 'รายชื่อโปรเจค',
|
||||||
|
'Completed tasks for "%s"' => 'งานที่เสร็จแล้วสำหรับ « %s »',
|
||||||
|
'%d closed tasks' => '%d งานที่ปิด',
|
||||||
|
'No task for this project' => 'ไม่มีงานสำหรับโปรเจคนี้',
|
||||||
|
'Public link' => 'ลิงค์สาธารณะ',
|
||||||
|
'There is no column in your project!' => 'ไม่มีคอลัมน์ในโปรเจคของคุณ',
|
||||||
|
'Change assignee' => 'เปลี่ยนการกำหนด',
|
||||||
|
'Change assignee for the task "%s"' => 'เปลี่ยนการกำหนดสำหรับงาน « %s »',
|
||||||
|
'Timezone' => 'เขตเวลา',
|
||||||
|
'Sorry, I didn\'t found this information in my database!' => 'เสียใจด้วย ไม่สามารถหาข้อมูลในฐานข้อมูลได้',
|
||||||
|
'Page not found' => 'ไม่พบหน้า',
|
||||||
|
'Complexity' => 'ความซับซ้อน',
|
||||||
|
'limit' => 'จำกัด',
|
||||||
|
'Task limit' => 'จำกัดงาน',
|
||||||
|
'This value must be greater than %d' => 'ค่าต้องมากกว่า %d',
|
||||||
|
'Edit project access list' => 'แก้ไขการเข้าถึงรายชื่อโปรเจค',
|
||||||
|
'Edit users access' => 'แก้ไขการเข้าถึงผู้ใช้',
|
||||||
|
'Allow this user' => 'อนุญาตผู้ใช้นี้',
|
||||||
|
'Only those users have access to this project:' => 'ผู้ใช้ที่สามารถเข้าถึงโปรเจคนี้:',
|
||||||
|
'Don\'t forget that administrators have access to everything.' => 'อย่าลืมผู้ดูแลระบบสามารถเข้าถึงได้ทุกอย่าง',
|
||||||
|
'revoke' => 'ยกเลิก',
|
||||||
|
'List of authorized users' => 'รายชื่อผู้ใช้ที่ได้รับการยืนยัน',
|
||||||
|
'User' => 'ผู้ใช้',
|
||||||
|
// 'Nobody have access to this project.' => '',
|
||||||
|
'You are not allowed to access to this project.' => 'คุณไม่ได้รับอนุญาตให้เข้าถึงโปรเจคนี้',
|
||||||
|
'Comments' => 'ความคิดเห็น',
|
||||||
|
'Post comment' => 'แสดงความคิดเห็น',
|
||||||
|
'Write your text in Markdown' => 'เขียนข้อความในรูปแบบ Markdown',
|
||||||
|
'Leave a comment' => 'ออกความคิดเห็น',
|
||||||
|
'Comment is required' => 'ต้องการความคิดเห็น',
|
||||||
|
'Leave a description' => 'แสดงคำอธิบาย',
|
||||||
|
'Comment added successfully.' => 'เพิ่มความคิดเห็นเรียบร้อยแล้ว',
|
||||||
|
'Unable to create your comment.' => 'ไม่สามารถสร้างความคิดเห็น',
|
||||||
|
'The description is required' => 'ต้องการคำอธิบาย',
|
||||||
|
'Edit this task' => 'แก้ไขงาน',
|
||||||
|
'Due Date' => 'วันที่ครบกำหนด',
|
||||||
|
'Invalid date' => 'วันที่ผิด',
|
||||||
|
'Must be done before %B %e, %Y' => 'ต้องทำให้เสร็จก่อน %d/%m/%Y',
|
||||||
|
'%B %e, %Y' => '%d/%m/%Y',
|
||||||
|
'Automatic actions' => 'การกระทำอัตโนมัติ',
|
||||||
|
'Your automatic action have been created successfully.' => 'การกระทำอัตโนมัติสร้างเรียบร้อยแล้ว',
|
||||||
|
'Unable to create your automatic action.' => 'ไม่สามารถสร้างการกระทำอัตโนมัติได้',
|
||||||
|
'Remove an action' => 'ลบการกระทำ',
|
||||||
|
'Unable to remove this action.' => 'ไม่สามารถลบการกระทำ',
|
||||||
|
'Action removed successfully.' => 'ลบการกระทำเรียบร้อยแล้ว',
|
||||||
|
'Automatic actions for the project "%s"' => 'การกระทำอัตโนมัติสำหรับโปรเจค « %s »',
|
||||||
|
'Defined actions' => 'กำหนดการกระทำ',
|
||||||
|
'Add an action' => 'เพิ่มการกระทำ',
|
||||||
|
'Event name' => 'ชื่อเหตุกาณ์',
|
||||||
|
'Action name' => 'ชื่อการกระทำ',
|
||||||
|
'Action parameters' => 'พารามิเตอร์ของการกระทำ',
|
||||||
|
'Action' => 'การกระทำ',
|
||||||
|
'Event' => 'เหตุการณ์',
|
||||||
|
'When the selected event occurs execute the corresponding action.' => 'เหตุการ์ที่เลือกจะเกิดขึ้นเมื่อมีการกระทำที่สอดคล้องกัน',
|
||||||
|
'Next step' => 'ขั้นตอนต่อไป',
|
||||||
|
'Define action parameters' => 'กำหนดพารามิเตอร์ของการกระทำ',
|
||||||
|
'Save this action' => 'บันทึกการกระทำนี้',
|
||||||
|
'Do you really want to remove this action: "%s"?' => 'คุณต้องการลบการกระทำ « %s » ใช่หรือไม่?',
|
||||||
|
'Remove an automatic action' => 'ลบการกระทำอัตโนมัติ',
|
||||||
|
'Close the task' => 'ปิดงาน',
|
||||||
|
'Assign the task to a specific user' => 'กำหนดงานให้ผู้ใช้แบบเจาะจง',
|
||||||
|
'Assign the task to the person who does the action' => 'กำหนดงานให้ผู้ใช้งานปัจจุบัน',
|
||||||
|
'Duplicate the task to another project' => 'ทำซ้ำงานนี้ในโปรเจคอื่น',
|
||||||
|
'Move a task to another column' => 'ย้ายงานไปคอลัมน์อื่น',
|
||||||
|
'Move a task to another position in the same column' => 'ย้ายงานไปตำแหน่งอื่นในคอลัมน์เดียวกัน',
|
||||||
|
'Task modification' => 'แก้ไขงาน',
|
||||||
|
'Task creation' => 'สร้างงาน',
|
||||||
|
'Open a closed task' => 'เปิดงานที่ปิดอยู่',
|
||||||
|
'Closing a task' => 'กำลังปิดงาน',
|
||||||
|
'Assign a color to a specific user' => 'กำหนดสีให้ผู้ใช้แบบเจาะจง',
|
||||||
|
'Column title' => 'หัวเรื่องคอลัมน์',
|
||||||
|
'Position' => 'ตำแหน่ง',
|
||||||
|
'Move Up' => 'ย้ายขึ้น',
|
||||||
|
'Move Down' => 'ย้ายลง',
|
||||||
|
'Duplicate to another project' => 'ทำซ้ำในโปรเจคอื่น',
|
||||||
|
'Duplicate' => 'ทำซ้ำ',
|
||||||
|
'link' => 'ลิงค์',
|
||||||
|
'Update this comment' => 'ปรับปรุงความคิดเห็นนี้',
|
||||||
|
'Comment updated successfully.' => 'ปรับปรุงความคิดเห็นเรียบร้อยแล้ว',
|
||||||
|
'Unable to update your comment.' => 'ไม่สามารถปรับปรุงความคิดเห็นได้',
|
||||||
|
'Remove a comment' => 'ลบความคิดเห็น',
|
||||||
|
'Comment removed successfully.' => 'ลบความคิดเห็นเรียบร้อยแล้ว',
|
||||||
|
'Unable to remove this comment.' => 'ไม่สามารถลบความคิดเห็นได้',
|
||||||
|
'Do you really want to remove this comment?' => 'คุณต้องการลบความคิดเห็น',
|
||||||
|
'Only administrators or the creator of the comment can access to this page.' => 'เฉพาะผู้ดูแลระบบหรือผู้สร้างความคิดเห็นเข้าถึงหน้านี้',
|
||||||
|
'Details' => 'รายละเอียด',
|
||||||
|
'Current password for the user "%s"' => 'รหัสผ่านปัจจุบันของผู้ใช้ « %s »',
|
||||||
|
'The current password is required' => 'ต้องการรหัสผ่านปัจจุบัน',
|
||||||
|
'Wrong password' => 'รหัสผ่านผิด',
|
||||||
|
'Reset all tokens' => 'รีเซตโทเคนทั้งหมด ',
|
||||||
|
'All tokens have been regenerated.' => 'โทเคนทั้งหมดทำการสร้างใหม่',
|
||||||
|
'Unknown' => 'ไม่ทราบ',
|
||||||
|
'Last logins' => 'เข้าใช้ล่าสุด',
|
||||||
|
'Login date' => 'วันที่เข้าใข้',
|
||||||
|
'Authentication method' => 'วิธีการยืนยันตัวตน',
|
||||||
|
'IP address' => 'ไอพี แอดเดรส',
|
||||||
|
'User agent' => 'User agent',
|
||||||
|
'Persistent connections' => 'Persistent connections',
|
||||||
|
'No session.' => 'No session.',
|
||||||
|
'Expiration date' => 'หมดอายุวันที่',
|
||||||
|
'Remember Me' => 'จดจำฉัน',
|
||||||
|
'Creation date' => 'สร้างวันที่',
|
||||||
|
'Filter by user' => 'กรองตามผู้ใช้',
|
||||||
|
'Filter by due date' => 'กรองตามวันครบกำหนด',
|
||||||
|
'Everybody' => 'ทุกคน',
|
||||||
|
'Open' => 'เปิด',
|
||||||
|
'Closed' => 'ปิด',
|
||||||
|
'Search' => 'ค้นหา',
|
||||||
|
'Nothing found.' => 'ค้นหาไม่พบ.',
|
||||||
|
'Search in the project "%s"' => 'ค้นหาในโปรเจค "%s"',
|
||||||
|
'Due date' => 'วันที่ครบกำหนด',
|
||||||
|
'Others formats accepted: %s and %s' => 'รูปแบบอื่นที่ได้รับการยอมรับ: %s และ %s',
|
||||||
|
'Description' => 'คำอธิบาย',
|
||||||
|
'%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.' => 'กูเกลิแอคเคาท์เชื่อมต่อกับประวัติของคุณเรียบร้อยแล้ว',
|
||||||
|
'Email' => 'อีเมล',
|
||||||
|
'Link my Google Account' => 'เชื่อมต่อกับกูเกิลแอคเคาท์',
|
||||||
|
'Unlink my Google Account' => 'ไม่เชื่อมต่อกับกูเกิลแอคเคาท์',
|
||||||
|
'Login with my Google Account' => 'เข้าใช้ด้วยกูเกิลแอคเคาท์',
|
||||||
|
'Project not found.' => 'หาโปรเจคไม่พบ',
|
||||||
|
'Task #%d' => 'งานที่ %d',
|
||||||
|
'Task removed successfully.' => 'ลบงานเรียบร้อยแล้ว',
|
||||||
|
'Unable to remove this task.' => 'ไม่สามารถลบงานนี้',
|
||||||
|
'Remove a task' => 'ลบงาาน',
|
||||||
|
'Do you really want to remove this task: "%s"?' => 'คุณต้องการลบงาน "%s" ออกใช่หรือไม่?',
|
||||||
|
'Assign automatically a color based on a category' => 'กำหนดสีอัตโนมัติขึ้นอยู่กับกลุ่ม',
|
||||||
|
'Assign automatically a category based on a color' => 'กำหนดกลุ่มอัตโนมัติขึ้นอยู่กับสี',
|
||||||
|
'Task creation or modification' => 'สร้างหรือแก้ไขงาน',
|
||||||
|
'Category' => 'กลุ่ม',
|
||||||
|
'Category:' => 'กลุ่ม:',
|
||||||
|
'Categories' => 'กลุ่ม',
|
||||||
|
'Category not found.' => 'ไม่พบกลุ่ม.',
|
||||||
|
'Your category have been created successfully.' => 'สร้างกลุ่มเรียบร้อยแล้ว',
|
||||||
|
'Unable to create your category.' => 'ไม่สามารถสร้างกลุ่มได้',
|
||||||
|
'Your category have been updated successfully.' => 'ปรับปรุงกลุ่มเรียบร้อยแล้ว',
|
||||||
|
'Unable to update your category.' => 'ไม่สามารถปรับปรุงกลุ่มได้',
|
||||||
|
'Remove a category' => 'ลบกลุ่ม',
|
||||||
|
'Category removed successfully.' => 'ลบกลุ่มเรียบร้อยแล้ว',
|
||||||
|
'Unable to remove this category.' => 'ไม่สามารถลบกลุ่มได้',
|
||||||
|
'Category modification for the project "%s"' => 'แก้ไขกลุ่มสำหรับโปรเจค "%s"',
|
||||||
|
'Category Name' => 'ชื่อกลุ่ม',
|
||||||
|
'Categories for the project "%s"' => 'กลุ่มสำหรับโปรเจค "%s"',
|
||||||
|
'Add a new category' => 'เพิ่มกลุ่มใหม่',
|
||||||
|
'Do you really want to remove this category: "%s"?' => 'คุณต้องการลบกลุ่ม "%s" ใช่หรือไม่?',
|
||||||
|
'Filter by category' => 'กรองตามกลุ่ม',
|
||||||
|
'All categories' => 'กลุ่มทั้งหมด',
|
||||||
|
'No category' => 'ไม่มีกลุ่ม',
|
||||||
|
'The name is required' => 'ต้องการชื่อ',
|
||||||
|
'Remove a file' => 'ลบไฟล์',
|
||||||
|
'Unable to remove this file.' => 'ไม่สามารถลบไฟล์ได้',
|
||||||
|
'File removed successfully.' => 'ลบไฟล์เรียบร้อยแล้ว',
|
||||||
|
'Attach a document' => 'แนบเอกสาร',
|
||||||
|
'Do you really want to remove this file: "%s"?' => 'คุณต้องการลบไฟล์ "%s" ใช่หรือไม่?',
|
||||||
|
'open' => 'เปิด',
|
||||||
|
'Attachments' => 'แนบ',
|
||||||
|
'Edit the task' => 'แก้ไขงาน',
|
||||||
|
'Edit the description' => 'แก้ไขคำอธิบาย',
|
||||||
|
'Add a comment' => 'เพิ่มความคิดเห็น',
|
||||||
|
'Edit a comment' => 'แก้ไขความคิดเห็น',
|
||||||
|
'Summary' => 'สรุป',
|
||||||
|
'Time tracking' => 'การติดตามเวลา',
|
||||||
|
'Estimate:' => 'ประมาณ:',
|
||||||
|
'Spent:' => 'ใช้:',
|
||||||
|
'Do you really want to remove this sub-task?' => 'คุณต้องการลบงานย่อยใช่หรือไม่?',
|
||||||
|
'Remaining:' => 'เหลือ:',
|
||||||
|
'hours' => 'ชั่วโมง',
|
||||||
|
'spent' => 'ใช้',
|
||||||
|
'estimated' => 'ประมาณ',
|
||||||
|
'Sub-Tasks' => 'งานย่อย',
|
||||||
|
'Add a sub-task' => 'เพิ่มงานย่อย',
|
||||||
|
// 'Original estimate' => '',
|
||||||
|
'Create another sub-task' => 'สร้างงานย่อยอื่น',
|
||||||
|
// 'Time spent' => '',
|
||||||
|
'Edit a sub-task' => 'แก้ไขงานย่อย',
|
||||||
|
'Remove a sub-task' => 'ลบงานย่อย',
|
||||||
|
'The time must be a numeric value' => 'เวลาที่ต้องเป็นตัวเลข',
|
||||||
|
'Todo' => 'สิ่งที่ต้องทำ',
|
||||||
|
'In progress' => 'กำลังดำเนินการ',
|
||||||
|
'Sub-task removed successfully.' => 'ลบงานย่อยเรียบร้อยแล้ว',
|
||||||
|
'Unable to remove this sub-task.' => 'ไม่สามารถลบงานย่อยได้',
|
||||||
|
'Sub-task updated successfully.' => 'ปรับปรุงงานย่อย่่เรียบร้อยแล้ว',
|
||||||
|
'Unable to update your sub-task.' => 'ไม่สามารถปรับปรุงานย่อยได้',
|
||||||
|
'Unable to create your sub-task.' => 'ไม่สามารถสร้างงานย่อยได้',
|
||||||
|
'Sub-task added successfully.' => 'เพิ่มงานย่อยเรียบร้อยแล้ว',
|
||||||
|
'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' => 'ยกเลิกการเชื่อมกับกิทอับแอคเคาท์',
|
||||||
|
'Created by %s' => 'สร้างโดย %s',
|
||||||
|
'Last modified on %B %e, %Y at %k:%M %p' => 'แก้ไขล่าสุดวันที่ %B %e, %Y เวลา %k:%M %p',
|
||||||
|
'Tasks Export' => 'ส่งออกงาน',
|
||||||
|
'Tasks exportation for "%s"' => 'ส่งออกงานสำหรับ "%s"',
|
||||||
|
'Start Date' => 'เริ่มวันที่',
|
||||||
|
'End Date' => 'สิ้นสุดวันที่',
|
||||||
|
'Execute' => 'ประมวลผล',
|
||||||
|
'Task Id' => 'งาน ไอดี',
|
||||||
|
'Creator' => 'ผู้สร้าง',
|
||||||
|
'Modification date' => 'วันที่แก้ไข',
|
||||||
|
'Completion date' => 'วันที่เสร็จสิ้น',
|
||||||
|
'Webhook URL for task creation' => 'Webhook URL for task creation',
|
||||||
|
'Webhook URL for task modification' => 'Webhook URL for task modification',
|
||||||
|
'Clone' => 'เลียนแบบ',
|
||||||
|
// 'Clone Project' => '',
|
||||||
|
'Project cloned successfully.' => 'เลียนแบบโปรเจคเรียบร้อยแล้ว',
|
||||||
|
'Unable to clone this project.' => 'ไม่สามารถเลียบแบบโปรเจคได้',
|
||||||
|
'Email notifications' => 'อีเมลแจ้งเตือน',
|
||||||
|
'Enable email notifications' => 'เปิดอีเมลแจ้งเตือน',
|
||||||
|
'Task position:' => 'ตำแหน่งงาน',
|
||||||
|
'The task #%d have been opened.' => 'งานที่ #%d ถุกเปิด',
|
||||||
|
'The task #%d have been closed.' => 'งานที่ #%d ถูกปิด',
|
||||||
|
'Sub-task updated' => 'ปรับปรุงงานย่อย',
|
||||||
|
'Title:' => 'หัวเรื่อง:',
|
||||||
|
'Status:' => 'สถานะ:',
|
||||||
|
'Assignee:' => 'กำหนดให้:',
|
||||||
|
'Time tracking:' => 'การติดตามเวลา:',
|
||||||
|
'New sub-task' => 'งานย่อยใหม่',
|
||||||
|
'New attachment added "%s"' => 'เพิ่มการแนบใหม่ "%s"',
|
||||||
|
'Comment updated' => 'ปรับปรุงความคิดเห็น',
|
||||||
|
'New comment posted by %s' => 'ความคิดเห็นใหม่จาก %s',
|
||||||
|
'List of due tasks for the project "%s"' => 'รายการงานสำหรับโปรเจค "%s"',
|
||||||
|
'[%s][New attachment] %s (#%d)' => '[%s][แนบใหม่] %s (#%d)',
|
||||||
|
'[%s][New comment] %s (#%d)' => '[%s][ความคิดเห็นใหม่] %s (#%d)',
|
||||||
|
'[%s][Comment updated] %s (#%d)' => '[%s][ปรับปรุงความคิดเห็น] %s (#%d)',
|
||||||
|
'[%s][New subtask] %s (#%d)' => '[%s][งานย่อยใหม่] %s (#%d)',
|
||||||
|
'[%s][Subtask updated] %s (#%d)' => '[%s][ปรับปรุงงานย่อย] %s (#%d)',
|
||||||
|
'[%s][New task] %s (#%d)' => '[%s][งานใหม่] %s (#%d)',
|
||||||
|
'[%s][Task updated] %s (#%d)' => '[%s][ปรับปรุุงงาน] %s (#%d)',
|
||||||
|
'[%s][Task closed] %s (#%d)' => '[%s][งานที่ปิด] %s (#%d)',
|
||||||
|
'[%s][Task opened] %s (#%d)' => '[%s][งานที่เปิด] %s (#%d)',
|
||||||
|
'[%s][Due tasks]' => '[%s][งานปัจจุบัน]',
|
||||||
|
'[Kanboard] Notification' => '[Kanboard] แจ้งเตือน',
|
||||||
|
'I want to receive notifications only for those projects:' => 'ฉันต้องการรับการแจ้งเตือนสำหรับโปรเจค:',
|
||||||
|
'view the task on Kanboard' => 'แสดงงานบน Kanboard',
|
||||||
|
'Public access' => 'การเข้าถึงสาธารณะ',
|
||||||
|
// 'Category management' => '',
|
||||||
|
// 'User management' => '',
|
||||||
|
'Active tasks' => 'งานที่กำลังใช้งาน',
|
||||||
|
'Disable public access' => 'ปิดการเข้าถึงสาธารณะ',
|
||||||
|
'Enable public access' => 'เปิดการเข้าถึงสาธารณะ',
|
||||||
|
'Active projects' => 'เปิดโปรเจค',
|
||||||
|
'Inactive projects' => 'ปิดโปรเจค',
|
||||||
|
'Public access disabled' => 'การเข้าถึงสาธารณะถูกปิด',
|
||||||
|
'Do you really want to disable this project: "%s"?' => 'คุณต้องการปิดการใช้งานโปรเจคนี้: "%s" ใช่หรือไม่?',
|
||||||
|
'Do you really want to duplicate this project: "%s"?' => 'คุณต้องการทำซ้ำโปรเจคนี้ "%s" ใช่หรือไม่?',
|
||||||
|
'Do you really want to enable this project: "%s"?' => 'คุณต้องการเปิดการใช้งานโปรเจคนี้: "%s" ใช่หรือไม่?',
|
||||||
|
'Project activation' => 'การ เปิด/ปิด ใช้งานโปรเจค',
|
||||||
|
'Move the task to another project' => 'ย้ายงานไปโปรเจคอื่น',
|
||||||
|
'Move to another project' => 'ย้ายไปโปรเจคอื่น',
|
||||||
|
'Do you really want to duplicate this task?' => 'คุณต้องการทำซ้ำงานนี้ใช่หรือไม่?',
|
||||||
|
'Duplicate a task' => 'ทำซ้ำงาน',
|
||||||
|
'External accounts' => 'บัญชีภายนอก',
|
||||||
|
'Account type' => 'ประเภทบัญชี',
|
||||||
|
'Local' => 'ท้องถิ่น',
|
||||||
|
'Remote' => 'รีโมท',
|
||||||
|
'Enabled' => 'เปิดการใช้',
|
||||||
|
'Disabled' => 'ปิดการใช้',
|
||||||
|
'Google account linked' => 'เชื่อมกับกูเกิลแอคเคาท์',
|
||||||
|
'Github account linked' => 'เชื่อมกับกิทฮับแอคเคาท์',
|
||||||
|
'Username:' => 'ชื่อผู้ใช้:',
|
||||||
|
'Name:' => 'ชื่อ:',
|
||||||
|
'Email:' => 'อีเมล:',
|
||||||
|
'Default project:' => 'โปรเจคเริ่มต้น:',
|
||||||
|
'Notifications:' => 'แจ้งเตือน:',
|
||||||
|
'Notifications' => 'การแจ้งเตือน',
|
||||||
|
'Group:' => 'กลุ่ม:',
|
||||||
|
'Regular user' => 'ผู้ใช้ปกติ:',
|
||||||
|
'Account type:' => 'ชนิดบัญชี:',
|
||||||
|
'Edit profile' => 'แก้ไขประวัติ',
|
||||||
|
'Change password' => 'เปลี่ยนรหัสผ่าน',
|
||||||
|
'Password modification' => 'แก้ไขรหัสผ่าน',
|
||||||
|
'External authentications' => 'การยืนยันภายนอก',
|
||||||
|
'Google Account' => 'กูเกิลแอคเคาท์',
|
||||||
|
'Github Account' => 'กิทฮับแอคเคาท์',
|
||||||
|
'Never connected.' => 'ไม่เชื่อมต่อ',
|
||||||
|
'No account linked.' => 'แอคเคาท์ไม่มีการเชื่อม',
|
||||||
|
'Account linked.' => 'แอคเคาท์เชื่อมต่อแล้ว',
|
||||||
|
'No external authentication enabled.' => 'ไม่เปิดการใช้งานการยืนยันภายนอก',
|
||||||
|
'Password modified successfully.' => 'แก้ไขรหัสผ่านเรียบร้อยแล้ว',
|
||||||
|
'Unable to change the password.' => 'ไม่สามารถเปลี่ยนรหัสผ่านได้',
|
||||||
|
'Change category for the task "%s"' => 'เปลี่ยนกลุ่มสำหรับงาน "%s"',
|
||||||
|
'Change category' => 'เปลี่ยนกลุ่ม',
|
||||||
|
'%s updated the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s ปรับปรุงงานแล้ว <a href="?controller=task&action=show&task_id=%d">#%d</a>',
|
||||||
|
'%s open the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s เปิดงานแล้ว <a href="?controller=task&action=show&task_id=%d">#%d</a>',
|
||||||
|
'%s moved the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to the position #%d in the column "%s"' => '%s ย้ายงานแล้ว <a href="?controller=task&action=show&task_id=%d">#%d</a> ไปตำแหน่ง #%d ในคอลัมน์ "%s"',
|
||||||
|
'%s moved the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to the column "%s"' => '%s ย้ายงานแล้ว <a href="?controller=task&action=show&task_id=%d">#%d</a> ไปคอลัมน์ "%s"',
|
||||||
|
'%s created the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s สร้างงานแล้ว <a href="?controller=task&action=show&task_id=%d">#%d</a>',
|
||||||
|
'%s closed the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s ปิดงานแล้ว <a href="?controller=task&action=show&task_id=%d">#%d</a>',
|
||||||
|
'%s created a subtask for the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s สร้างงานย่อยสำหรับงานแล้ว <a href="?controller=task&action=show&task_id=%d">#%d</a>',
|
||||||
|
'%s updated a subtask for the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s ปรับปรุงงานย่อยสำหรับงานแล้ว <a href="?controller=task&action=show&task_id=%d">#%d</a>',
|
||||||
|
'Assigned to %s with an estimate of %s/%sh' => 'กำหนดให้ %s โดยประมาณแล้ว %s/%sh',
|
||||||
|
'Not assigned, estimate of %sh' => 'ไม่กำหนดแล้ว, ประมาณเวลาที่ใช้ %s ชั่วโมง',
|
||||||
|
'%s updated a comment on the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s ปรับปรุงความคิดเห็นในงานแล้ว <a href="?controller=task&action=show&task_id=%d">#%d</a>',
|
||||||
|
'%s commented the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s แสดงความคิดเห็นของงานแล้ว <a href="?controller=task&action=show&task_id=%d">#%d</a>',
|
||||||
|
'%s\'s activity' => 'กิจกรรม %s',
|
||||||
|
'No activity.' => 'ไม่มีกิจกรรม',
|
||||||
|
'RSS feed' => 'RSS feed',
|
||||||
|
'%s updated a comment on the task #%d' => '%s ปรับปรุงความคิดเห็นบนงานแล้ว #%d',
|
||||||
|
'%s commented on the task #%d' => '%s แสดงความคิดเห็นบนงานแล้ว #%d',
|
||||||
|
'%s updated a subtask for the task #%d' => '%s ปรับปรุงงานย่อยสำหรับงานแล้ว #%d',
|
||||||
|
'%s created a subtask for the task #%d' => '%s สร้างงานย่อยสำหรับงานแล้ว #%d',
|
||||||
|
'%s updated the task #%d' => '%s ปรับปรุงงานแล้ว #%d',
|
||||||
|
'%s created the task #%d' => '%s สร้างงานแล้ว #%d',
|
||||||
|
'%s closed the task #%d' => '%s ปิดงานแล้ว #%d',
|
||||||
|
'%s open the task #%d' => '%s เปิดงานแล้ว #%d',
|
||||||
|
'%s moved the task #%d to the column "%s"' => '%s ย้ายงานแล้ว #%d ไปที่คอลัมน์ "%s"',
|
||||||
|
'%s moved the task #%d to the position %d in the column "%s"' => '%s ย้ายงานแล้ว #%d ไปตำแหน่ง %d ในคอลัมน์ที่ "%s"',
|
||||||
|
'Activity' => 'กิจกรรม',
|
||||||
|
'Default values are "%s"' => 'ค่าเริ่มต้น "%s"',
|
||||||
|
'Default columns for new projects (Comma-separated)' => 'คอลัมน์เริ่มต้นสำหรับโปรเจคใหม่ (Comma-separated)',
|
||||||
|
'Task assignee change' => 'เปลี่ยนการกำหนดบุคคลของงาน',
|
||||||
|
// '%s change the assignee of the task #%d to %s' => '',
|
||||||
|
// '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to %s' => '',
|
||||||
|
// '[%s][Column Change] %s (#%d)' => '',
|
||||||
|
// '[%s][Position Change] %s (#%d)' => '',
|
||||||
|
// '[%s][Assignee Change] %s (#%d)' => '',
|
||||||
|
'New password for the user "%s"' => 'รหัสผ่านใหม่สำหรับผู้ใช้ "%s"',
|
||||||
|
// 'Choose an event' => '',
|
||||||
|
// 'Github commit received' => '',
|
||||||
|
// 'Github issue opened' => '',
|
||||||
|
// 'Github issue closed' => '',
|
||||||
|
// 'Github issue reopened' => '',
|
||||||
|
// 'Github issue assignee change' => '',
|
||||||
|
// 'Github issue label change' => '',
|
||||||
|
// 'Create a task from an external provider' => '',
|
||||||
|
// 'Change the assignee based on an external username' => '',
|
||||||
|
// 'Change the category based on an external label' => '',
|
||||||
|
// 'Reference' => '',
|
||||||
|
// 'Reference: %s' => '',
|
||||||
|
// 'Label' => '',
|
||||||
|
// 'Database' => '',
|
||||||
|
// 'About' => '',
|
||||||
|
// 'Database driver:' => '',
|
||||||
|
// 'Board settings' => '',
|
||||||
|
// 'URL and token' => '',
|
||||||
|
// 'Webhook settings' => '',
|
||||||
|
// 'URL for task creation:' => '',
|
||||||
|
// 'Reset token' => '',
|
||||||
|
// 'API endpoint:' => '',
|
||||||
|
// 'Refresh interval for private board' => '',
|
||||||
|
// 'Refresh interval for public board' => '',
|
||||||
|
// 'Task highlight period' => '',
|
||||||
|
// 'Period (in second) to consider a task was modified recently (0 to disable, 2 days by default)' => '',
|
||||||
|
// 'Frequency in second (60 seconds by default)' => '',
|
||||||
|
// 'Frequency in second (0 to disable this feature, 10 seconds by default)' => '',
|
||||||
|
// 'Application URL' => '',
|
||||||
|
// 'Example: http://example.kanboard.net/ (used by email notifications)' => '',
|
||||||
|
// 'Token regenerated.' => '',
|
||||||
|
// 'Date format' => '',
|
||||||
|
// 'ISO format is always accepted, example: "%s" and "%s"' => '',
|
||||||
|
// 'New private project' => '',
|
||||||
|
// 'This project is private' => '',
|
||||||
|
// 'Type here to create a new sub-task' => '',
|
||||||
|
// 'Add' => '',
|
||||||
|
// 'Estimated time: %s hours' => '',
|
||||||
|
// 'Time spent: %s hours' => '',
|
||||||
|
// 'Started on %B %e, %Y' => '',
|
||||||
|
// 'Start date' => '',
|
||||||
|
// 'Time estimated' => '',
|
||||||
|
// 'There is nothing assigned to you.' => '',
|
||||||
|
// 'My tasks' => '',
|
||||||
|
// 'Activity stream' => '',
|
||||||
|
// 'Dashboard' => '',
|
||||||
|
'Confirmation' => 'ยืนยันรหัสผ่าน',
|
||||||
|
// 'Allow everybody to access to this project' => '',
|
||||||
|
'Everybody have access to this project.' => 'ทุกคนสามารถเข้าถึงโปรเจคนี้',
|
||||||
|
// 'Webhooks' => '',
|
||||||
|
// 'API' => '',
|
||||||
|
// 'Integration' => '',
|
||||||
|
// 'Github webhook' => '',
|
||||||
|
// 'Help on Github webhook' => '',
|
||||||
|
// 'Create a comment from an external provider' => '',
|
||||||
|
// 'Github issue comment created' => '',
|
||||||
|
);
|
561
sources/app/Locale/zh_CN/translations.php
Normal file
561
sources/app/Locale/zh_CN/translations.php
Normal file
|
@ -0,0 +1,561 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'None' => '无',
|
||||||
|
'edit' => '编辑',
|
||||||
|
'Edit' => '编辑',
|
||||||
|
'remove' => '移除',
|
||||||
|
'Remove' => '移除',
|
||||||
|
'Update' => '更新',
|
||||||
|
'Yes' => '是',
|
||||||
|
'No' => '否',
|
||||||
|
'cancel' => '取消',
|
||||||
|
'or' => '或者',
|
||||||
|
'Yellow' => '黄色',
|
||||||
|
'Blue' => '蓝色',
|
||||||
|
'Green' => '绿色',
|
||||||
|
'Purple' => '紫色',
|
||||||
|
'Red' => '红色',
|
||||||
|
'Orange' => '橘色',
|
||||||
|
'Grey' => '灰色',
|
||||||
|
'Save' => '保存',
|
||||||
|
'Login' => '登录',
|
||||||
|
'Official website:' => '官方网站:',
|
||||||
|
'Unassigned' => '未指定',
|
||||||
|
'View this task' => '查看该任务',
|
||||||
|
'Remove user' => '移除用户',
|
||||||
|
'Do you really want to remove this user: "%s"?' => '你确定要移除这个用户吗:"%s"?',
|
||||||
|
'New user' => '新建用户',
|
||||||
|
'All users' => '所有用户',
|
||||||
|
'Username' => '用户名',
|
||||||
|
'Password' => '密码',
|
||||||
|
'Default project' => '默认项目',
|
||||||
|
'Administrator' => '管理员',
|
||||||
|
'Sign in' => '登录',
|
||||||
|
'Users' => '用户',
|
||||||
|
'No user' => '没有用户',
|
||||||
|
'Forbidden' => '禁止',
|
||||||
|
'Access Forbidden' => '禁止进入',
|
||||||
|
'Only administrators can access to this page.' => '只有管理员可以查看该页面。',
|
||||||
|
'Edit user' => '修改用户',
|
||||||
|
'Logout' => '退出',
|
||||||
|
'Bad username or password' => '用户名或密码错误',
|
||||||
|
'users' => '用户',
|
||||||
|
'projects' => '项目',
|
||||||
|
'Edit project' => '修改项目',
|
||||||
|
'Name' => '名称',
|
||||||
|
'Activated' => '已激活',
|
||||||
|
'Projects' => '项目',
|
||||||
|
'No project' => '无项目',
|
||||||
|
'Project' => '项目',
|
||||||
|
'Status' => '状态',
|
||||||
|
'Tasks' => '任务',
|
||||||
|
'Board' => '看板',
|
||||||
|
'Actions' => '动作',
|
||||||
|
'Inactive' => '未激活',
|
||||||
|
'Active' => '激活',
|
||||||
|
'Column %d' => '第%d栏目',
|
||||||
|
'Add this column' => '加入该栏目',
|
||||||
|
'%d tasks on the board' => '看板目前有%d个任务',
|
||||||
|
'%d tasks in total' => '总共有%d个任务',
|
||||||
|
'Unable to update this board.' => '无法更新该看板。',
|
||||||
|
'Edit board' => '修改看板',
|
||||||
|
'Disable' => '停用',
|
||||||
|
'Enable' => '启用',
|
||||||
|
'New project' => '新建项目',
|
||||||
|
'Do you really want to remove this project: "%s"?' => '你确定要移除该项目吗:"%s"?',
|
||||||
|
'Remove project' => '移除项目',
|
||||||
|
'Boards' => '看板',
|
||||||
|
'Edit the board for "%s"' => '为"%s"修改看板',
|
||||||
|
'All projects' => '所有项目',
|
||||||
|
'Change columns' => '更改栏目',
|
||||||
|
'Add a new column' => '添加新栏目',
|
||||||
|
'Title' => '标题',
|
||||||
|
'Add Column' => '添加栏目',
|
||||||
|
'Project "%s"' => '项目 "%s"',
|
||||||
|
'Nobody assigned' => '无人被指派',
|
||||||
|
'Assigned to %s' => '指派给 %s',
|
||||||
|
'Remove a column' => '移除一个栏目',
|
||||||
|
'Remove a column from a board' => '从看板移除一个栏目',
|
||||||
|
'Unable to remove this column.' => '无法移除该栏目。',
|
||||||
|
'Do you really want to remove this column: "%s"?' => '你确定要移除该栏目:"%s"吗?',
|
||||||
|
'This action will REMOVE ALL TASKS associated to this column!' => '该动作将移除与该栏目相关的所有项目!',
|
||||||
|
'Settings' => '设置',
|
||||||
|
'Application settings' => '应用设置',
|
||||||
|
'Language' => '语言',
|
||||||
|
'Webhook token:' => '页面钩子令牌:',
|
||||||
|
'API token:' => 'API 令牌:',
|
||||||
|
'More information' => '更多信息',
|
||||||
|
'Database size:' => '数据库大小:',
|
||||||
|
'Download the database' => '下载数据库',
|
||||||
|
'Optimize the database' => '优化数据库',
|
||||||
|
'(VACUUM command)' => '(VACUUM 指令)',
|
||||||
|
'(Gzip compressed Sqlite file)' => '(用Gzip压缩的Sqlite文件)',
|
||||||
|
'User settings' => '用户设置',
|
||||||
|
'My default project:' => '我的默认项目:',
|
||||||
|
'Close a task' => '关闭一个任务',
|
||||||
|
'Do you really want to close this task: "%s"?' => '你确定要关闭任务: "%s"?',
|
||||||
|
'Edit a task' => '修改一个任务',
|
||||||
|
'Column' => '栏目',
|
||||||
|
'Color' => '颜色',
|
||||||
|
'Assignee' => '负责人',
|
||||||
|
'Create another task' => '创建另一个任务',
|
||||||
|
'New task' => '新进任务',
|
||||||
|
'Open a task' => '开一个任务',
|
||||||
|
'Do you really want to open this task: "%s"?' => '你确定要开这个任务吗?"%s"',
|
||||||
|
'Back to the board' => '回到看板',
|
||||||
|
'Created on %B %e, %Y at %k:%M %p' => '创建时间:%Y/%m/%d %H:%M',
|
||||||
|
'There is nobody assigned' => '无人负责',
|
||||||
|
'Column on the board:' => '看板上的栏目:',
|
||||||
|
'Status is open' => '开启状态',
|
||||||
|
'Status is closed' => '关闭状态',
|
||||||
|
'Close this task' => '关闭该任务',
|
||||||
|
'Open this task' => '开启该任务',
|
||||||
|
'There is no description.' => '无描述。',
|
||||||
|
'Add a new task' => '添加新任务',
|
||||||
|
'The username is required' => '需要用户名',
|
||||||
|
'The maximum length is %d characters' => '最长%d个英文字符',
|
||||||
|
'The minimum length is %d characters' => '最短%d个英文自负',
|
||||||
|
'The password is required' => '需要密码',
|
||||||
|
'This value must be an integer' => '该值必须为整数',
|
||||||
|
'The username must be unique' => '用户名必须唯一',
|
||||||
|
'The username must be alphanumeric' => '用户名必须是英文字符或数字组成',
|
||||||
|
'The user id is required' => '用户id是必须的',
|
||||||
|
'Passwords don\'t match' => '密码不匹配',
|
||||||
|
'The confirmation is required' => '需要确认',
|
||||||
|
'The column is required' => '需要指定栏目',
|
||||||
|
'The project is required' => '需要指定项目',
|
||||||
|
'The color is required' => '需要指定颜色',
|
||||||
|
'The id is required' => '需要指定id',
|
||||||
|
'The project id is required' => '需要指定项目id',
|
||||||
|
'The project name is required' => '需要指定项目名称',
|
||||||
|
'This project must be unique' => '项目名称必须唯一',
|
||||||
|
'The title is required' => '需要指定标题',
|
||||||
|
'The language 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.' => '数据库优化完成。',
|
||||||
|
'Your project have been created successfully.' => '您的项目已经成功创建。',
|
||||||
|
'Unable to create your project.' => '无法为您创建项目。',
|
||||||
|
'Project updated successfully.' => '成功更新项目。',
|
||||||
|
'Unable to update this project.' => '无法更新该项目。',
|
||||||
|
'Unable to remove this project.' => '无法移除该项目。',
|
||||||
|
'Project removed successfully.' => '成功移除项目。',
|
||||||
|
'Project activated successfully.' => '项目成功激活。',
|
||||||
|
'Unable to activate this project.' => '无法激活该项目。',
|
||||||
|
'Project disabled successfully.' => '成功停用项目。',
|
||||||
|
'Unable to disable this project.' => '无法停用该项目。',
|
||||||
|
'Unable to open this task.' => '无法开启该任务。',
|
||||||
|
'Task opened successfully.' => '任务开启成功。',
|
||||||
|
'Unable to close this task.' => '无法关闭该任务。',
|
||||||
|
'Task closed successfully.' => '成功关闭任务。',
|
||||||
|
'Unable to update your task.' => '无法更新您的任务。',
|
||||||
|
'Task updated successfully.' => '成功更新任务。',
|
||||||
|
'Unable to create your task.' => '无法为您创建任务。',
|
||||||
|
'Task created successfully.' => '成功创建任务。',
|
||||||
|
'User created successfully.' => '成功创建用户。',
|
||||||
|
'Unable to create your user.' => '无法创建用户。',
|
||||||
|
'User updated successfully.' => '成功更新用户。',
|
||||||
|
'Unable to update your user.' => '无法为您更新用户。',
|
||||||
|
'User removed successfully.' => '成功移除用户。',
|
||||||
|
'Unable to remove this user.' => '无法移除该用户。',
|
||||||
|
'Board updated successfully.' => '看板成功更新。',
|
||||||
|
'Ready' => '预备',
|
||||||
|
'Backlog' => '积压',
|
||||||
|
'Work in progress' => '工作进行中',
|
||||||
|
'Done' => '完成',
|
||||||
|
'Application version:' => '应用程序版本:',
|
||||||
|
'Completed on %B %e, %Y at %k:%M %p' => '于%Y/%m/%d %H:%M 完成',
|
||||||
|
'%B %e, %Y at %k:%M %p' => '%Y/%m/%d %H:%M',
|
||||||
|
'Date created' => '创建时间',
|
||||||
|
'Date completed' => '完成时间',
|
||||||
|
'Id' => '编号',
|
||||||
|
'No task' => '无任务',
|
||||||
|
'Completed tasks' => '已完成任务',
|
||||||
|
'List of projects' => '项目列表',
|
||||||
|
'Completed tasks for "%s"' => '"%s"已经完成的任务',
|
||||||
|
'%d closed tasks' => '%d个已关闭任务',
|
||||||
|
'No task for this project' => '该项目尚无任务',
|
||||||
|
'Public link' => '公开链接',
|
||||||
|
'There is no column in your project!' => '该项目尚无栏目项!',
|
||||||
|
'Change assignee' => '变更负责人',
|
||||||
|
'Change assignee for the task "%s"' => '更改任务"%s"的负责人',
|
||||||
|
'Timezone' => '时区',
|
||||||
|
'Sorry, I didn\'t found this information in my database!' => '抱歉,无法在数据库中找到该信息!',
|
||||||
|
'Page not found' => '页面未找到',
|
||||||
|
'Complexity' => '复杂度',
|
||||||
|
'limit' => '限制',
|
||||||
|
'Task limit' => '任务限制',
|
||||||
|
'This value must be greater than %d' => '该数值必须大于%d',
|
||||||
|
'Edit project access list' => '编辑项目存取列表',
|
||||||
|
'Edit users access' => '编辑用户存取权限',
|
||||||
|
'Allow this user' => '允许该用户',
|
||||||
|
'Only those users have access to this project:' => '只有这些用户有该项目的存取权限:',
|
||||||
|
'Don\'t forget that administrators have access to everything.' => '别忘了管理员有一切的权限。',
|
||||||
|
'revoke' => '撤销',
|
||||||
|
'List of authorized users' => '已授权的用户列表',
|
||||||
|
'User' => '用户',
|
||||||
|
'Nobody have access to this project.' => '无用户可以访问此项目.',
|
||||||
|
'You are not allowed to access to this project.' => '您对该项目没有权限。',
|
||||||
|
'Comments' => '评论',
|
||||||
|
'Post comment' => '发表评论',
|
||||||
|
'Write your text in Markdown' => '用Markdown格式编写',
|
||||||
|
'Leave a comment' => '留言',
|
||||||
|
'Comment is required' => '必须得有评论',
|
||||||
|
'Leave a description' => '给一个描述',
|
||||||
|
'Comment added successfully.' => '评论成功添加。',
|
||||||
|
'Unable to create your comment.' => '无法创建评论。',
|
||||||
|
'The description is required' => '必须得有描述',
|
||||||
|
'Edit this task' => '编辑该任务',
|
||||||
|
'Due Date' => '到期时间',
|
||||||
|
'Invalid date' => '无效日期',
|
||||||
|
'Must be done before %B %e, %Y' => '必须在%Y/%m/%d前完成',
|
||||||
|
'%B %e, %Y' => '%Y/%m/%d',
|
||||||
|
'Automatic actions' => '自动动作',
|
||||||
|
'Your automatic action have been created successfully.' => '您的自动动作已成功创建',
|
||||||
|
'Unable to create your automatic action.' => '无法为您创建自动动作。',
|
||||||
|
'Remove an action' => '移除一个动作。',
|
||||||
|
'Unable to remove this action.' => '无法移除该动作',
|
||||||
|
'Action removed successfully.' => '成功移除动作。',
|
||||||
|
'Automatic actions for the project "%s"' => '项目"%s"的自动动作',
|
||||||
|
'Defined actions' => '已定义的动作',
|
||||||
|
'Add an action' => '添加动作',
|
||||||
|
'Event name' => '事件名称',
|
||||||
|
'Action name' => '动作名称',
|
||||||
|
'Action parameters' => '动作参数',
|
||||||
|
'Action' => '动作',
|
||||||
|
'Event' => '事件',
|
||||||
|
'When the selected event occurs execute the corresponding action.' => '当所选事件发生时执行相应动作。',
|
||||||
|
'Next step' => '下一步',
|
||||||
|
'Define action parameters' => '定义动作参数',
|
||||||
|
'Save this action' => '保存该动作',
|
||||||
|
'Do you really want to remove this action: "%s"?' => '确定要移除该动作"%s"吗?',
|
||||||
|
'Remove an automatic action' => '移除一个自动动作',
|
||||||
|
'Close the task' => '关闭任务',
|
||||||
|
'Assign the task to a specific user' => '将该任务指派给一个用户',
|
||||||
|
'Assign the task to the person who does the action' => '将任务指派给产生该动作的用户',
|
||||||
|
'Duplicate the task to another project' => '复制该任务到另一项目',
|
||||||
|
'Move a task to another column' => '移动任务到另一栏目',
|
||||||
|
'Move a task to another position in the same column' => '将任务移到该栏目另一位置',
|
||||||
|
'Task modification' => '任务修改',
|
||||||
|
'Task creation' => '任务创建',
|
||||||
|
'Open a closed task' => '开启已关闭任务',
|
||||||
|
'Closing a task' => '正在关闭任务',
|
||||||
|
'Assign a color to a specific user' => '为特定用户指派颜色',
|
||||||
|
'Column title' => '栏目名称',
|
||||||
|
'Position' => '位置',
|
||||||
|
'Move Up' => '往上移',
|
||||||
|
'Move Down' => '往下移',
|
||||||
|
'Duplicate to another project' => '复制到另一项目',
|
||||||
|
'Duplicate' => '复制',
|
||||||
|
'link' => '连接',
|
||||||
|
'Update this comment' => '更新该评论',
|
||||||
|
'Comment updated successfully.' => '评论成功更新。',
|
||||||
|
'Unable to update your comment.' => '无法更新您的评论。',
|
||||||
|
'Remove a comment' => '移除评论',
|
||||||
|
'Comment removed successfully.' => '评论成功移除。',
|
||||||
|
'Unable to remove this comment.' => '无法移除该评论。',
|
||||||
|
'Do you really want to remove this comment?' => '确定要移除评论吗?',
|
||||||
|
'Only administrators or the creator of the comment can access to this page.' => '只有管理员或评论创建者可以进入该页面。',
|
||||||
|
'Details' => '细节',
|
||||||
|
'Current password for the user "%s"' => '用户"%s"的当前密码',
|
||||||
|
'The current password is required' => '需要输入当前密码',
|
||||||
|
'Wrong password' => '密码错误',
|
||||||
|
'Reset all tokens' => '重置所有令牌',
|
||||||
|
'All tokens have been regenerated.' => '所有令牌都重新生成了。',
|
||||||
|
'Unknown' => '未知',
|
||||||
|
'Last logins' => '上次登录',
|
||||||
|
'Login date' => '登录日期',
|
||||||
|
'Authentication method' => '认证方式',
|
||||||
|
'IP address' => 'IP地址',
|
||||||
|
'User agent' => '浏览器标识',
|
||||||
|
'Persistent connections' => '持续连接',
|
||||||
|
'No session.' => '无会话',
|
||||||
|
'Expiration date' => '过期',
|
||||||
|
'Remember Me' => '记住我',
|
||||||
|
'Creation date' => '创建日期',
|
||||||
|
'Filter by user' => '按用户过滤',
|
||||||
|
'Filter by due date' => '按到期时间过滤',
|
||||||
|
'Everybody' => '所有人',
|
||||||
|
'Open' => '打开',
|
||||||
|
'Closed' => '关闭',
|
||||||
|
'Search' => '查找',
|
||||||
|
'Nothing found.' => '没找到。',
|
||||||
|
'Search in the project "%s"' => '在项目"%s"中查找',
|
||||||
|
'Due date' => '到期时间',
|
||||||
|
'Others formats accepted: %s and %s' => '允许其他格式:%s 和 %s',
|
||||||
|
'Description' => '描述',
|
||||||
|
'%d comments' => '%d个评论',
|
||||||
|
'%d comment' => '%d个评论',
|
||||||
|
'Email address invalid' => 'Email地址无效',
|
||||||
|
'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帐号已成功与账户配置关联。',
|
||||||
|
'Email' => 'Email',
|
||||||
|
'Link my Google Account' => '关联我的google帐号',
|
||||||
|
'Unlink my Google Account' => '去除我的google帐号关联',
|
||||||
|
'Login with my Google Account' => '用我的google帐号登录',
|
||||||
|
'Project not found.' => '未发现项目',
|
||||||
|
'Task #%d' => '任务 #%d',
|
||||||
|
'Task removed successfully.' => '任务成功去除',
|
||||||
|
'Unable to remove this task.' => '无法移除该任务。',
|
||||||
|
'Remove a task' => '移除一个任务',
|
||||||
|
'Do you really want to remove this task: "%s"?' => '确定要移除任务"%s"吗?',
|
||||||
|
'Assign automatically a color based on a category' => '基于一个分类自动指派颜色',
|
||||||
|
'Assign automatically a category based on a color' => '基于一种颜色自动指派分类',
|
||||||
|
'Task creation or modification' => '任务创建或修改',
|
||||||
|
'Category' => '分类',
|
||||||
|
'Category:' => '分类:',
|
||||||
|
'Categories' => '分类',
|
||||||
|
'Category not found.' => '未找到分类。',
|
||||||
|
'Your category have been created successfully.' => '成功为您创建分类。',
|
||||||
|
'Unable to create your category.' => '无法为您创建分类。',
|
||||||
|
'Your category have been updated successfully.' => '成功为您更新分类。',
|
||||||
|
'Unable to update your category.' => '无法为您更新分类。',
|
||||||
|
'Remove a category' => '移除一个分类',
|
||||||
|
'Category removed successfully.' => '分类成功移除。',
|
||||||
|
'Unable to remove this category.' => '无法移除该分类。',
|
||||||
|
'Category modification for the project "%s"' => '为项目"%s"修改分类',
|
||||||
|
'Category Name' => '分类名称',
|
||||||
|
'Categories for the project "%s"' => '项目"%s"的分类',
|
||||||
|
'Add a new category' => '加入新分类',
|
||||||
|
'Do you really want to remove this category: "%s"?' => '您确定要移除分类"%s"吗?',
|
||||||
|
'Filter by category' => '按分类过滤',
|
||||||
|
'All categories' => '所有分类',
|
||||||
|
'No category' => '无分类',
|
||||||
|
'The name is required' => '必须要有名字',
|
||||||
|
'Remove a file' => '移除一个文件',
|
||||||
|
'Unable to remove this file.' => '无法移除该文件。',
|
||||||
|
'File removed successfully.' => '文件成功移除。',
|
||||||
|
'Attach a document' => '附加文档',
|
||||||
|
'Do you really want to remove this file: "%s"?' => '您确定要移除文件"%s"吗?',
|
||||||
|
'open' => '打开',
|
||||||
|
'Attachments' => '附件',
|
||||||
|
'Edit the task' => '修改任务',
|
||||||
|
'Edit the description' => '修改描述',
|
||||||
|
'Add a comment' => '添加评论',
|
||||||
|
'Edit a comment' => '编辑评论',
|
||||||
|
'Summary' => '概要',
|
||||||
|
'Time tracking' => '时间记录',
|
||||||
|
'Estimate:' => '评估:',
|
||||||
|
'Spent:' => '花费:',
|
||||||
|
'Do you really want to remove this sub-task?' => '请确认是否要删除此子任务?',
|
||||||
|
'Remaining:' => '剩余:',
|
||||||
|
'hours' => '小时',
|
||||||
|
'spent' => '花费',
|
||||||
|
'estimated' => '评估',
|
||||||
|
'Sub-Tasks' => '子任务',
|
||||||
|
'Add a sub-task' => '添加子任务',
|
||||||
|
'Original estimate' => '初步预估',
|
||||||
|
'Create another sub-task' => '创建另一个子任务',
|
||||||
|
'Time spent' => '时间花费',
|
||||||
|
'Edit a sub-task' => '编辑子任务',
|
||||||
|
'Remove a sub-task' => '删除子任务',
|
||||||
|
'The time must be a numeric value' => '时间必须为数字',
|
||||||
|
'Todo' => '待完成',
|
||||||
|
'In progress' => '正在进行',
|
||||||
|
'Sub-task removed successfully.' => '成功删除子任务',
|
||||||
|
'Unable to remove this sub-task.' => '无法删除此任务',
|
||||||
|
'Sub-task updated successfully.' => '成功创建子任务',
|
||||||
|
'Unable to update your sub-task.' => '无法更新子任务',
|
||||||
|
'Unable to create your sub-task.' => '无法创建子任务',
|
||||||
|
'Sub-task added successfully.' => '成功添加子任务',
|
||||||
|
'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账号链接',
|
||||||
|
'Created by %s' => '创建者:',
|
||||||
|
'Last modified on %B %e, %Y at %k:%M %p' => '最后修改:%Y/%m/%d/ %H:%M',
|
||||||
|
'Tasks Export' => '任务导出',
|
||||||
|
'Tasks exportation for "%s"' => '导出任务"%s"',
|
||||||
|
'Start Date' => '开始时间',
|
||||||
|
'End Date' => '结束时间',
|
||||||
|
'Execute' => '执行',
|
||||||
|
'Task Id' => '任务ID',
|
||||||
|
'Creator' => '创建者',
|
||||||
|
'Modification date' => '修改日期',
|
||||||
|
'Completion date' => '完成日期',
|
||||||
|
'Webhook URL for task creation' => '创建任务的Webhook URL',
|
||||||
|
'Webhook URL for task modification' => '修改任务的Webhook URL',
|
||||||
|
'Clone' => '克隆',
|
||||||
|
'Clone Project' => '复制项目',
|
||||||
|
'Project cloned successfully.' => '成功复制项目。',
|
||||||
|
'Unable to clone this project.' => '无法复制此项目',
|
||||||
|
'Email notifications' => '邮件通知',
|
||||||
|
'Enable email notifications' => '启用邮件通知',
|
||||||
|
'Task position:' => '任务位置:',
|
||||||
|
'The task #%d have been opened.' => '任务#%d已经被开启.',
|
||||||
|
'The task #%d have been closed.' => '任务#%d已经被关闭.',
|
||||||
|
'Sub-task updated' => '子任务更新',
|
||||||
|
'Title:' => '标题:',
|
||||||
|
'Status:' => '状态:',
|
||||||
|
'Assignee:' => '负责人',
|
||||||
|
'Time tracking:' => '时间记录',
|
||||||
|
'New sub-task' => '新建子任务',
|
||||||
|
'New attachment added "%s"' => '新附件已添加"%s"',
|
||||||
|
'Comment updated' => '更新了评论',
|
||||||
|
'New comment posted by %s' => '%s 的新评论',
|
||||||
|
'List of due tasks for the project "%s"' => '项目"%s"的到期任务列表',
|
||||||
|
'[%s][New attachment] %s (#%d)' => '[%s][新附件] %s (#%d)',
|
||||||
|
'[%s][New comment] %s (#%d)' => '[%s][新评论] %s (#%d)',
|
||||||
|
'[%s][Comment updated] %s (#%d)' => '[%s][评论更新] %s (#%d)',
|
||||||
|
'[%s][New subtask] %s (#%d)' => '[%s][新子任务] %s (#%d)',
|
||||||
|
'[%s][Subtask updated] %s (#%d)' => '[%s][子任务更新] %s (#%d)',
|
||||||
|
'[%s][New task] %s (#%d)' => '[%s][新任务] %s (#%d)',
|
||||||
|
'[%s][Task updated] %s (#%d)' => '[%s][任务更新] %s (#%d)',
|
||||||
|
'[%s][Task closed] %s (#%d)' => '[%s][任务关闭] %s (#%d)',
|
||||||
|
'[%s][Task opened] %s (#%d)' => '[%s][任务开启] %s (#%d)',
|
||||||
|
'[%s][Due tasks]' => '[%s][到期任务]',
|
||||||
|
'[Kanboard] Notification' => '[Kanboard] 通知',
|
||||||
|
'I want to receive notifications only for those projects:' => '我仅需要收到下面项目的通知:',
|
||||||
|
'view the task on Kanboard' => '在看板中查看此任务',
|
||||||
|
'Public access' => '公开访问',
|
||||||
|
'Category management' => '分类管理',
|
||||||
|
'User management' => '用户管理',
|
||||||
|
'Active tasks' => '活动任务',
|
||||||
|
'Disable public access' => '停止公开访问',
|
||||||
|
'Enable public access' => '开启公开访问',
|
||||||
|
'Active projects' => '活动项目',
|
||||||
|
'Inactive projects' => '不活动项目',
|
||||||
|
'Public access disabled' => '已经禁止公开访问',
|
||||||
|
'Do you really want to disable this project: "%s"?' => '确认要禁用项目"%s"吗?',
|
||||||
|
'Do you really want to duplicate this project: "%s"?' => '确认要复制项目"%s"吗?',
|
||||||
|
'Do you really want to enable this project: "%s"?' => '确认要启用项目"%s"吗?',
|
||||||
|
'Project activation' => '项目启动',
|
||||||
|
'Move the task to another project' => '移动任务到其它项目',
|
||||||
|
'Move to another project' => '移动到其它项目',
|
||||||
|
'Do you really want to duplicate this task?' => '确定要复制此任务吗?',
|
||||||
|
'Duplicate a task' => '复制任务',
|
||||||
|
'External accounts' => '外部账户',
|
||||||
|
'Account type' => '账户类型',
|
||||||
|
'Local' => '本地',
|
||||||
|
'Remote' => '远程',
|
||||||
|
'Enabled' => '启用',
|
||||||
|
'Disabled' => '停用',
|
||||||
|
'Google account linked' => '已经链接谷歌账号',
|
||||||
|
'Github account linked' => '已经链接Github账号',
|
||||||
|
'Username:' => '用户名:',
|
||||||
|
'Name:' => '姓名:',
|
||||||
|
'Email:' => '电子邮件:',
|
||||||
|
'Default project:' => '默认项目:',
|
||||||
|
'Notifications:' => '通知:',
|
||||||
|
'Notifications' => '通知',
|
||||||
|
'Group:' => '群组:',
|
||||||
|
'Regular user' => '常规用户',
|
||||||
|
'Account type:' => '账户类型:',
|
||||||
|
'Edit profile' => '编辑属性',
|
||||||
|
'Change password' => '修改密码',
|
||||||
|
'Password modification' => '修改密码',
|
||||||
|
'External authentications' => '外部认证',
|
||||||
|
'Google Account' => '谷歌账号',
|
||||||
|
'Github Account' => 'Github 账号',
|
||||||
|
'Never connected.' => '从未连接。',
|
||||||
|
'No account linked.' => '未链接账号。',
|
||||||
|
'Account linked.' => '已经链接账号。',
|
||||||
|
'No external authentication enabled.' => '未启用外部认证。',
|
||||||
|
'Password modified successfully.' => '已经成功修改密码。',
|
||||||
|
'Unable to change the password.' => '无法修改密码。',
|
||||||
|
'Change category for the task "%s"' => '变更任务 "%s" 的分类',
|
||||||
|
'Change category' => '变更分类',
|
||||||
|
'%s updated the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s 更新了任务 <a href="?controller=task&action=show&task_id=%d">#%d</a>',
|
||||||
|
'%s open the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s 开启了任务 <a href="?controller=task&action=show&task_id=%d">#%d</a>',
|
||||||
|
'%s moved the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to the position #%d in the column "%s"' => '%s 将任务 <a href="?controller=task&action=show&task_id=%d">#%d</a> 移动到了"%s"的第#%d个位置',
|
||||||
|
'%s moved the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to the column "%s"' => '%s 移动任务 <a href="?controller=task&action=show&task_id=%d">#%d</a> 到栏目 "%s"',
|
||||||
|
'%s created the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s 创建了任务 <a href="?controller=task&action=show&task_id=%d">#%d</a>',
|
||||||
|
'%s closed the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s 关闭了任务 <a href="?controller=task&action=show&task_id=%d">#%d</a>',
|
||||||
|
'%s created a subtask for the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s 创建了 <a href="?controller=task&action=show&task_id=%d">#%d</a>的子任务',
|
||||||
|
'%s updated a subtask for the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s 更新了 <a href="?controller=task&action=show&task_id=%d">#%d</a>的子任务',
|
||||||
|
'Assigned to %s with an estimate of %s/%sh' => '分配给 %s,预估需要 %s/%s 小时',
|
||||||
|
'Not assigned, estimate of %sh' => '未分配,预估需要 %s 小时',
|
||||||
|
'%s updated a comment on the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s 更新了任务 <a href="?controller=task&action=show&task_id=%d">#%d</a>的评论',
|
||||||
|
'%s commented the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '%s 评论了任务 <a href="?controller=task&action=show&task_id=%d">#%d</a>',
|
||||||
|
'%s\'s activity' => '%s的活动',
|
||||||
|
'No activity.' => '无活动',
|
||||||
|
'RSS feed' => 'RSS 链接',
|
||||||
|
'%s updated a comment on the task #%d' => '%s 更新了任务 #%d 的评论',
|
||||||
|
'%s commented on the task #%d' => '%s 评论了任务 #%d',
|
||||||
|
'%s updated a subtask for the task #%d' => '%s 更新了任务 #%d 的子任务',
|
||||||
|
'%s created a subtask for the task #%d' => '%s 创建了任务 #%d 的子任务',
|
||||||
|
'%s updated the task #%d' => '%s 更新了任务 #%d',
|
||||||
|
'%s created the task #%d' => '%s 创建了任务 #%d',
|
||||||
|
'%s closed the task #%d' => '%s 关闭了任务 #%d',
|
||||||
|
'%s open the task #%d' => '%s 开启了任务 #%d',
|
||||||
|
'%s moved the task #%d to the column "%s"' => '%s 将任务 #%d 移动到栏目 "%s"',
|
||||||
|
'%s moved the task #%d to the position %d in the column "%s"' => '%s将任务#%d移动到"%s"的第 %d 列',
|
||||||
|
'Activity' => '活动',
|
||||||
|
'Default values are "%s"' => '默认值为 "%s"',
|
||||||
|
'Default columns for new projects (Comma-separated)' => '新建项目的默认栏目(用逗号分开)',
|
||||||
|
'Task assignee change' => '任务分配变更',
|
||||||
|
'%s change the assignee of the task #%d to %s' => '%s 将任务 #%d 分配给了 %s',
|
||||||
|
'%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to %s' => '%s 将任务 <a href="?controller=task&action=show&task_id=%d">#%d</a> 分配给 %s',
|
||||||
|
'[%s][Column Change] %s (#%d)' => '[%s][栏目变更] %s (#%d)',
|
||||||
|
'[%s][Position Change] %s (#%d)' => '[%s][位置变更] %s (#%d)',
|
||||||
|
'[%s][Assignee Change] %s (#%d)' => '[%s][任务分配变更] %s (#%d)',
|
||||||
|
'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任务标签修改',
|
||||||
|
'Create a task from an external provider' => '从外部创建任务',
|
||||||
|
'Change the assignee based on an external username' => '根据外部用户名修改任务分配',
|
||||||
|
'Change the category based on an external label' => '根据外部标签修改分类',
|
||||||
|
'Reference' => '参考',
|
||||||
|
'Reference: %s' => '参考:%s',
|
||||||
|
'Label' => '标签',
|
||||||
|
'Database' => '数据库',
|
||||||
|
'About' => '关于',
|
||||||
|
'Database driver:' => '数据库驱动:',
|
||||||
|
'Board settings' => '看板设置',
|
||||||
|
'URL and token' => 'URL和令牌',
|
||||||
|
'Webhook settings' => 'Webhook 设置',
|
||||||
|
'URL for task creation:' => '创建任务的URL:',
|
||||||
|
'Reset token' => '重置令牌',
|
||||||
|
'API endpoint:' => 'API 端点:',
|
||||||
|
'Refresh interval for private board' => '私人看板的刷新时间',
|
||||||
|
'Refresh interval for public board' => '公共看板的刷新时间',
|
||||||
|
'Task highlight period' => '任务高亮时间',
|
||||||
|
'Period (in second) to consider a task was modified recently (0 to disable, 2 days by default)' => '多久内的任务视作刚刚修改(单位:秒,设置为0停用,默认是2天',
|
||||||
|
'Frequency in second (60 seconds by default)' => '频率,单位为秒(默认是60秒)',
|
||||||
|
'Frequency in second (0 to disable this feature, 10 seconds by default)' => '频率,单位为秒(设置为0停用此功能,默认是10秒)',
|
||||||
|
'Application URL' => '应用URL',
|
||||||
|
'Example: http://example.kanboard.net/ (used by email notifications)' => '例如:http://example.kanboard.net/ (用于电子邮件通知)',
|
||||||
|
'Token regenerated.' => '重新生成令牌',
|
||||||
|
'Date format' => '日期格式',
|
||||||
|
'ISO format is always accepted, example: "%s" and "%s"' => 'ISO 格式总是允许的,例如:"%s" 和 "%s"',
|
||||||
|
'New private project' => '新建私有项目',
|
||||||
|
'This project is private' => '此项目为私有项目',
|
||||||
|
'Type here to create a new sub-task' => '要创建新的子任务,请在此输入',
|
||||||
|
'Add' => '添加',
|
||||||
|
'Estimated time: %s hours' => '预计时间:%s小时',
|
||||||
|
'Time spent: %s hours' => '花费时间:%s小时',
|
||||||
|
'Started on %B %e, %Y' => '开始时间: %Y/%m/%d %H:%M ',
|
||||||
|
'Start date' => '启动日期',
|
||||||
|
'Time estimated' => '预计时间',
|
||||||
|
'There is nothing assigned to you.' => '无任务指派给你。',
|
||||||
|
'My tasks' => '我的任务',
|
||||||
|
'Activity stream' => '活动流',
|
||||||
|
'Dashboard' => '面板',
|
||||||
|
'Confirmation' => '确认',
|
||||||
|
// 'Allow everybody to access to this project' => '',
|
||||||
|
// 'Everybody have access to this project.' => '',
|
||||||
|
// 'Webhooks' => '',
|
||||||
|
// 'API' => '',
|
||||||
|
// 'Integration' => '',
|
||||||
|
// 'Github webhook' => '',
|
||||||
|
// 'Help on Github webhook' => '',
|
||||||
|
// 'Create a comment from an external provider' => '',
|
||||||
|
// 'Github issue comment created' => '',
|
||||||
|
);
|
|
@ -1,506 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
return array(
|
|
||||||
'None' => '未知',
|
|
||||||
'edit' => '修改',
|
|
||||||
'Edit' => '修改',
|
|
||||||
'remove' => '移除',
|
|
||||||
'Remove' => '移除',
|
|
||||||
'Update' => '更新',
|
|
||||||
'Yes' => '是',
|
|
||||||
'No' => '否',
|
|
||||||
'cancel' => '取消',
|
|
||||||
'or' => '或者',
|
|
||||||
'Yellow' => '黄色',
|
|
||||||
'Blue' => '蓝色',
|
|
||||||
'Green' => '绿色',
|
|
||||||
'Purple' => '紫色',
|
|
||||||
'Red' => '红色',
|
|
||||||
'Orange' => '橘色',
|
|
||||||
'Grey' => '灰色',
|
|
||||||
'Save' => '保存',
|
|
||||||
'Login' => '登陆',
|
|
||||||
'Official website:' => '官方网站:',
|
|
||||||
'Unassigned' => '未指定',
|
|
||||||
'View this task' => '查看该任务',
|
|
||||||
'Remove user' => '移除用户',
|
|
||||||
'Do you really want to remove this user: "%s"?' => '你确定要移除这个用户吗:"%s"?',
|
|
||||||
'New user' => '新用户',
|
|
||||||
'All users' => '所有用户',
|
|
||||||
'Username' => '用户名',
|
|
||||||
'Password' => '密码',
|
|
||||||
'Default project' => '默认项目',
|
|
||||||
'Administrator' => '管理员',
|
|
||||||
'Sign in' => '登录',
|
|
||||||
'Users' => '用户组',
|
|
||||||
'No user' => '没有用户',
|
|
||||||
'Forbidden' => '禁止',
|
|
||||||
'Access Forbidden' => '禁止进入',
|
|
||||||
'Only administrators can access to this page.' => '只有管理员可以查看该页面。',
|
|
||||||
'Edit user' => '修改用户',
|
|
||||||
'Logout' => '登出',
|
|
||||||
'Bad username or password' => '用户名或密码错误',
|
|
||||||
'users' => '用户组',
|
|
||||||
'projects' => '项目群',
|
|
||||||
'Edit project' => '修改项目',
|
|
||||||
'Name' => '名称',
|
|
||||||
'Activated' => '已激活',
|
|
||||||
'Projects' => '项目群',
|
|
||||||
'No project' => '无项目',
|
|
||||||
'Project' => '项目',
|
|
||||||
'Status' => '状态',
|
|
||||||
'Tasks' => '任务群',
|
|
||||||
'Board' => '看板',
|
|
||||||
'Actions' => '行为',
|
|
||||||
'Inactive' => '未激活',
|
|
||||||
'Active' => '激活',
|
|
||||||
'Column %d' => '第%d栏目',
|
|
||||||
'Add this column' => '加入该栏目',
|
|
||||||
'%d tasks on the board' => '看板目前有%d个任务',
|
|
||||||
'%d tasks in total' => '总共有%d个任务',
|
|
||||||
'Unable to update this board.' => '无法更新该看板。',
|
|
||||||
'Edit board' => '修改看板',
|
|
||||||
'Disable' => '禁用',
|
|
||||||
'Enable' => '启用',
|
|
||||||
'New project' => '新项目',
|
|
||||||
'Do you really want to remove this project: "%s"?' => '你确定要移除该项目吗:"%s"?',
|
|
||||||
'Remove project' => '移除项目',
|
|
||||||
'Boards' => '看板群',
|
|
||||||
'Edit the board for "%s"' => '为"%s"修改看板',
|
|
||||||
'All projects' => '所有项目',
|
|
||||||
'Change columns' => '更改栏目',
|
|
||||||
'Add a new column' => '添加新栏目',
|
|
||||||
'Title' => '标题',
|
|
||||||
'Add Column' => '添加栏目',
|
|
||||||
'Project "%s"' => '项目 "%s"',
|
|
||||||
'Nobody assigned' => '无人被指派',
|
|
||||||
'Assigned to %s' => '指派给 %s',
|
|
||||||
'Remove a column' => '移除一个栏目',
|
|
||||||
'Remove a column from a board' => '从看板移除一个栏目',
|
|
||||||
'Unable to remove this column.' => '无法移除该栏目。',
|
|
||||||
'Do you really want to remove this column: "%s"?' => '你确定要移除该栏目:"%s"吗?',
|
|
||||||
'This action will REMOVE ALL TASKS associated to this column!' => '该行为将移除与该栏目相关的所有项目!',
|
|
||||||
'Settings' => '设置',
|
|
||||||
'Application settings' => '应用设置',
|
|
||||||
'Language' => '语言',
|
|
||||||
'Webhooks token:' => '页面钩子令牌:',
|
|
||||||
// 'API token:' => '',
|
|
||||||
'More information' => '更多信息',
|
|
||||||
'Database size:' => '数据库大小:',
|
|
||||||
'Download the database' => '下载数据库',
|
|
||||||
'Optimize the database' => '优化数据库',
|
|
||||||
'(VACUUM command)' => '(数据库归整指令)',
|
|
||||||
'(Gzip compressed Sqlite file)' => '(用Gzip压缩Sqlite文件)',
|
|
||||||
'User settings' => '用户设置',
|
|
||||||
'My default project:' => '我的默认项目:',
|
|
||||||
'Close a task' => '关闭一个项目',
|
|
||||||
'Do you really want to close this task: "%s"?' => '你确定要关闭该项目?"%s"',
|
|
||||||
'Edit a task' => '修改一个项目',
|
|
||||||
'Column' => '栏目',
|
|
||||||
'Color' => '颜色',
|
|
||||||
'Assignee' => '负责人',
|
|
||||||
'Create another task' => '创建另一个项目',
|
|
||||||
'New task' => '新项目',
|
|
||||||
'Open a task' => '开一个项目',
|
|
||||||
'Do you really want to open this task: "%s"?' => '你确定要开这个项目吗?"%s"',
|
|
||||||
'Back to the board' => '回到看板',
|
|
||||||
'Created on %B %e, %Y at %k:%M %p' => '在%d/%m/%Y %H:%M创建',
|
|
||||||
'There is nobody assigned' => '无人负责',
|
|
||||||
'Column on the board:' => '看板上的栏目:',
|
|
||||||
'Status is open' => '开放状态',
|
|
||||||
'Status is closed' => '关闭状态',
|
|
||||||
'Close this task' => '关闭该项目',
|
|
||||||
'Open this task' => '开放该项目',
|
|
||||||
'There is no description.' => '无描述。',
|
|
||||||
'Add a new task' => '添加新任务',
|
|
||||||
'The username is required' => '需要用户名',
|
|
||||||
'The maximum length is %d characters' => '最长%d个英文字符',
|
|
||||||
'The minimum length is %d characters' => '最短%d个英文自负',
|
|
||||||
'The password is required' => '需要密码',
|
|
||||||
'This value must be an integer' => '该值必须为整数',
|
|
||||||
'The username must be unique' => '用户名必须唯一',
|
|
||||||
'The username must be alphanumeric' => '用户名必须是英文字符或数字组成',
|
|
||||||
'The user id is required' => '用户id是必须的',
|
|
||||||
// 'Passwords don\'t match' => '',
|
|
||||||
'The confirmation is required' => '需要确认',
|
|
||||||
'The column is required' => '需要指定栏目',
|
|
||||||
'The project is required' => '需要指定项目',
|
|
||||||
'The color is required' => '需要指定颜色',
|
|
||||||
'The id is required' => '需要指定id',
|
|
||||||
'The project id is required' => '需要指定项目id',
|
|
||||||
'The project name is required' => '需要指定项目名称',
|
|
||||||
'This project must be unique' => '项目名称必须唯一',
|
|
||||||
'The title is required' => '需要指定标题',
|
|
||||||
'The language 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.' => '数据库优化完成。',
|
|
||||||
'Your project have been created successfully.' => '您的项目已经成功创建。',
|
|
||||||
'Unable to create your project.' => '无法为您创建项目。',
|
|
||||||
'Project updated successfully.' => '项目成功更新。',
|
|
||||||
'Unable to update this project.' => '无法更新该项目。',
|
|
||||||
'Unable to remove this project.' => '无法移除该项目。',
|
|
||||||
'Project removed successfully.' => '项目成功移除。',
|
|
||||||
'Project activated successfully.' => '项目成功激活。',
|
|
||||||
'Unable to activate this project.' => '无法激活该项目。',
|
|
||||||
'Project disabled successfully.' => '项目成功禁用。',
|
|
||||||
'Unable to disable this project.' => '无法禁用该项目。',
|
|
||||||
'Unable to open this task.' => '无法开启该任务。',
|
|
||||||
'Task opened successfully.' => '任务开启成功。',
|
|
||||||
'Unable to close this task.' => '无法关闭该任务。',
|
|
||||||
'Task closed successfully.' => '任务成功关闭。',
|
|
||||||
'Unable to update your task.' => '无法更新您的任务。',
|
|
||||||
'Task updated successfully.' => '任务成功更新。',
|
|
||||||
'Unable to create your task.' => '无法为您创建项目。',
|
|
||||||
'Task created successfully.' => '任务成功创建。',
|
|
||||||
'User created successfully.' => '用户成功创建。',
|
|
||||||
'Unable to create your user.' => '无法创建用户。',
|
|
||||||
'User updated successfully.' => '用户成功更新。',
|
|
||||||
'Unable to update your user.' => '无法为您更新用户。',
|
|
||||||
'User removed successfully.' => '用户成功移除。',
|
|
||||||
'Unable to remove this user.' => '无法移除该用户。',
|
|
||||||
'Board updated successfully.' => '看板成功更新。',
|
|
||||||
'Ready' => '预备',
|
|
||||||
'Backlog' => '积压',
|
|
||||||
'Work in progress' => '工作进行中',
|
|
||||||
'Done' => '完成',
|
|
||||||
'Application version:' => '应用程序版本',
|
|
||||||
'Completed on %B %e, %Y at %k:%M %p' => '于%Y年%m月%d日%H时%M分完成',
|
|
||||||
'%B %e, %Y at %k:%M %p' => '%Y年%m月%d日%H时%M分',
|
|
||||||
'Date created' => '创建时间',
|
|
||||||
'Date completed' => '完成时间',
|
|
||||||
'Id' => '昵称',
|
|
||||||
'No task' => '无任务',
|
|
||||||
'Completed tasks' => '已完成任务',
|
|
||||||
'List of projects' => '项目列表',
|
|
||||||
'Completed tasks for "%s"' => '任务因"%s"原因完成',
|
|
||||||
'%d closed tasks' => '%d个已关闭任务',
|
|
||||||
'No task for this project' => '该项目尚无任务',
|
|
||||||
'Public link' => '公开链接',
|
|
||||||
'There is no column in your project!' => '该项目尚无栏目项!',
|
|
||||||
'Change assignee' => '被指派人变更',
|
|
||||||
'Change assignee for the task "%s"' => '为任务"%s"更改被指派人',
|
|
||||||
'Timezone' => '时区',
|
|
||||||
'Sorry, I didn\'t found this information in my database!' => '抱歉,无法在数据库中找到该信息!',
|
|
||||||
'Page not found' => '页面未找到',
|
|
||||||
'Complexity' => '评估分值',
|
|
||||||
'limit' => '限制',
|
|
||||||
'Task limit' => '任务限制',
|
|
||||||
'This value must be greater than %d' => '该数值必须大于%d',
|
|
||||||
'Edit project access list' => '编辑项目存取列表',
|
|
||||||
'Edit users access' => '编辑用户存取权限',
|
|
||||||
'Allow this user' => '允许该用户',
|
|
||||||
'Only those users have access to this project:' => '只有这些用户有该项目的存取权限:',
|
|
||||||
'Don\'t forget that administrators have access to everything.' => '别忘了管理员有一切的权限。',
|
|
||||||
'revoke' => '撤销',
|
|
||||||
'List of authorized users' => '已授权的用户列表',
|
|
||||||
'User' => '用户',
|
|
||||||
'Everybody have access to this project.' => '任何人都有该项目权限。',
|
|
||||||
'You are not allowed to access to this project.' => '您对该项目没有权限。',
|
|
||||||
'Comments' => '评论',
|
|
||||||
'Post comment' => '发表评论',
|
|
||||||
'Write your text in Markdown' => '用Markdown格式编写',
|
|
||||||
'Leave a comment' => '留言',
|
|
||||||
'Comment is required' => '必须得有评论',
|
|
||||||
'Leave a description' => '给一个描述',
|
|
||||||
'Comment added successfully.' => '评论成功添加。',
|
|
||||||
'Unable to create your comment.' => '无法创建评论。',
|
|
||||||
'The description is required' => '必须得有描述',
|
|
||||||
'Edit this task' => '编辑该任务',
|
|
||||||
'Due Date' => '到期',
|
|
||||||
'm/d/Y' => 'Y/m/d',
|
|
||||||
'month/day/year' => '年/月/日',
|
|
||||||
'Invalid date' => '无效日期',
|
|
||||||
'Must be done before %B %e, %Y' => '必须在%Y年%m月%d日前完成',
|
|
||||||
'%B %e, %Y' => '%Y/%m/%d',
|
|
||||||
'Automatic actions' => '自动行为',
|
|
||||||
'Your automatic action have been created successfully.' => '您的自动行为已成功创建',
|
|
||||||
'Unable to create your automatic action.' => '无法为您创建自动行为。',
|
|
||||||
'Remove an action' => '移除一个行为。',
|
|
||||||
'Unable to remove this action.' => '无法移除该行为',
|
|
||||||
'Action removed successfully.' => '成功移除行为。',
|
|
||||||
'Automatic actions for the project "%s"' => '项目"%s"的自动行为',
|
|
||||||
'Defined actions' => '已定义的行为',
|
|
||||||
'Add an action' => '添加一个行为',
|
|
||||||
'Event name' => '事件名称',
|
|
||||||
'Action name' => '行为名称',
|
|
||||||
'Action parameters' => '行为参数',
|
|
||||||
'Action' => '行为',
|
|
||||||
'Event' => '事件',
|
|
||||||
'When the selected event occurs execute the corresponding action.' => '当所选事件发生时执行相应行为。',
|
|
||||||
'Next step' => '下一步',
|
|
||||||
'Define action parameters' => '定义行为参数',
|
|
||||||
'Save this action' => '保存该行为',
|
|
||||||
'Do you really want to remove this action: "%s"?' => '确定要益处该行为"%s"吗?',
|
|
||||||
'Remove an automatic action' => '移除一个自动行为',
|
|
||||||
'Close the task' => '关闭任务',
|
|
||||||
'Assign the task to a specific user' => '将该任务指派给一个用户',
|
|
||||||
'Assign the task to the person who does the action' => '将任务指派给产生该行为的用户',
|
|
||||||
'Duplicate the task to another project' => '复制该任务到另一项目',
|
|
||||||
'Move a task to another column' => '移动任务到另一栏目',
|
|
||||||
'Move a task to another position in the same column' => '将任务移到该栏目另一位置',
|
|
||||||
'Task modification' => '任务修改',
|
|
||||||
'Task creation' => '任务创建',
|
|
||||||
'Open a closed task' => '开启已关闭任务',
|
|
||||||
'Closing a task' => '正在关闭任务',
|
|
||||||
'Assign a color to a specific user' => '为特定用户指派颜色',
|
|
||||||
'Column title' => '栏目名称',
|
|
||||||
'Position' => '位置',
|
|
||||||
'Move Up' => '往上移',
|
|
||||||
'Move Down' => '往下移',
|
|
||||||
'Duplicate to another project' => '复制到另一项目',
|
|
||||||
'Duplicate' => '复制',
|
|
||||||
'link' => '连接',
|
|
||||||
'Update this comment' => '更新该评论',
|
|
||||||
'Comment updated successfully.' => '评论成功更新。',
|
|
||||||
'Unable to update your comment.' => '无法更新您的评论。',
|
|
||||||
'Remove a comment' => '移除评论',
|
|
||||||
'Comment removed successfully.' => '评论成功移除。',
|
|
||||||
'Unable to remove this comment.' => '无法移除该评论。',
|
|
||||||
'Do you really want to remove this comment?' => '确定要移除评论吗?',
|
|
||||||
'Only administrators or the creator of the comment can access to this page.' => '只有管理员或评论创建者可以进入该页面。',
|
|
||||||
'Details' => '细节',
|
|
||||||
'Current password for the user "%s"' => '用户"%s"的当前密码',
|
|
||||||
'The current password is required' => '需要输入当前密码',
|
|
||||||
'Wrong password' => '密码错误',
|
|
||||||
'Reset all tokens' => '重置所有令牌',
|
|
||||||
'All tokens have been regenerated.' => '所有令牌都重新生成了。',
|
|
||||||
'Unknown' => '未知',
|
|
||||||
'Last logins' => '上次登录',
|
|
||||||
'Login date' => '登录日期',
|
|
||||||
'Authentication method' => '认证方式',
|
|
||||||
'IP address' => 'IP地址',
|
|
||||||
'User agent' => '用户代理',
|
|
||||||
'Persistent connections' => '持续连接',
|
|
||||||
'No session.' => '无会话',
|
|
||||||
'Expiration date' => '过期',
|
|
||||||
'Remember Me' => '记住我',
|
|
||||||
'Creation date' => '创建日期',
|
|
||||||
'Filter by user' => '按用户过滤',
|
|
||||||
'Filter by due date' => '按到期时间过滤',
|
|
||||||
'Everybody' => '所有人',
|
|
||||||
'Open' => '打开',
|
|
||||||
'Closed' => '关闭',
|
|
||||||
'Search' => '查找',
|
|
||||||
'Nothing found.' => '没找到。',
|
|
||||||
'Search in the project "%s"' => '在项目"%s"中查找',
|
|
||||||
'Due date' => '到期',
|
|
||||||
'Others formats accepted: %s and %s' => '允许其他格式:%s和%s',
|
|
||||||
'Description' => '描述',
|
|
||||||
'%d comments' => '%d个评论',
|
|
||||||
'%d comment' => '%d个评论',
|
|
||||||
'Email address invalid' => 'Email地址无效',
|
|
||||||
'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帐号已成功与账户配置关联。',
|
|
||||||
'Email' => 'Email',
|
|
||||||
'Link my Google Account' => '关联我的google帐号',
|
|
||||||
'Unlink my Google Account' => '去除我的google帐号关联',
|
|
||||||
'Login with my Google Account' => '用我的google帐号登录',
|
|
||||||
'Project not found.' => '未发现项目',
|
|
||||||
'Task #%d' => '任务 #%d',
|
|
||||||
'Task removed successfully.' => '任务成功去除',
|
|
||||||
'Unable to remove this task.' => '无法移除该任务。',
|
|
||||||
'Remove a task' => '移除一个任务',
|
|
||||||
'Do you really want to remove this task: "%s"?' => '确定要溢出该任务"%s"吗?',
|
|
||||||
'Assign automatically a color based on a category' => '基于一个分类自动指派颜色',
|
|
||||||
'Assign automatically a category based on a color' => '基于一种颜色自动指派分类',
|
|
||||||
'Task creation or modification' => '任务创建或修改',
|
|
||||||
'Category' => '分类',
|
|
||||||
'Category:' => '分类:',
|
|
||||||
'Categories' => '分类',
|
|
||||||
'Category not found.' => '未找到分类。',
|
|
||||||
'Your category have been created successfully.' => '成功为您创建分类。',
|
|
||||||
'Unable to create your category.' => '无法为您创建分类。',
|
|
||||||
'Your category have been updated successfully.' => '成功为您更新分类。',
|
|
||||||
'Unable to update your category.' => '无法为您更新分类。',
|
|
||||||
'Remove a category' => '移除一个分类',
|
|
||||||
'Category removed successfully.' => '分类成功移除。',
|
|
||||||
'Unable to remove this category.' => '无法移除该分类。',
|
|
||||||
'Category modification for the project "%s"' => '为项目"%s"修改分类',
|
|
||||||
'Category Name' => '分类名称',
|
|
||||||
'Categories for the project "%s"' => '项目"%s"的分类',
|
|
||||||
'Add a new category' => '加入一个新分类',
|
|
||||||
'Do you really want to remove this category: "%s"?' => '您确定要移除分类"%s"吗?',
|
|
||||||
'Filter by category' => '按分类过滤',
|
|
||||||
'All categories' => '所有分类',
|
|
||||||
'No category' => '无分类',
|
|
||||||
'The name is required' => '必须要有名字',
|
|
||||||
'Remove a file' => '移除一个文件',
|
|
||||||
'Unable to remove this file.' => '无法移除该文件。',
|
|
||||||
'File removed successfully.' => '文件成功移除。',
|
|
||||||
'Attach a document' => '附上一个文档',
|
|
||||||
'Do you really want to remove this file: "%s"?' => '您确定要移除文件"%s"吗?',
|
|
||||||
'open' => '打开',
|
|
||||||
'Attachments' => '附件',
|
|
||||||
'Edit the task' => '修改任务',
|
|
||||||
'Edit the description' => '修改描述',
|
|
||||||
'Add a comment' => '添加一个注释',
|
|
||||||
'Edit a comment' => '修改一个注释',
|
|
||||||
'Summary' => '概要',
|
|
||||||
// 'Time tracking' => '',
|
|
||||||
// 'Estimate:' => '',
|
|
||||||
// 'Spent:' => '',
|
|
||||||
// 'Do you really want to remove this sub-task?' => '',
|
|
||||||
// 'Remaining:' => '',
|
|
||||||
'hours' => '小时',
|
|
||||||
// 'spent' => '',
|
|
||||||
// 'estimated' => '',
|
|
||||||
// 'Sub-Tasks' => '',
|
|
||||||
'Add a sub-task' => '添加一个子任务',
|
|
||||||
'Original Estimate' => '初步预计耗时',
|
|
||||||
'Create another sub-task' => '创建另一个子任务',
|
|
||||||
// 'Time Spent' => '',
|
|
||||||
// 'Edit a sub-task' => '',
|
|
||||||
// 'Remove a sub-task' => '',
|
|
||||||
// 'The time must be a numeric value' => '',
|
|
||||||
// 'Todo' => '',
|
|
||||||
// 'In progress' => '',
|
|
||||||
// 'Sub-task removed successfully.' => '',
|
|
||||||
// 'Unable to remove this sub-task.' => '',
|
|
||||||
// 'Sub-task updated successfully.' => '',
|
|
||||||
// 'Unable to update your sub-task.' => '',
|
|
||||||
// 'Unable to create your sub-task.' => '',
|
|
||||||
// 'Sub-task added successfully.' => '',
|
|
||||||
// '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' => '',
|
|
||||||
// 'Created by %s' => '',
|
|
||||||
// 'Last modified on %B %e, %Y at %k:%M %p' => '',
|
|
||||||
// 'Tasks Export' => '',
|
|
||||||
// 'Tasks exportation for "%s"' => '',
|
|
||||||
// 'Start Date' => '',
|
|
||||||
// 'End Date' => '',
|
|
||||||
// 'Execute' => '',
|
|
||||||
// 'Task Id' => '',
|
|
||||||
// 'Creator' => '',
|
|
||||||
// 'Modification date' => '',
|
|
||||||
// 'Completion date' => '',
|
|
||||||
// 'Webhook URL for task creation' => '',
|
|
||||||
// 'Webhook URL for task modification' => '',
|
|
||||||
// 'Clone' => '',
|
|
||||||
// 'Clone Project' => '',
|
|
||||||
// 'Project cloned successfully.' => '',
|
|
||||||
// 'Unable to clone this project.' => '',
|
|
||||||
// 'Email notifications' => '',
|
|
||||||
// 'Enable email notifications' => '',
|
|
||||||
// 'Task position:' => '',
|
|
||||||
// 'The task #%d have been opened.' => '',
|
|
||||||
// 'The task #%d have been closed.' => '',
|
|
||||||
// 'Sub-task updated' => '',
|
|
||||||
// 'Title:' => '',
|
|
||||||
// 'Status:' => '',
|
|
||||||
// 'Assignee:' => '',
|
|
||||||
// 'Time tracking:' => '',
|
|
||||||
// 'New sub-task' => '',
|
|
||||||
// 'New attachment added "%s"' => '',
|
|
||||||
// 'Comment updated' => '',
|
|
||||||
// 'New comment posted by %s' => '',
|
|
||||||
// 'List of due tasks for the project "%s"' => '',
|
|
||||||
// '[%s][New attachment] %s (#%d)' => '',
|
|
||||||
// '[%s][New comment] %s (#%d)' => '',
|
|
||||||
// '[%s][Comment updated] %s (#%d)' => '',
|
|
||||||
// '[%s][New subtask] %s (#%d)' => '',
|
|
||||||
// '[%s][Subtask updated] %s (#%d)' => '',
|
|
||||||
// '[%s][New task] %s (#%d)' => '',
|
|
||||||
// '[%s][Task updated] %s (#%d)' => '',
|
|
||||||
// '[%s][Task closed] %s (#%d)' => '',
|
|
||||||
// '[%s][Task opened] %s (#%d)' => '',
|
|
||||||
// '[%s][Due tasks]' => '',
|
|
||||||
// '[Kanboard] Notification' => '',
|
|
||||||
// 'I want to receive notifications only for those projects:' => '',
|
|
||||||
// 'view the task on Kanboard' => '',
|
|
||||||
// 'Public access' => '',
|
|
||||||
// 'Categories management' => '',
|
|
||||||
// 'Users management' => '',
|
|
||||||
// 'Active tasks' => '',
|
|
||||||
// 'Disable public access' => '',
|
|
||||||
// 'Enable public access' => '',
|
|
||||||
// 'Active projects' => '',
|
|
||||||
// 'Inactive projects' => '',
|
|
||||||
// 'Public access disabled' => '',
|
|
||||||
// 'Do you really want to disable this project: "%s"?' => '',
|
|
||||||
// 'Do you really want to duplicate this project: "%s"?' => '',
|
|
||||||
// 'Do you really want to enable this project: "%s"?' => '',
|
|
||||||
// 'Project activation' => '',
|
|
||||||
// 'Move the task to another project' => '',
|
|
||||||
// 'Move to another project' => '',
|
|
||||||
// 'Do you really want to duplicate this task?' => '',
|
|
||||||
// 'Duplicate a task' => '',
|
|
||||||
// 'External accounts' => '',
|
|
||||||
// 'Account type' => '',
|
|
||||||
// 'Local' => '',
|
|
||||||
// 'Remote' => '',
|
|
||||||
// 'Enabled' => '',
|
|
||||||
// 'Disabled' => '',
|
|
||||||
// 'Google account linked' => '',
|
|
||||||
// 'Github account linked' => '',
|
|
||||||
// 'Username:' => '',
|
|
||||||
// 'Name:' => '',
|
|
||||||
// 'Email:' => '',
|
|
||||||
// 'Default project:' => '',
|
|
||||||
// 'Notifications:' => '',
|
|
||||||
// 'Group:' => '',
|
|
||||||
// 'Regular user' => '',
|
|
||||||
// 'Account type:' => '',
|
|
||||||
// 'Edit profile' => '',
|
|
||||||
// 'Change password' => '',
|
|
||||||
// 'Password modification' => '',
|
|
||||||
// 'External authentications' => '',
|
|
||||||
// 'Google Account' => '',
|
|
||||||
// 'Github Account' => '',
|
|
||||||
// 'Never connected.' => '',
|
|
||||||
// 'No account linked.' => '',
|
|
||||||
// 'Account linked.' => '',
|
|
||||||
// 'No external authentication enabled.' => '',
|
|
||||||
// 'Password modified successfully.' => '',
|
|
||||||
// 'Unable to change the password.' => '',
|
|
||||||
// 'Change category for the task "%s"' => '',
|
|
||||||
// 'Change category' => '',
|
|
||||||
// '%s updated the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '',
|
|
||||||
// '%s open the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '',
|
|
||||||
// '%s moved the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to the position #%d in the column "%s"' => '',
|
|
||||||
// '%s moved the task <a href="?controller=task&action=show&task_id=%d">#%d</a> to the column "%s"' => '',
|
|
||||||
// '%s created the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '',
|
|
||||||
// '%s closed the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '',
|
|
||||||
// '%s created a subtask for the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '',
|
|
||||||
// '%s updated a subtask for the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '',
|
|
||||||
// 'Assigned to %s with an estimate of %s/%sh' => '',
|
|
||||||
// 'Not assigned, estimate of %sh' => '',
|
|
||||||
// '%s updated a comment on the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '',
|
|
||||||
// '%s commented the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '',
|
|
||||||
// '%s\'s activity' => '',
|
|
||||||
// 'No activity.' => '',
|
|
||||||
// 'RSS feed' => '',
|
|
||||||
// '%s updated a comment on the task #%d' => '',
|
|
||||||
// '%s commented on the task #%d' => '',
|
|
||||||
// '%s updated a subtask for the task #%d' => '',
|
|
||||||
// '%s created a subtask for the task #%d' => '',
|
|
||||||
// '%s updated the task #%d' => '',
|
|
||||||
// '%s created the task #%d' => '',
|
|
||||||
// '%s closed the task #%d' => '',
|
|
||||||
// '%s open the task #%d' => '',
|
|
||||||
// '%s moved the task #%d to the column "%s"' => '',
|
|
||||||
// '%s moved the task #%d to the position %d in the column "%s"' => '',
|
|
||||||
// 'Activity' => '',
|
|
||||||
// 'Default values are "%s"' => '',
|
|
||||||
// 'Default columns for new projects (Comma-separated)' => '',
|
|
||||||
// 'Task assignee change' => '',
|
|
||||||
// '%s change the assignee of the task #%d' => '',
|
|
||||||
// '%s change the assignee of the task <a href="?controller=task&action=show&task_id=%d">#%d</a>' => '',
|
|
||||||
// '[%s][Column Change] %s (#%d)' => '',
|
|
||||||
// '[%s][Position Change] %s (#%d)' => '',
|
|
||||||
// '[%s][Assignee Change] %s (#%d)' => '',
|
|
||||||
// 'New password for the user "%s"' => '',
|
|
||||||
);
|
|
|
@ -18,9 +18,10 @@ class Acl extends Base
|
||||||
*/
|
*/
|
||||||
private $public_actions = array(
|
private $public_actions = array(
|
||||||
'user' => array('login', 'check', 'google', 'github'),
|
'user' => array('login', 'check', 'google', 'github'),
|
||||||
'task' => array('add', 'readonly'),
|
'task' => array('readonly'),
|
||||||
'board' => array('readonly'),
|
'board' => array('readonly'),
|
||||||
'project' => array('feed'),
|
'project' => array('feed'),
|
||||||
|
'webhook' => array('task', 'github'),
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,13 +32,15 @@ class Acl extends Base
|
||||||
*/
|
*/
|
||||||
private $user_actions = array(
|
private $user_actions = array(
|
||||||
'app' => array('index'),
|
'app' => array('index'),
|
||||||
'board' => array('index', 'show', 'save', 'check', 'changeassignee', 'updateassignee', 'changecategory', 'updatecategory'),
|
'board' => array('index', 'show', 'save', 'check', 'changeassignee', 'updateassignee', 'changecategory', 'updatecategory', 'movecolumn', 'edit', 'update', 'add', 'confirm', 'remove'),
|
||||||
'project' => array('tasks', 'index', 'forbidden', 'search', 'export', 'show', 'activity'),
|
'project' => array('index', 'show', 'export', 'share', 'edit', 'update', 'users', 'remove', 'duplicate', 'disable', 'enable', 'activity', 'search', 'tasks', 'create', 'save'),
|
||||||
'user' => array('index', 'edit', 'forbidden', 'logout', 'index', 'show', 'external', 'unlinkgoogle', 'unlinkgithub', 'sessions', 'removesession', 'last', 'notifications', 'password'),
|
'user' => array('edit', 'forbidden', 'logout', 'show', 'external', 'unlinkgoogle', 'unlinkgithub', 'sessions', 'removesession', 'last', 'notifications', 'password'),
|
||||||
'comment' => array('create', 'save', 'confirm', 'remove', 'update', 'edit', 'forbidden'),
|
'comment' => array('create', 'save', 'confirm', 'remove', 'update', 'edit', 'forbidden'),
|
||||||
'file' => array('create', 'save', 'download', 'confirm', 'remove', 'open', 'image'),
|
'file' => array('create', 'save', 'download', 'confirm', 'remove', 'open', 'image'),
|
||||||
'subtask' => array('create', 'save', 'edit', 'update', 'confirm', 'remove'),
|
'subtask' => array('create', 'save', 'edit', 'update', 'confirm', 'remove', 'togglestatus'),
|
||||||
'task' => array('show', 'create', 'save', 'edit', 'update', 'close', 'open', 'duplicate', 'remove', 'description', 'move', 'copy'),
|
'task' => array('show', 'create', 'save', 'edit', 'update', 'close', 'open', 'duplicate', 'remove', 'description', 'move', 'copy', 'time'),
|
||||||
|
'category' => array('index', 'save', 'edit', 'update', 'confirm', 'remove'),
|
||||||
|
'action' => array('index', 'event', 'params', 'create', 'confirm', 'remove'),
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -36,8 +36,9 @@ class Action extends Base
|
||||||
*/
|
*/
|
||||||
public function getAvailableActions()
|
public function getAvailableActions()
|
||||||
{
|
{
|
||||||
return array(
|
$values = array(
|
||||||
'TaskClose' => t('Close the task'),
|
'TaskClose' => t('Close a task'),
|
||||||
|
'TaskOpen' => t('Open a task'),
|
||||||
'TaskAssignSpecificUser' => t('Assign the task to a specific user'),
|
'TaskAssignSpecificUser' => t('Assign the task to a specific user'),
|
||||||
'TaskAssignCurrentUser' => t('Assign the task to the person who does the action'),
|
'TaskAssignCurrentUser' => t('Assign the task to the person who does the action'),
|
||||||
'TaskDuplicateAnotherProject' => t('Duplicate the task to another project'),
|
'TaskDuplicateAnotherProject' => t('Duplicate the task to another project'),
|
||||||
|
@ -45,7 +46,15 @@ class Action extends Base
|
||||||
'TaskAssignColorUser' => t('Assign a color to a specific user'),
|
'TaskAssignColorUser' => t('Assign a color to a specific user'),
|
||||||
'TaskAssignColorCategory' => t('Assign automatically a color based on a category'),
|
'TaskAssignColorCategory' => t('Assign automatically a color based on a category'),
|
||||||
'TaskAssignCategoryColor' => t('Assign automatically a category based on a color'),
|
'TaskAssignCategoryColor' => t('Assign automatically a category based on a color'),
|
||||||
|
'CommentCreation' => t('Create a comment from an external provider'),
|
||||||
|
'TaskCreation' => t('Create a task from an external provider'),
|
||||||
|
'TaskAssignUser' => t('Change the assignee based on an external username'),
|
||||||
|
'TaskAssignCategoryLabel' => t('Change the category based on an external label'),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
asort($values);
|
||||||
|
|
||||||
|
return $values;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -56,16 +65,48 @@ class Action extends Base
|
||||||
*/
|
*/
|
||||||
public function getAvailableEvents()
|
public function getAvailableEvents()
|
||||||
{
|
{
|
||||||
return array(
|
$values = array(
|
||||||
Task::EVENT_MOVE_COLUMN => t('Move a task to another column'),
|
Task::EVENT_MOVE_COLUMN => t('Move a task to another column'),
|
||||||
Task::EVENT_MOVE_POSITION => t('Move a task to another position in the same column'),
|
|
||||||
Task::EVENT_UPDATE => t('Task modification'),
|
Task::EVENT_UPDATE => t('Task modification'),
|
||||||
Task::EVENT_CREATE => t('Task creation'),
|
Task::EVENT_CREATE => t('Task creation'),
|
||||||
Task::EVENT_OPEN => t('Open a closed task'),
|
Task::EVENT_OPEN => t('Open a closed task'),
|
||||||
Task::EVENT_CLOSE => t('Closing a task'),
|
Task::EVENT_CLOSE => t('Closing a task'),
|
||||||
Task::EVENT_CREATE_UPDATE => t('Task creation or modification'),
|
Task::EVENT_CREATE_UPDATE => t('Task creation or modification'),
|
||||||
Task::EVENT_ASSIGNEE_CHANGE => t('Task assignee change'),
|
Task::EVENT_ASSIGNEE_CHANGE => t('Task assignee change'),
|
||||||
|
GithubWebhook::EVENT_COMMIT => t('Github commit received'),
|
||||||
|
GithubWebhook::EVENT_ISSUE_OPENED => t('Github issue opened'),
|
||||||
|
GithubWebhook::EVENT_ISSUE_CLOSED => t('Github issue closed'),
|
||||||
|
GithubWebhook::EVENT_ISSUE_REOPENED => t('Github issue reopened'),
|
||||||
|
GithubWebhook::EVENT_ISSUE_ASSIGNEE_CHANGE => t('Github issue assignee change'),
|
||||||
|
GithubWebhook::EVENT_ISSUE_LABEL_CHANGE => t('Github issue label change'),
|
||||||
|
GithubWebhook::EVENT_ISSUE_COMMENT => t('Github issue comment created'),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
asort($values);
|
||||||
|
|
||||||
|
return $values;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the name and description of compatible actions
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param string $action_name Action name
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getCompatibleEvents($action_name)
|
||||||
|
{
|
||||||
|
$action = $this->load($action_name, 0, '');
|
||||||
|
$compatible_events = $action->getCompatibleEvents();
|
||||||
|
$events = array();
|
||||||
|
|
||||||
|
foreach ($this->getAvailableEvents() as $event_name => $event_description) {
|
||||||
|
if (in_array($event_name, $compatible_events)) {
|
||||||
|
$events[$event_name] = $event_description;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $events;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -115,7 +156,7 @@ class Action extends Base
|
||||||
|
|
||||||
foreach ($this->getAll() as $action) {
|
foreach ($this->getAll() as $action) {
|
||||||
|
|
||||||
$action = $this->load($action['action_name'], $action['project_id']);
|
$action = $this->load($action['action_name'], $action['project_id'], $action['event_name']);
|
||||||
$params += $action->getActionRequiredParameters();
|
$params += $action->getActionRequiredParameters();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,7 +242,7 @@ class Action extends Base
|
||||||
{
|
{
|
||||||
foreach ($this->getAll() as $action) {
|
foreach ($this->getAll() as $action) {
|
||||||
|
|
||||||
$listener = $this->load($action['action_name'], $action['project_id']);
|
$listener = $this->load($action['action_name'], $action['project_id'], $action['event_name']);
|
||||||
|
|
||||||
foreach ($action['params'] as $param) {
|
foreach ($action['params'] as $param) {
|
||||||
$listener->setParam($param['name'], $param['value']);
|
$listener->setParam($param['name'], $param['value']);
|
||||||
|
@ -217,19 +258,13 @@ class Action extends Base
|
||||||
* @access public
|
* @access public
|
||||||
* @param string $name Action class name
|
* @param string $name Action class name
|
||||||
* @param integer $project_id Project id
|
* @param integer $project_id Project id
|
||||||
* @throws \LogicException
|
* @param string $event Event name
|
||||||
* @return \Core\Listener Action Instance
|
* @return \Core\Listener Action instance
|
||||||
*/
|
*/
|
||||||
public function load($name, $project_id)
|
public function load($name, $project_id, $event)
|
||||||
{
|
{
|
||||||
$className = '\Action\\'.$name;
|
$className = '\Action\\'.$name;
|
||||||
|
return new $className($this->registry, $project_id, $event);
|
||||||
if ($name === 'TaskAssignCurrentUser') {
|
|
||||||
return new $className($project_id, new Task($this->registry), new Acl($this->registry));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return new $className($project_id, new Task($this->registry));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace Model;
|
namespace Model;
|
||||||
|
|
||||||
|
use Core\Request;
|
||||||
use Auth\Database;
|
use Auth\Database;
|
||||||
use SimpleValidator\Validator;
|
use SimpleValidator\Validator;
|
||||||
use SimpleValidator\Validators;
|
use SimpleValidator\Validators;
|
||||||
|
@ -117,7 +118,7 @@ class Authentication extends Base
|
||||||
if (! empty($values['remember_me'])) {
|
if (! empty($values['remember_me'])) {
|
||||||
|
|
||||||
$credentials = $this->backend('rememberMe')
|
$credentials = $this->backend('rememberMe')
|
||||||
->create($this->acl->getUserId(), $this->user->getIpAddress(), $this->user->getUserAgent());
|
->create($this->acl->getUserId(), Request::getIpAddress(), Request::getUserAgent());
|
||||||
|
|
||||||
$this->backend('rememberMe')->writeCookie($credentials['token'], $credentials['sequence'], $credentials['expiration']);
|
$this->backend('rememberMe')->writeCookie($credentials['token'], $credentials['sequence'], $credentials['expiration']);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,14 +19,23 @@ use PicoDb\Database;
|
||||||
* @property \Model\Board $board
|
* @property \Model\Board $board
|
||||||
* @property \Model\Category $category
|
* @property \Model\Category $category
|
||||||
* @property \Model\Comment $comment
|
* @property \Model\Comment $comment
|
||||||
|
* @property \Model\CommentHistory $commentHistory
|
||||||
|
* @property \Model\Color $color
|
||||||
* @property \Model\Config $config
|
* @property \Model\Config $config
|
||||||
|
* @property \Model\DateParser $dateParser
|
||||||
* @property \Model\File $file
|
* @property \Model\File $file
|
||||||
* @property \Model\LastLogin $lastLogin
|
* @property \Model\LastLogin $lastLogin
|
||||||
* @property \Model\Notification $notification
|
* @property \Model\Notification $notification
|
||||||
* @property \Model\Project $project
|
* @property \Model\Project $project
|
||||||
|
* @property \Model\ProjectPermission $projectPermission
|
||||||
* @property \Model\SubTask $subTask
|
* @property \Model\SubTask $subTask
|
||||||
|
* @property \Model\SubtaskHistory $subtaskHistory
|
||||||
* @property \Model\Task $task
|
* @property \Model\Task $task
|
||||||
|
* @property \Model\TaskExport $taskExport
|
||||||
|
* @property \Model\TaskFinder $taskFinder
|
||||||
* @property \Model\TaskHistory $taskHistory
|
* @property \Model\TaskHistory $taskHistory
|
||||||
|
* @property \Model\TaskValidator $taskValidator
|
||||||
|
* @property \Model\TimeTracking $timeTracking
|
||||||
* @property \Model\User $user
|
* @property \Model\User $user
|
||||||
* @property \Model\Webhook $webhook
|
* @property \Model\Webhook $webhook
|
||||||
*/
|
*/
|
||||||
|
@ -80,4 +89,52 @@ abstract class Base
|
||||||
{
|
{
|
||||||
return Tool::loadModel($this->registry, $name);
|
return Tool::loadModel($this->registry, $name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove keys from an array
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $values Input array
|
||||||
|
* @param array $keys List of keys to remove
|
||||||
|
*/
|
||||||
|
public function removeFields(array &$values, array $keys)
|
||||||
|
{
|
||||||
|
foreach ($keys as $key) {
|
||||||
|
if (isset($values[$key])) {
|
||||||
|
unset($values[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Force some fields to be at 0 if empty
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $values Input array
|
||||||
|
* @param array $keys List of keys
|
||||||
|
*/
|
||||||
|
public function resetFields(array &$values, array $keys)
|
||||||
|
{
|
||||||
|
foreach ($keys as $key) {
|
||||||
|
if (isset($values[$key]) && empty($values[$key])) {
|
||||||
|
$values[$key] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Force some fields to be integer
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $values Input array
|
||||||
|
* @param array $keys List of keys
|
||||||
|
*/
|
||||||
|
public function convertIntegerFields(array &$values, array $keys)
|
||||||
|
{
|
||||||
|
foreach ($keys as $key) {
|
||||||
|
if (isset($values[$key])) {
|
||||||
|
$values[$key] = (int) $values[$key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,70 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Model;
|
|
||||||
|
|
||||||
use PDO;
|
|
||||||
use Core\Template;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Task history model
|
|
||||||
*
|
|
||||||
* @package model
|
|
||||||
* @author Frederic Guillot
|
|
||||||
*/
|
|
||||||
abstract class BaseHistory extends Base
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* SQL table name
|
|
||||||
*
|
|
||||||
* @access protected
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $table = '';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove old event entries to avoid a large table
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param integer $max Maximum number of items to keep in the table
|
|
||||||
*/
|
|
||||||
public function cleanup($max)
|
|
||||||
{
|
|
||||||
if ($this->db->table($this->table)->count() > $max) {
|
|
||||||
|
|
||||||
$this->db->execute('
|
|
||||||
DELETE FROM '.$this->table.'
|
|
||||||
WHERE id <= (
|
|
||||||
SELECT id FROM (
|
|
||||||
SELECT id FROM '.$this->table.' ORDER BY id DESC LIMIT 1 OFFSET '.$max.'
|
|
||||||
) foo
|
|
||||||
)');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all events for a given project
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getAllByProjectId($project_id)
|
|
||||||
{
|
|
||||||
return $this->db->table($this->table)
|
|
||||||
->eq('project_id', $project_id)
|
|
||||||
->desc('id')
|
|
||||||
->findAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the event html content
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param array $params Event properties
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getContent(array $params)
|
|
||||||
{
|
|
||||||
$tpl = new Template;
|
|
||||||
return $tpl->load('event_'.str_replace('.', '_', $params['event_name']), $params);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -31,6 +31,29 @@ class Board extends Base
|
||||||
return array(t('Backlog'), t('Ready'), t('Work in progress'), t('Done'));
|
return array(t('Backlog'), t('Ready'), t('Work in progress'), t('Done'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get user default columns
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getUserColumns()
|
||||||
|
{
|
||||||
|
$column_names = explode(',', $this->config->get('board_columns', implode(',', $this->getDefaultColumns())));
|
||||||
|
$columns = array();
|
||||||
|
|
||||||
|
foreach ($column_names as $column_name) {
|
||||||
|
|
||||||
|
$column_name = trim($column_name);
|
||||||
|
|
||||||
|
if (! empty($column_name)) {
|
||||||
|
$columns[] = array('title' => $column_name, 'task_limit' => 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $columns;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a board with default columns, must be executed inside a transaction
|
* Create a board with default columns, must be executed inside a transaction
|
||||||
*
|
*
|
||||||
|
@ -211,14 +234,8 @@ class Board extends Base
|
||||||
*/
|
*/
|
||||||
public function get($project_id, array $filters = array())
|
public function get($project_id, array $filters = array())
|
||||||
{
|
{
|
||||||
$this->db->startTransaction();
|
|
||||||
|
|
||||||
$columns = $this->getColumns($project_id);
|
$columns = $this->getColumns($project_id);
|
||||||
|
$tasks = $this->taskFinder->getTasksOnBoard($project_id);
|
||||||
$filters[] = array('column' => 'project_id', 'operator' => 'eq', 'value' => $project_id);
|
|
||||||
$filters[] = array('column' => 'is_active', 'operator' => 'eq', 'value' => Task::STATUS_OPEN);
|
|
||||||
|
|
||||||
$tasks = $this->task->find($filters);
|
|
||||||
|
|
||||||
foreach ($columns as &$column) {
|
foreach ($columns as &$column) {
|
||||||
|
|
||||||
|
@ -231,8 +248,6 @@ class Board extends Base
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->db->closeTransaction();
|
|
||||||
|
|
||||||
return $columns;
|
return $columns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
31
sources/app/Model/Color.php
Normal file
31
sources/app/Model/Color.php
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Color model (TODO: model for the future color picker)
|
||||||
|
*
|
||||||
|
* @package model
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
class Color extends Base
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get available colors
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getList()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'yellow' => t('Yellow'),
|
||||||
|
'blue' => t('Blue'),
|
||||||
|
'green' => t('Green'),
|
||||||
|
'purple' => t('Purple'),
|
||||||
|
'red' => t('Red'),
|
||||||
|
'orange' => t('Orange'),
|
||||||
|
'grey' => t('Grey'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,152 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Model;
|
|
||||||
|
|
||||||
use PDO;
|
|
||||||
use Core\Registry;
|
|
||||||
use Event\CommentHistoryListener;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Comment history model
|
|
||||||
*
|
|
||||||
* @package model
|
|
||||||
* @author Frederic Guillot
|
|
||||||
*/
|
|
||||||
class CommentHistory extends BaseHistory
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* SQL table name
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
const TABLE = 'comment_has_events';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Maximum number of events
|
|
||||||
*
|
|
||||||
* @var integer
|
|
||||||
*/
|
|
||||||
const MAX_EVENTS = 5000;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param \Core\Registry $registry Registry instance
|
|
||||||
*/
|
|
||||||
public function __construct(Registry $registry)
|
|
||||||
{
|
|
||||||
parent::__construct($registry);
|
|
||||||
$this->table = self::TABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new event
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param integer $project_id Project id
|
|
||||||
* @param integer $task_id Task id
|
|
||||||
* @param integer $comment_id Comment id
|
|
||||||
* @param integer $creator_id Author of the event (user id)
|
|
||||||
* @param string $event_name Task event name
|
|
||||||
* @param string $data Current comment
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function create($project_id, $task_id, $comment_id, $creator_id, $event_name, $data)
|
|
||||||
{
|
|
||||||
$values = array(
|
|
||||||
'project_id' => $project_id,
|
|
||||||
'task_id' => $task_id,
|
|
||||||
'comment_id' => $comment_id,
|
|
||||||
'creator_id' => $creator_id,
|
|
||||||
'event_name' => $event_name,
|
|
||||||
'date_creation' => time(),
|
|
||||||
'data' => $data,
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->db->startTransaction();
|
|
||||||
|
|
||||||
$this->cleanup(self::MAX_EVENTS - 1);
|
|
||||||
$result = $this->db->table(self::TABLE)->insert($values);
|
|
||||||
|
|
||||||
$this->db->closeTransaction();
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all necessary content to display activity feed
|
|
||||||
*
|
|
||||||
* $author_name
|
|
||||||
* $author_username
|
|
||||||
* $task['id', 'title', 'position', 'column_name']
|
|
||||||
*/
|
|
||||||
public function getAllContentByProjectId($project_id, $limit = 50)
|
|
||||||
{
|
|
||||||
$sql = '
|
|
||||||
SELECT
|
|
||||||
comment_has_events.id,
|
|
||||||
comment_has_events.date_creation,
|
|
||||||
comment_has_events.event_name,
|
|
||||||
comment_has_events.data as comment,
|
|
||||||
comment_has_events.task_id,
|
|
||||||
tasks.title as task_title,
|
|
||||||
users.username as author_username,
|
|
||||||
users.name as author_name
|
|
||||||
FROM comment_has_events
|
|
||||||
LEFT JOIN users ON users.id=comment_has_events.creator_id
|
|
||||||
LEFT JOIN tasks ON tasks.id=comment_has_events.task_id
|
|
||||||
WHERE comment_has_events.project_id = ?
|
|
||||||
ORDER BY comment_has_events.id DESC
|
|
||||||
LIMIT '.$limit.' OFFSET 0
|
|
||||||
';
|
|
||||||
|
|
||||||
$rq = $this->db->execute($sql, array($project_id));
|
|
||||||
$events = $rq->fetchAll(PDO::FETCH_ASSOC);
|
|
||||||
|
|
||||||
foreach ($events as &$event) {
|
|
||||||
$event['author'] = $event['author_name'] ?: $event['author_username'];
|
|
||||||
$event['event_title'] = $this->getTitle($event);
|
|
||||||
$event['event_content'] = $this->getContent($event);
|
|
||||||
$event['event_type'] = 'comment';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $events;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the event title (translated)
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param array $event Event properties
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getTitle(array $event)
|
|
||||||
{
|
|
||||||
$titles = array(
|
|
||||||
Comment::EVENT_UPDATE => t('%s updated a comment on the task #%d', $event['author'], $event['task_id']),
|
|
||||||
Comment::EVENT_CREATE => t('%s commented on the task #%d', $event['author'], $event['task_id']),
|
|
||||||
);
|
|
||||||
|
|
||||||
return isset($titles[$event['event_name']]) ? $titles[$event['event_name']] : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attach events to be able to record the history
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
*/
|
|
||||||
public function attachEvents()
|
|
||||||
{
|
|
||||||
$events = array(
|
|
||||||
Comment::EVENT_UPDATE,
|
|
||||||
Comment::EVENT_CREATE,
|
|
||||||
);
|
|
||||||
|
|
||||||
$listener = new CommentHistoryListener($this);
|
|
||||||
|
|
||||||
foreach ($events as $event_name) {
|
|
||||||
$this->event->attach($event_name, $listener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,6 +6,7 @@ use SimpleValidator\Validator;
|
||||||
use SimpleValidator\Validators;
|
use SimpleValidator\Validators;
|
||||||
use Core\Translator;
|
use Core\Translator;
|
||||||
use Core\Security;
|
use Core\Security;
|
||||||
|
use Core\Session;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Config model
|
* Config model
|
||||||
|
@ -20,7 +21,7 @@ class Config extends Base
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
const TABLE = 'config';
|
const TABLE = 'settings';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get available timezones
|
* Get available timezones
|
||||||
|
@ -44,6 +45,7 @@ class Config extends Base
|
||||||
{
|
{
|
||||||
// Sorted by value
|
// Sorted by value
|
||||||
return array(
|
return array(
|
||||||
|
'da_DK' => 'Dansk',
|
||||||
'de_DE' => 'Deutsch',
|
'de_DE' => 'Deutsch',
|
||||||
'en_US' => 'English',
|
'en_US' => 'English',
|
||||||
'es_ES' => 'Español',
|
'es_ES' => 'Español',
|
||||||
|
@ -55,6 +57,8 @@ class Config extends Base
|
||||||
'fi_FI' => 'Suomi',
|
'fi_FI' => 'Suomi',
|
||||||
'sv_SE' => 'Svenska',
|
'sv_SE' => 'Svenska',
|
||||||
'zh_CN' => '中文(简体)',
|
'zh_CN' => '中文(简体)',
|
||||||
|
'ja_JP' => '日本語',
|
||||||
|
'th_TH' => 'ไทย',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,6 +72,11 @@ class Config extends Base
|
||||||
*/
|
*/
|
||||||
public function get($name, $default_value = '')
|
public function get($name, $default_value = '')
|
||||||
{
|
{
|
||||||
|
if (! Session::isOpen()) {
|
||||||
|
$value = $this->db->table(self::TABLE)->eq('option', $name)->findOneColumn('value');
|
||||||
|
return $value ?: $default_value;
|
||||||
|
}
|
||||||
|
|
||||||
if (! isset($_SESSION['config'][$name])) {
|
if (! isset($_SESSION['config'][$name])) {
|
||||||
$_SESSION['config'] = $this->getAll();
|
$_SESSION['config'] = $this->getAll();
|
||||||
}
|
}
|
||||||
|
@ -87,7 +96,7 @@ class Config extends Base
|
||||||
*/
|
*/
|
||||||
public function getAll()
|
public function getAll()
|
||||||
{
|
{
|
||||||
return $this->db->table(self::TABLE)->findOne();
|
return $this->db->table(self::TABLE)->listing('option', 'value');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -99,8 +108,16 @@ class Config extends Base
|
||||||
*/
|
*/
|
||||||
public function save(array $values)
|
public function save(array $values)
|
||||||
{
|
{
|
||||||
$_SESSION['config'] = $values;
|
foreach ($values as $option => $value) {
|
||||||
return $this->db->table(self::TABLE)->update($values);
|
|
||||||
|
$result = $this->db->table(self::TABLE)->eq('option', $option)->update(array('value' => $value));
|
||||||
|
|
||||||
|
if (! $result) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -111,27 +128,31 @@ class Config extends Base
|
||||||
public function reload()
|
public function reload()
|
||||||
{
|
{
|
||||||
$_SESSION['config'] = $this->getAll();
|
$_SESSION['config'] = $this->getAll();
|
||||||
Translator::load($this->get('language', 'en_US'));
|
$this->setupTranslations();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate settings modification
|
* Load translations
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @param array $values Form values
|
|
||||||
* @return array $valid, $errors [0] = Success or not, [1] = List of errors
|
|
||||||
*/
|
*/
|
||||||
public function validateModification(array $values)
|
public function setupTranslations()
|
||||||
{
|
{
|
||||||
$v = new Validator($values, array(
|
$language = $this->get('application_language', 'en_US');
|
||||||
new Validators\Required('language', t('The language is required')),
|
|
||||||
new Validators\Required('timezone', t('The timezone is required')),
|
|
||||||
));
|
|
||||||
|
|
||||||
return array(
|
if ($language !== 'en_US') {
|
||||||
$v->execute(),
|
Translator::load($language);
|
||||||
$v->getErrors()
|
}
|
||||||
);
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set timezone
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
public function setupTimezone()
|
||||||
|
{
|
||||||
|
date_default_timezone_set($this->get('application_timezone', 'UTC'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -168,21 +189,15 @@ class Config extends Base
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Regenerate all tokens (projects and webhooks)
|
* Regenerate a token
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
|
* @param string $option Parameter name
|
||||||
*/
|
*/
|
||||||
public function regenerateTokens()
|
public function regenerateToken($option)
|
||||||
{
|
{
|
||||||
$this->db->table(self::TABLE)->update(array(
|
return $this->db->table(self::TABLE)
|
||||||
'webhooks_token' => Security::generateToken(),
|
->eq('option', $option)
|
||||||
'api_token' => Security::generateToken(),
|
->update(array('value' => Security::generateToken()));
|
||||||
));
|
|
||||||
|
|
||||||
$projects = $this->db->table(Project::TABLE)->findAllByColumn('id');
|
|
||||||
|
|
||||||
foreach ($projects as $project_id) {
|
|
||||||
$this->db->table(Project::TABLE)->eq('id', $project_id)->update(array('token' => Security::generateToken()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
142
sources/app/Model/DateParser.php
Normal file
142
sources/app/Model/DateParser.php
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Model;
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date parser model
|
||||||
|
*
|
||||||
|
* @package model
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
class DateParser extends Base
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Return a timestamp if the given date format is correct otherwise return 0
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param string $value Date to parse
|
||||||
|
* @param string $format Date format
|
||||||
|
* @return integer
|
||||||
|
*/
|
||||||
|
public function getValidDate($value, $format)
|
||||||
|
{
|
||||||
|
$date = DateTime::createFromFormat($format, $value);
|
||||||
|
|
||||||
|
if ($date !== false) {
|
||||||
|
$errors = DateTime::getLastErrors();
|
||||||
|
if ($errors['error_count'] === 0 && $errors['warning_count'] === 0) {
|
||||||
|
$timestamp = $date->getTimestamp();
|
||||||
|
return $timestamp > 0 ? $timestamp : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a date ad return a unix timestamp, try different date formats
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param string $value Date to parse
|
||||||
|
* @return integer
|
||||||
|
*/
|
||||||
|
public function getTimestamp($value)
|
||||||
|
{
|
||||||
|
foreach ($this->getDateFormats() as $format) {
|
||||||
|
|
||||||
|
$timestamp = $this->getValidDate($value, $format);
|
||||||
|
|
||||||
|
if ($timestamp !== 0) {
|
||||||
|
return $timestamp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the list of supported date formats (for the parser)
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getDateFormats()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
$this->config->get('application_date_format', 'm/d/Y'),
|
||||||
|
'Y-m-d',
|
||||||
|
'Y_m_d',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the list of available date formats (for the config page)
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAvailableFormats()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'm/d/Y' => date('m/d/Y'),
|
||||||
|
'd/m/Y' => date('d/m/Y'),
|
||||||
|
'Y/m/d' => date('Y/m/d'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For a given timestamp, reset the date to midnight
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $timestamp Timestamp
|
||||||
|
* @return integer
|
||||||
|
*/
|
||||||
|
public function resetDateToMidnight($timestamp)
|
||||||
|
{
|
||||||
|
return mktime(0, 0, 0, date('m', $timestamp), date('d', $timestamp), date('Y', $timestamp));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format date (form display)
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $values Database values
|
||||||
|
* @param array $fields Date fields
|
||||||
|
* @param string $format Date format
|
||||||
|
*/
|
||||||
|
public function format(array &$values, array $fields, $format = '')
|
||||||
|
{
|
||||||
|
if ($format === '') {
|
||||||
|
$format = $this->config->get('application_date_format');
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($fields as $field) {
|
||||||
|
|
||||||
|
if (! empty($values[$field])) {
|
||||||
|
$values[$field] = date($format, $values[$field]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$values[$field] = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert date (form input data)
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $values Database values
|
||||||
|
* @param array $fields Date fields
|
||||||
|
*/
|
||||||
|
public function convert(array &$values, array $fields)
|
||||||
|
{
|
||||||
|
foreach ($fields as $field) {
|
||||||
|
|
||||||
|
if (! empty($values[$field]) && ! is_numeric($values[$field])) {
|
||||||
|
$values[$field] = $this->getTimestamp($values[$field]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
339
sources/app/Model/GithubWebhook.php
Normal file
339
sources/app/Model/GithubWebhook.php
Normal file
|
@ -0,0 +1,339 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Github Webhook model
|
||||||
|
*
|
||||||
|
* @package model
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
class GithubWebhook extends Base
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Events
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const EVENT_ISSUE_OPENED = 'github.webhook.issue.opened';
|
||||||
|
const EVENT_ISSUE_CLOSED = 'github.webhook.issue.closed';
|
||||||
|
const EVENT_ISSUE_REOPENED = 'github.webhook.issue.reopened';
|
||||||
|
const EVENT_ISSUE_ASSIGNEE_CHANGE = 'github.webhook.issue.assignee';
|
||||||
|
const EVENT_ISSUE_LABEL_CHANGE = 'github.webhook.issue.label';
|
||||||
|
const EVENT_ISSUE_COMMENT = 'github.webhook.issue.commented';
|
||||||
|
const EVENT_COMMIT = 'github.webhook.commit';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Project id
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
private $project_id = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the project id
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $project_id Project id
|
||||||
|
*/
|
||||||
|
public function setProjectId($project_id)
|
||||||
|
{
|
||||||
|
$this->project_id = $project_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse Github events
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param string $type Github event type
|
||||||
|
* @param string $payload Raw Github event (JSON)
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function parsePayload($type, $payload)
|
||||||
|
{
|
||||||
|
$payload = json_decode($payload, true);
|
||||||
|
|
||||||
|
switch ($type) {
|
||||||
|
case 'push':
|
||||||
|
return $this->parsePushEvent($payload);
|
||||||
|
case 'issues':
|
||||||
|
return $this->parseIssueEvent($payload);
|
||||||
|
case 'issue_comment':
|
||||||
|
return $this->parseCommentIssueEvent($payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse Push events (list of commits)
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $payload Event data
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function parsePushEvent(array $payload)
|
||||||
|
{
|
||||||
|
foreach ($payload['commits'] as $commit) {
|
||||||
|
|
||||||
|
$task_id = $this->task->getTaskIdFromText($commit['message']);
|
||||||
|
|
||||||
|
if (! $task_id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$task = $this->taskFinder->getById($task_id);
|
||||||
|
|
||||||
|
if (! $task) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($task['is_active'] == Task::STATUS_OPEN) {
|
||||||
|
$this->event->trigger(self::EVENT_COMMIT, array('task_id' => $task_id) + $task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse issue events
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $payload Event data
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function parseIssueEvent(array $payload)
|
||||||
|
{
|
||||||
|
switch ($payload['action']) {
|
||||||
|
case 'opened':
|
||||||
|
return $this->handleIssueOpened($payload['issue']);
|
||||||
|
case 'closed':
|
||||||
|
return $this->handleIssueClosed($payload['issue']);
|
||||||
|
case 'reopened':
|
||||||
|
return $this->handleIssueReopened($payload['issue']);
|
||||||
|
case 'assigned':
|
||||||
|
return $this->handleIssueAssigned($payload['issue']);
|
||||||
|
case 'unassigned':
|
||||||
|
return $this->handleIssueUnassigned($payload['issue']);
|
||||||
|
case 'labeled':
|
||||||
|
return $this->handleIssueLabeled($payload['issue'], $payload['label']);
|
||||||
|
case 'unlabeled':
|
||||||
|
return $this->handleIssueUnlabeled($payload['issue'], $payload['label']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse comment issue events
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $payload Event data
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function parseCommentIssueEvent(array $payload)
|
||||||
|
{
|
||||||
|
$task = $this->taskFinder->getByReference($payload['issue']['number']);
|
||||||
|
$user = $this->user->getByUsername($payload['comment']['user']['login']);
|
||||||
|
|
||||||
|
if ($task && $user) {
|
||||||
|
|
||||||
|
$event = array(
|
||||||
|
'project_id' => $this->project_id,
|
||||||
|
'reference' => $payload['comment']['id'],
|
||||||
|
'comment' => $payload['comment']['body'],
|
||||||
|
'user_id' => $user['id'],
|
||||||
|
'task_id' => $task['id'],
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->event->trigger(self::EVENT_ISSUE_COMMENT, $event);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle new issues
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $issue Issue data
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function handleIssueOpened(array $issue)
|
||||||
|
{
|
||||||
|
$event = array(
|
||||||
|
'project_id' => $this->project_id,
|
||||||
|
'reference' => $issue['number'],
|
||||||
|
'title' => $issue['title'],
|
||||||
|
'description' => $issue['body']."\n\n[".t('Github Issue').']('.$issue['html_url'].')',
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->event->trigger(self::EVENT_ISSUE_OPENED, $event);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle issue closing
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $issue Issue data
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function handleIssueClosed(array $issue)
|
||||||
|
{
|
||||||
|
$task = $this->taskFinder->getByReference($issue['number']);
|
||||||
|
|
||||||
|
if ($task) {
|
||||||
|
$event = array(
|
||||||
|
'project_id' => $this->project_id,
|
||||||
|
'task_id' => $task['id'],
|
||||||
|
'reference' => $issue['number'],
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->event->trigger(self::EVENT_ISSUE_CLOSED, $event);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle issue reopened
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $issue Issue data
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function handleIssueReopened(array $issue)
|
||||||
|
{
|
||||||
|
$task = $this->taskFinder->getByReference($issue['number']);
|
||||||
|
|
||||||
|
if ($task) {
|
||||||
|
$event = array(
|
||||||
|
'project_id' => $this->project_id,
|
||||||
|
'task_id' => $task['id'],
|
||||||
|
'reference' => $issue['number'],
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->event->trigger(self::EVENT_ISSUE_REOPENED, $event);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle issue assignee change
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $issue Issue data
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function handleIssueAssigned(array $issue)
|
||||||
|
{
|
||||||
|
$user = $this->user->getByUsername($issue['assignee']['login']);
|
||||||
|
$task = $this->taskFinder->getByReference($issue['number']);
|
||||||
|
|
||||||
|
if ($user && $task) {
|
||||||
|
|
||||||
|
$event = array(
|
||||||
|
'project_id' => $this->project_id,
|
||||||
|
'task_id' => $task['id'],
|
||||||
|
'owner_id' => $user['id'],
|
||||||
|
'reference' => $issue['number'],
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->event->trigger(self::EVENT_ISSUE_ASSIGNEE_CHANGE, $event);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle unassigned issue
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $issue Issue data
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function handleIssueUnassigned(array $issue)
|
||||||
|
{
|
||||||
|
$task = $this->taskFinder->getByReference($issue['number']);
|
||||||
|
|
||||||
|
if ($task) {
|
||||||
|
|
||||||
|
$event = array(
|
||||||
|
'project_id' => $this->project_id,
|
||||||
|
'task_id' => $task['id'],
|
||||||
|
'owner_id' => 0,
|
||||||
|
'reference' => $issue['number'],
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->event->trigger(self::EVENT_ISSUE_ASSIGNEE_CHANGE, $event);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle labeled issue
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $issue Issue data
|
||||||
|
* @param array $label Label data
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function handleIssueLabeled(array $issue, array $label)
|
||||||
|
{
|
||||||
|
$task = $this->taskFinder->getByReference($issue['number']);
|
||||||
|
|
||||||
|
if ($task) {
|
||||||
|
|
||||||
|
$event = array(
|
||||||
|
'project_id' => $this->project_id,
|
||||||
|
'task_id' => $task['id'],
|
||||||
|
'reference' => $issue['number'],
|
||||||
|
'label' => $label['name'],
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->event->trigger(self::EVENT_ISSUE_LABEL_CHANGE, $event);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle unlabeled issue
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $issue Issue data
|
||||||
|
* @param array $label Label data
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function handleIssueUnlabeled(array $issue, array $label)
|
||||||
|
{
|
||||||
|
$task = $this->taskFinder->getByReference($issue['number']);
|
||||||
|
|
||||||
|
if ($task) {
|
||||||
|
|
||||||
|
$event = array(
|
||||||
|
'project_id' => $this->project_id,
|
||||||
|
'task_id' => $task['id'],
|
||||||
|
'reference' => $issue['number'],
|
||||||
|
'label' => $label['name'],
|
||||||
|
'category_id' => 0,
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->event->trigger(self::EVENT_ISSUE_LABEL_CHANGE, $event);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,14 +2,13 @@
|
||||||
|
|
||||||
namespace Model;
|
namespace Model;
|
||||||
|
|
||||||
|
use Core\Session;
|
||||||
use Core\Translator;
|
use Core\Translator;
|
||||||
use Core\Template;
|
use Core\Template;
|
||||||
use Event\TaskNotificationListener;
|
use Event\NotificationListener;
|
||||||
use Event\CommentNotificationListener;
|
|
||||||
use Event\FileNotificationListener;
|
|
||||||
use Event\SubTaskNotificationListener;
|
|
||||||
use Swift_Message;
|
use Swift_Message;
|
||||||
use Swift_Mailer;
|
use Swift_Mailer;
|
||||||
|
use Swift_TransportException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notification model
|
* Notification model
|
||||||
|
@ -26,20 +25,54 @@ class Notification extends Base
|
||||||
*/
|
*/
|
||||||
const TABLE = 'user_has_notifications';
|
const TABLE = 'user_has_notifications';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of people with notifications enabled
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $project_id Project id
|
||||||
|
* @param array $exlude_users List of user_id to exclude
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getUsersWithNotification($project_id, array $exclude_users = array())
|
||||||
|
{
|
||||||
|
if ($this->projectPermission->isEverybodyAllowed($project_id)) {
|
||||||
|
|
||||||
|
return $this->db
|
||||||
|
->table(User::TABLE)
|
||||||
|
->columns(User::TABLE.'.id', User::TABLE.'.username', User::TABLE.'.name', User::TABLE.'.email')
|
||||||
|
->eq('notifications_enabled', '1')
|
||||||
|
->neq('email', '')
|
||||||
|
->notin(User::TABLE.'.id', $exclude_users)
|
||||||
|
->findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->db
|
||||||
|
->table(ProjectPermission::TABLE)
|
||||||
|
->columns(User::TABLE.'.id', User::TABLE.'.username', User::TABLE.'.name', User::TABLE.'.email')
|
||||||
|
->join(User::TABLE, 'id', 'user_id')
|
||||||
|
->eq('project_id', $project_id)
|
||||||
|
->eq('notifications_enabled', '1')
|
||||||
|
->neq('email', '')
|
||||||
|
->notin(User::TABLE.'.id', $exclude_users)
|
||||||
|
->findAll();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the list of users to send the notification for a given project
|
* Get the list of users to send the notification for a given project
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @param integer $project_id Project id
|
* @param integer $project_id Project id
|
||||||
|
* @param array $exlude_users List of user_id to exclude
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getUsersList($project_id)
|
public function getUsersList($project_id, array $exclude_users = array())
|
||||||
{
|
{
|
||||||
$users = $this->db->table(User::TABLE)
|
// Exclude the connected user
|
||||||
->columns('id', 'username', 'name', 'email')
|
if (Session::isOpen()) {
|
||||||
->eq('notifications_enabled', '1')
|
$exclude_users[] = $this->acl->getUserId();
|
||||||
->neq('email', '')
|
}
|
||||||
->findAll();
|
|
||||||
|
$users = $this->getUsersWithNotification($project_id, $exclude_users);
|
||||||
|
|
||||||
foreach ($users as $index => $user) {
|
foreach ($users as $index => $user) {
|
||||||
|
|
||||||
|
@ -67,21 +100,28 @@ class Notification extends Base
|
||||||
*/
|
*/
|
||||||
public function attachEvents()
|
public function attachEvents()
|
||||||
{
|
{
|
||||||
$this->event->attach(File::EVENT_CREATE, new FileNotificationListener($this, 'notification_file_creation'));
|
$events = array(
|
||||||
|
Task::EVENT_CREATE => 'notification_task_creation',
|
||||||
|
Task::EVENT_UPDATE => 'notification_task_update',
|
||||||
|
Task::EVENT_CLOSE => 'notification_task_close',
|
||||||
|
Task::EVENT_OPEN => 'notification_task_open',
|
||||||
|
Task::EVENT_MOVE_COLUMN => 'notification_task_move_column',
|
||||||
|
Task::EVENT_MOVE_POSITION => 'notification_task_move_position',
|
||||||
|
Task::EVENT_ASSIGNEE_CHANGE => 'notification_task_assignee_change',
|
||||||
|
SubTask::EVENT_CREATE => 'notification_subtask_creation',
|
||||||
|
SubTask::EVENT_UPDATE => 'notification_subtask_update',
|
||||||
|
Comment::EVENT_CREATE => 'notification_comment_creation',
|
||||||
|
Comment::EVENT_UPDATE => 'notification_comment_update',
|
||||||
|
File::EVENT_CREATE => 'notification_file_creation',
|
||||||
|
);
|
||||||
|
|
||||||
$this->event->attach(Comment::EVENT_CREATE, new CommentNotificationListener($this, 'notification_comment_creation'));
|
foreach ($events as $event_name => $template_name) {
|
||||||
$this->event->attach(Comment::EVENT_UPDATE, new CommentNotificationListener($this, 'notification_comment_update'));
|
|
||||||
|
|
||||||
$this->event->attach(SubTask::EVENT_CREATE, new SubTaskNotificationListener($this, 'notification_subtask_creation'));
|
$listener = new NotificationListener($this->registry);
|
||||||
$this->event->attach(SubTask::EVENT_UPDATE, new SubTaskNotificationListener($this, 'notification_subtask_update'));
|
$listener->setTemplate($template_name);
|
||||||
|
|
||||||
$this->event->attach(Task::EVENT_CREATE, new TaskNotificationListener($this, 'notification_task_creation'));
|
$this->event->attach($event_name, $listener);
|
||||||
$this->event->attach(Task::EVENT_UPDATE, new TaskNotificationListener($this, 'notification_task_update'));
|
}
|
||||||
$this->event->attach(Task::EVENT_CLOSE, new TaskNotificationListener($this, 'notification_task_close'));
|
|
||||||
$this->event->attach(Task::EVENT_OPEN, new TaskNotificationListener($this, 'notification_task_open'));
|
|
||||||
$this->event->attach(Task::EVENT_MOVE_COLUMN, new TaskNotificationListener($this, 'notification_task_move_column'));
|
|
||||||
$this->event->attach(Task::EVENT_MOVE_POSITION, new TaskNotificationListener($this, 'notification_task_move_position'));
|
|
||||||
$this->event->attach(Task::EVENT_ASSIGNEE_CHANGE, new TaskNotificationListener($this, 'notification_task_assignee_change'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -94,6 +134,7 @@ class Notification extends Base
|
||||||
*/
|
*/
|
||||||
public function sendEmails($template, array $users, array $data)
|
public function sendEmails($template, array $users, array $data)
|
||||||
{
|
{
|
||||||
|
try {
|
||||||
$transport = $this->registry->shared('mailer');
|
$transport = $this->registry->shared('mailer');
|
||||||
$mailer = Swift_Mailer::newInstance($transport);
|
$mailer = Swift_Mailer::newInstance($transport);
|
||||||
|
|
||||||
|
@ -107,6 +148,10 @@ class Notification extends Base
|
||||||
$mailer->send($message);
|
$mailer->send($message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Swift_TransportException $e) {
|
||||||
|
debug($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the mail subject for a given template name
|
* Get the mail subject for a given template name
|
||||||
|
@ -174,7 +219,7 @@ class Notification extends Base
|
||||||
public function getMailContent($template, array $data)
|
public function getMailContent($template, array $data)
|
||||||
{
|
{
|
||||||
$tpl = new Template;
|
$tpl = new Template;
|
||||||
return $tpl->load($template, $data);
|
return $tpl->load($template, $data + array('application_url' => $this->config->get('application_url')));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -4,7 +4,7 @@ namespace Model;
|
||||||
|
|
||||||
use SimpleValidator\Validator;
|
use SimpleValidator\Validator;
|
||||||
use SimpleValidator\Validators;
|
use SimpleValidator\Validators;
|
||||||
use Event\ProjectModificationDate;
|
use Event\ProjectModificationDateListener;
|
||||||
use Core\Security;
|
use Core\Security;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -22,13 +22,6 @@ class Project extends Base
|
||||||
*/
|
*/
|
||||||
const TABLE = 'projects';
|
const TABLE = 'projects';
|
||||||
|
|
||||||
/**
|
|
||||||
* SQL table name for users
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
const TABLE_USERS = 'project_has_users';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Value for active project
|
* Value for active project
|
||||||
*
|
*
|
||||||
|
@ -43,157 +36,6 @@ class Project extends Base
|
||||||
*/
|
*/
|
||||||
const INACTIVE = 0;
|
const INACTIVE = 0;
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a list of people that can be assigned for tasks
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param integer $project_id Project id
|
|
||||||
* @param bool $prepend_unassigned Prepend the 'Unassigned' value
|
|
||||||
* @param bool $prepend_everybody Prepend the 'Everbody' value
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getUsersList($project_id, $prepend_unassigned = true, $prepend_everybody = false)
|
|
||||||
{
|
|
||||||
$allowed_users = $this->getAllowedUsers($project_id);
|
|
||||||
|
|
||||||
if (empty($allowed_users)) {
|
|
||||||
$allowed_users = $this->user->getList();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($prepend_unassigned) {
|
|
||||||
$allowed_users = array(t('Unassigned')) + $allowed_users;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($prepend_everybody) {
|
|
||||||
$allowed_users = array(User::EVERYBODY_ID => t('Everybody')) + $allowed_users;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $allowed_users;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a list of allowed people for a project
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param integer $project_id Project id
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getAllowedUsers($project_id)
|
|
||||||
{
|
|
||||||
$users = $this->db
|
|
||||||
->table(self::TABLE_USERS)
|
|
||||||
->join(User::TABLE, 'id', 'user_id')
|
|
||||||
->eq('project_id', $project_id)
|
|
||||||
->asc('username')
|
|
||||||
->columns(User::TABLE.'.id', User::TABLE.'.username', User::TABLE.'.name')
|
|
||||||
->findAll();
|
|
||||||
|
|
||||||
$result = array();
|
|
||||||
|
|
||||||
foreach ($users as $user) {
|
|
||||||
$result[$user['id']] = $user['name'] ?: $user['username'];
|
|
||||||
}
|
|
||||||
|
|
||||||
asort($result);
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get allowed and not allowed users for a project
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param integer $project_id Project id
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getAllUsers($project_id)
|
|
||||||
{
|
|
||||||
$users = array(
|
|
||||||
'allowed' => array(),
|
|
||||||
'not_allowed' => array(),
|
|
||||||
);
|
|
||||||
|
|
||||||
$all_users = $this->user->getList();
|
|
||||||
|
|
||||||
$users['allowed'] = $this->getAllowedUsers($project_id);
|
|
||||||
|
|
||||||
foreach ($all_users as $user_id => $username) {
|
|
||||||
|
|
||||||
if (! isset($users['allowed'][$user_id])) {
|
|
||||||
$users['not_allowed'][$user_id] = $username;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $users;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allow a specific user for a given project
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param integer $project_id Project id
|
|
||||||
* @param integer $user_id User id
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function allowUser($project_id, $user_id)
|
|
||||||
{
|
|
||||||
return $this->db
|
|
||||||
->table(self::TABLE_USERS)
|
|
||||||
->save(array('project_id' => $project_id, 'user_id' => $user_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Revoke a specific user for a given project
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param integer $project_id Project id
|
|
||||||
* @param integer $user_id User id
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function revokeUser($project_id, $user_id)
|
|
||||||
{
|
|
||||||
return $this->db
|
|
||||||
->table(self::TABLE_USERS)
|
|
||||||
->eq('project_id', $project_id)
|
|
||||||
->eq('user_id', $user_id)
|
|
||||||
->remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a specific user is allowed to access to a given project
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param integer $project_id Project id
|
|
||||||
* @param integer $user_id User id
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function isUserAllowed($project_id, $user_id)
|
|
||||||
{
|
|
||||||
// If there is nobody specified, everybody have access to the project
|
|
||||||
$nb_users = $this->db
|
|
||||||
->table(self::TABLE_USERS)
|
|
||||||
->eq('project_id', $project_id)
|
|
||||||
->count();
|
|
||||||
|
|
||||||
if ($nb_users < 1) return true;
|
|
||||||
|
|
||||||
// Check if user has admin rights
|
|
||||||
$nb_users = $this->db
|
|
||||||
->table(User::TABLE)
|
|
||||||
->eq('id', $user_id)
|
|
||||||
->eq('is_admin', 1)
|
|
||||||
->count();
|
|
||||||
|
|
||||||
if ($nb_users > 0) return true;
|
|
||||||
|
|
||||||
// Otherwise, allow only specific users
|
|
||||||
return (bool) $this->db
|
|
||||||
->table(self::TABLE_USERS)
|
|
||||||
->eq('project_id', $project_id)
|
|
||||||
->eq('user_id', $user_id)
|
|
||||||
->count();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a project by the id
|
* Get a project by the id
|
||||||
*
|
*
|
||||||
|
@ -241,6 +83,18 @@ class Project extends Base
|
||||||
return $this->db->table(self::TABLE)->findOne();
|
return $this->db->table(self::TABLE)->findOne();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the project is private
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $project_id Project id
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function isPrivate($project_id)
|
||||||
|
{
|
||||||
|
return (bool) $this->db->table(self::TABLE)->eq('id', $project_id)->eq('is_private', 1)->count();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all projects, optionaly fetch stats for each project and can check users permissions
|
* Get all projects, optionaly fetch stats for each project and can check users permissions
|
||||||
*
|
*
|
||||||
|
@ -256,7 +110,7 @@ class Project extends Base
|
||||||
|
|
||||||
foreach ($projects as $key => $project) {
|
foreach ($projects as $key => $project) {
|
||||||
|
|
||||||
if (! $this->isUserAllowed($project['id'], $this->acl->getUserId())) {
|
if (! $this->projectPermission->isUserAllowed($project['id'], $this->acl->getUserId())) {
|
||||||
unset($projects[$key]);
|
unset($projects[$key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -328,37 +182,6 @@ class Project extends Base
|
||||||
->count();
|
->count();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Filter a list of projects for a given user
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param array $projects Project list: ['project_id' => 'project_name']
|
|
||||||
* @param integer $user_id User id
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function filterListByAccess(array $projects, $user_id)
|
|
||||||
{
|
|
||||||
foreach ($projects as $project_id => $project_name) {
|
|
||||||
if (! $this->isUserAllowed($project_id, $user_id)) {
|
|
||||||
unset($projects[$project_id]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $projects;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a list of projects for a given user
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param integer $user_id User id
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getAvailableList($user_id)
|
|
||||||
{
|
|
||||||
return $this->filterListByAccess($this->getListByStatus(self::ACTIVE), $user_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gather some task metrics for a given project
|
* Gather some task metrics for a given project
|
||||||
*
|
*
|
||||||
|
@ -373,12 +196,12 @@ class Project extends Base
|
||||||
$stats['nb_active_tasks'] = 0;
|
$stats['nb_active_tasks'] = 0;
|
||||||
|
|
||||||
foreach ($columns as &$column) {
|
foreach ($columns as &$column) {
|
||||||
$column['nb_active_tasks'] = $this->task->countByColumnId($project_id, $column['id']);
|
$column['nb_active_tasks'] = $this->taskFinder->countByColumnId($project_id, $column['id']);
|
||||||
$stats['nb_active_tasks'] += $column['nb_active_tasks'];
|
$stats['nb_active_tasks'] += $column['nb_active_tasks'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$stats['columns'] = $columns;
|
$stats['columns'] = $columns;
|
||||||
$stats['nb_tasks'] = $this->task->countByProjectId($project_id);
|
$stats['nb_tasks'] = $this->taskFinder->countByProjectId($project_id);
|
||||||
$stats['nb_inactive_tasks'] = $stats['nb_tasks'] - $stats['nb_active_tasks'];
|
$stats['nb_inactive_tasks'] = $stats['nb_tasks'] - $stats['nb_active_tasks'];
|
||||||
|
|
||||||
return $stats;
|
return $stats;
|
||||||
|
@ -393,43 +216,24 @@ class Project extends Base
|
||||||
*/
|
*/
|
||||||
public function createProjectFromAnotherProject($project_id)
|
public function createProjectFromAnotherProject($project_id)
|
||||||
{
|
{
|
||||||
$project_name = $this->db->table(self::TABLE)->eq('id', $project_id)->findOneColumn('name');
|
$project = $this->getById($project_id);
|
||||||
|
|
||||||
$project = array(
|
$values = array(
|
||||||
'name' => $project_name.' ('.t('Clone').')',
|
'name' => $project['name'].' ('.t('Clone').')',
|
||||||
'is_active' => true,
|
'is_active' => true,
|
||||||
'last_modified' => 0,
|
'last_modified' => 0,
|
||||||
'token' => '',
|
'token' => '',
|
||||||
|
'is_public' => 0,
|
||||||
|
'is_private' => empty($project['is_private']) ? 0 : 1,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (! $this->db->table(self::TABLE)->save($project)) {
|
if (! $this->db->table(self::TABLE)->save($values)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->db->getConnection()->getLastId();
|
return $this->db->getConnection()->getLastId();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy user access from a project to another one
|
|
||||||
*
|
|
||||||
* @author Antonio Rabelo
|
|
||||||
* @param integer $project_from Project Template
|
|
||||||
* @return integer $project_to Project that receives the copy
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function duplicateUsers($project_from, $project_to)
|
|
||||||
{
|
|
||||||
$users = $this->getAllowedUsers($project_from);
|
|
||||||
|
|
||||||
foreach ($users as $user_id => $name) {
|
|
||||||
if (! $this->allowUser($project_to, $user_id)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clone a project
|
* Clone a project
|
||||||
*
|
*
|
||||||
|
@ -443,33 +247,18 @@ class Project extends Base
|
||||||
|
|
||||||
// Get the cloned project Id
|
// Get the cloned project Id
|
||||||
$clone_project_id = $this->createProjectFromAnotherProject($project_id);
|
$clone_project_id = $this->createProjectFromAnotherProject($project_id);
|
||||||
|
|
||||||
if (! $clone_project_id) {
|
if (! $clone_project_id) {
|
||||||
$this->db->cancelTransaction();
|
$this->db->cancelTransaction();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clone Board
|
foreach (array('board', 'category', 'projectPermission', 'action') as $model) {
|
||||||
if (! $this->board->duplicate($project_id, $clone_project_id)) {
|
|
||||||
|
if (! $this->$model->duplicate($project_id, $clone_project_id)) {
|
||||||
$this->db->cancelTransaction();
|
$this->db->cancelTransaction();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clone Categories
|
|
||||||
if (! $this->category->duplicate($project_id, $clone_project_id)) {
|
|
||||||
$this->db->cancelTransaction();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clone Allowed Users
|
|
||||||
if (! $this->duplicateUsers($project_id, $clone_project_id)) {
|
|
||||||
$this->db->cancelTransaction();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clone Actions
|
|
||||||
if (! $this->action->duplicate($project_id, $clone_project_id)) {
|
|
||||||
$this->db->cancelTransaction();
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->db->closeTransaction();
|
$this->db->closeTransaction();
|
||||||
|
@ -482,14 +271,16 @@ class Project extends Base
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @param array $values Form values
|
* @param array $values Form values
|
||||||
|
* @param integer $user_id User who create the project
|
||||||
* @return integer Project id
|
* @return integer Project id
|
||||||
*/
|
*/
|
||||||
public function create(array $values)
|
public function create(array $values, $user_id = 0)
|
||||||
{
|
{
|
||||||
$this->db->startTransaction();
|
$this->db->startTransaction();
|
||||||
|
|
||||||
$values['token'] = '';
|
$values['token'] = '';
|
||||||
$values['last_modified'] = time();
|
$values['last_modified'] = time();
|
||||||
|
$values['is_private'] = empty($values['is_private']) ? 0 : 1;
|
||||||
|
|
||||||
if (! $this->db->table(self::TABLE)->save($values)) {
|
if (! $this->db->table(self::TABLE)->save($values)) {
|
||||||
$this->db->cancelTransaction();
|
$this->db->cancelTransaction();
|
||||||
|
@ -497,19 +288,16 @@ class Project extends Base
|
||||||
}
|
}
|
||||||
|
|
||||||
$project_id = $this->db->getConnection()->getLastId();
|
$project_id = $this->db->getConnection()->getLastId();
|
||||||
$column_names = explode(',', $this->config->get('default_columns', implode(',', $this->board->getDefaultColumns())));
|
|
||||||
$columns = array();
|
|
||||||
|
|
||||||
foreach ($column_names as $column_name) {
|
if (! $this->board->create($project_id, $this->board->getUserColumns())) {
|
||||||
|
$this->db->cancelTransaction();
|
||||||
$column_name = trim($column_name);
|
return false;
|
||||||
|
}
|
||||||
if (! empty($column_name)) {
|
|
||||||
$columns[] = array('title' => $column_name, 'task_limit' => 0);
|
if ($values['is_private'] && $user_id) {
|
||||||
}
|
$this->projectPermission->allowUser($project_id, $user_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->board->create($project_id, $columns);
|
|
||||||
$this->db->closeTransaction();
|
$this->db->closeTransaction();
|
||||||
|
|
||||||
return (int) $project_id;
|
return (int) $project_id;
|
||||||
|
@ -701,28 +489,6 @@ class Project extends Base
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate allowed users
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param array $values Form values
|
|
||||||
* @return array $valid, $errors [0] = Success or not, [1] = List of errors
|
|
||||||
*/
|
|
||||||
public function validateUserAccess(array $values)
|
|
||||||
{
|
|
||||||
$v = new Validator($values, array(
|
|
||||||
new Validators\Required('project_id', t('The project id is required')),
|
|
||||||
new Validators\Integer('project_id', t('This value must be an integer')),
|
|
||||||
new Validators\Required('user_id', t('The user id is required')),
|
|
||||||
new Validators\Integer('user_id', t('This value must be an integer')),
|
|
||||||
));
|
|
||||||
|
|
||||||
return array(
|
|
||||||
$v->execute(),
|
|
||||||
$v->getErrors()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attach events
|
* Attach events
|
||||||
*
|
*
|
||||||
|
@ -737,43 +503,19 @@ class Project extends Base
|
||||||
Task::EVENT_MOVE_COLUMN,
|
Task::EVENT_MOVE_COLUMN,
|
||||||
Task::EVENT_MOVE_POSITION,
|
Task::EVENT_MOVE_POSITION,
|
||||||
Task::EVENT_ASSIGNEE_CHANGE,
|
Task::EVENT_ASSIGNEE_CHANGE,
|
||||||
|
GithubWebhook::EVENT_ISSUE_OPENED,
|
||||||
|
GithubWebhook::EVENT_ISSUE_CLOSED,
|
||||||
|
GithubWebhook::EVENT_ISSUE_REOPENED,
|
||||||
|
GithubWebhook::EVENT_ISSUE_ASSIGNEE_CHANGE,
|
||||||
|
GithubWebhook::EVENT_ISSUE_LABEL_CHANGE,
|
||||||
|
GithubWebhook::EVENT_ISSUE_COMMENT,
|
||||||
|
GithubWebhook::EVENT_COMMIT,
|
||||||
);
|
);
|
||||||
|
|
||||||
$listener = new ProjectModificationDate($this);
|
$listener = new ProjectModificationDateListener($this->registry);
|
||||||
|
|
||||||
foreach ($events as $event_name) {
|
foreach ($events as $event_name) {
|
||||||
$this->event->attach($event_name, $listener);
|
$this->event->attach($event_name, $listener);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get project activity
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param integer $project_id Project id
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getActivity($project_id)
|
|
||||||
{
|
|
||||||
$activity = array();
|
|
||||||
$tasks = $this->taskHistory->getAllContentByProjectId($project_id, 25);
|
|
||||||
$comments = $this->commentHistory->getAllContentByProjectId($project_id, 25);
|
|
||||||
$subtasks = $this->subtaskHistory->getAllContentByProjectId($project_id, 25);
|
|
||||||
|
|
||||||
foreach ($tasks as &$task) {
|
|
||||||
$activity[$task['date_creation'].'-'.$task['id']] = $task;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($subtasks as &$subtask) {
|
|
||||||
$activity[$subtask['date_creation'].'-'.$subtask['id']] = $subtask;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($comments as &$comment) {
|
|
||||||
$activity[$comment['date_creation'].'-'.$comment['id']] = $comment;
|
|
||||||
}
|
|
||||||
|
|
||||||
krsort($activity);
|
|
||||||
|
|
||||||
return $activity;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
206
sources/app/Model/ProjectActivity.php
Normal file
206
sources/app/Model/ProjectActivity.php
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Model;
|
||||||
|
|
||||||
|
use Core\Template;
|
||||||
|
use Event\ProjectActivityListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Project activity model
|
||||||
|
*
|
||||||
|
* @package model
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
class ProjectActivity extends Base
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* SQL table name
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const TABLE = 'project_activities';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum number of events
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
const MAX_EVENTS = 5000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a new event for the project
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $project_id Project id
|
||||||
|
* @param integer $task_id Task id
|
||||||
|
* @param integer $creator_id User id
|
||||||
|
* @param string $event_name Event name
|
||||||
|
* @param array $data Event data (will be serialized)
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function createEvent($project_id, $task_id, $creator_id, $event_name, array $data)
|
||||||
|
{
|
||||||
|
$values = array(
|
||||||
|
'project_id' => $project_id,
|
||||||
|
'task_id' => $task_id,
|
||||||
|
'creator_id' => $creator_id,
|
||||||
|
'event_name' => $event_name,
|
||||||
|
'date_creation' => time(),
|
||||||
|
'data' => serialize($data),
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->cleanup(self::MAX_EVENTS - 1);
|
||||||
|
return $this->db->table(self::TABLE)->insert($values);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all events for the given project
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $project_id Project id
|
||||||
|
* @param integer $limit Maximum events number
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getProject($project_id, $limit = 50)
|
||||||
|
{
|
||||||
|
return $this->getProjects(array($project_id), $limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all events for the given projects list
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $project_id Project id
|
||||||
|
* @param integer $limit Maximum events number
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getProjects(array $projects, $limit = 50)
|
||||||
|
{
|
||||||
|
if (empty($projects)) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$events = $this->db->table(self::TABLE)
|
||||||
|
->columns(
|
||||||
|
self::TABLE.'.*',
|
||||||
|
User::TABLE.'.username AS author_username',
|
||||||
|
User::TABLE.'.name AS author_name'
|
||||||
|
)
|
||||||
|
->in('project_id', $projects)
|
||||||
|
->join(User::TABLE, 'id', 'creator_id')
|
||||||
|
->desc('id')
|
||||||
|
->limit($limit)
|
||||||
|
->findAll();
|
||||||
|
|
||||||
|
foreach ($events as &$event) {
|
||||||
|
|
||||||
|
$event += unserialize($event['data']);
|
||||||
|
unset($event['data']);
|
||||||
|
|
||||||
|
$event['author'] = $event['author_name'] ?: $event['author_username'];
|
||||||
|
$event['event_title'] = $this->getTitle($event);
|
||||||
|
$event['event_content'] = $this->getContent($event);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $events;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove old event entries to avoid large table
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $max Maximum number of items to keep in the table
|
||||||
|
*/
|
||||||
|
public function cleanup($max)
|
||||||
|
{
|
||||||
|
if ($this->db->table(self::TABLE)->count() > $max) {
|
||||||
|
|
||||||
|
$this->db->execute('
|
||||||
|
DELETE FROM '.self::TABLE.'
|
||||||
|
WHERE id <= (
|
||||||
|
SELECT id FROM (
|
||||||
|
SELECT id FROM '.self::TABLE.' ORDER BY id DESC LIMIT 1 OFFSET '.$max.'
|
||||||
|
) foo
|
||||||
|
)'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attach events to be able to record the history
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
public function attachEvents()
|
||||||
|
{
|
||||||
|
$events = array(
|
||||||
|
Task::EVENT_ASSIGNEE_CHANGE,
|
||||||
|
Task::EVENT_UPDATE,
|
||||||
|
Task::EVENT_CREATE,
|
||||||
|
Task::EVENT_CLOSE,
|
||||||
|
Task::EVENT_OPEN,
|
||||||
|
Task::EVENT_MOVE_COLUMN,
|
||||||
|
Task::EVENT_MOVE_POSITION,
|
||||||
|
Comment::EVENT_UPDATE,
|
||||||
|
Comment::EVENT_CREATE,
|
||||||
|
SubTask::EVENT_UPDATE,
|
||||||
|
SubTask::EVENT_CREATE,
|
||||||
|
);
|
||||||
|
|
||||||
|
$listener = new ProjectActivityListener($this->registry);
|
||||||
|
|
||||||
|
foreach ($events as $event_name) {
|
||||||
|
$this->event->attach($event_name, $listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the event html content
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $params Event properties
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getContent(array $params)
|
||||||
|
{
|
||||||
|
$tpl = new Template;
|
||||||
|
return $tpl->load('event_'.str_replace('.', '_', $params['event_name']), $params);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the event title (translated)
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $event Event properties
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getTitle(array $event)
|
||||||
|
{
|
||||||
|
switch ($event['event_name']) {
|
||||||
|
case Task::EVENT_ASSIGNEE_CHANGE:
|
||||||
|
return t('%s change the assignee of the task #%d to %s', $event['author'], $event['task']['id'], $event['task']['assignee_name'] ?: $event['task']['assignee_username']);
|
||||||
|
case Task::EVENT_UPDATE:
|
||||||
|
return t('%s updated the task #%d', $event['author'], $event['task']['id']);
|
||||||
|
case Task::EVENT_CREATE:
|
||||||
|
return t('%s created the task #%d', $event['author'], $event['task']['id']);
|
||||||
|
case Task::EVENT_CLOSE:
|
||||||
|
return t('%s closed the task #%d', $event['author'], $event['task']['id']);
|
||||||
|
case Task::EVENT_OPEN:
|
||||||
|
return t('%s open the task #%d', $event['author'], $event['task']['id']);
|
||||||
|
case Task::EVENT_MOVE_COLUMN:
|
||||||
|
return t('%s moved the task #%d to the column "%s"', $event['author'], $event['task']['id'], $event['task']['column_title']);
|
||||||
|
case Task::EVENT_MOVE_POSITION:
|
||||||
|
return t('%s moved the task #%d to the position %d in the column "%s"', $event['author'], $event['task']['id'], $event['task']['position'], $event['task']['column_title']);
|
||||||
|
case SubTask::EVENT_UPDATE:
|
||||||
|
return t('%s updated a subtask for the task #%d', $event['author'], $event['task']['id']);
|
||||||
|
case SubTask::EVENT_CREATE:
|
||||||
|
return t('%s created a subtask for the task #%d', $event['author'], $event['task']['id']);
|
||||||
|
case Comment::EVENT_UPDATE:
|
||||||
|
return t('%s updated a comment on the task #%d', $event['author'], $event['task']['id']);
|
||||||
|
case Comment::EVENT_CREATE:
|
||||||
|
return t('%s commented on the task #%d', $event['author'], $event['task']['id']);
|
||||||
|
default:
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
295
sources/app/Model/ProjectPermission.php
Normal file
295
sources/app/Model/ProjectPermission.php
Normal file
|
@ -0,0 +1,295 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Model;
|
||||||
|
|
||||||
|
use SimpleValidator\Validator;
|
||||||
|
use SimpleValidator\Validators;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Project permission model
|
||||||
|
*
|
||||||
|
* @package model
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
class ProjectPermission extends Base
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* SQL table name for permissions
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const TABLE = 'project_has_users';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of people that can be assigned for tasks
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $project_id Project id
|
||||||
|
* @param bool $prepend_unassigned Prepend the 'Unassigned' value
|
||||||
|
* @param bool $prepend_everybody Prepend the 'Everbody' value
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getUsersList($project_id, $prepend_unassigned = true, $prepend_everybody = false)
|
||||||
|
{
|
||||||
|
$allowed_users = $this->getAllowedUsers($project_id);
|
||||||
|
|
||||||
|
if ($prepend_unassigned) {
|
||||||
|
$allowed_users = array(t('Unassigned')) + $allowed_users;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($prepend_everybody) {
|
||||||
|
$allowed_users = array(User::EVERYBODY_ID => t('Everybody')) + $allowed_users;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $allowed_users;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of allowed people for a project
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $project_id Project id
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAllowedUsers($project_id)
|
||||||
|
{
|
||||||
|
if ($this->isEverybodyAllowed($project_id)) {
|
||||||
|
return $this->user->getList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->getAssociatedUsers($project_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of people associated to the project
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $project_id Project id
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAssociatedUsers($project_id)
|
||||||
|
{
|
||||||
|
$users = $this->db
|
||||||
|
->table(self::TABLE)
|
||||||
|
->join(User::TABLE, 'id', 'user_id')
|
||||||
|
->eq('project_id', $project_id)
|
||||||
|
->asc('username')
|
||||||
|
->columns(User::TABLE.'.id', User::TABLE.'.username', User::TABLE.'.name')
|
||||||
|
->findAll();
|
||||||
|
|
||||||
|
return $this->user->prepareList($users);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get allowed and not allowed users for a project
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $project_id Project id
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAllUsers($project_id)
|
||||||
|
{
|
||||||
|
$users = array(
|
||||||
|
'allowed' => array(),
|
||||||
|
'not_allowed' => array(),
|
||||||
|
);
|
||||||
|
|
||||||
|
$all_users = $this->user->getList();
|
||||||
|
|
||||||
|
$users['allowed'] = $this->getAllowedUsers($project_id);
|
||||||
|
|
||||||
|
foreach ($all_users as $user_id => $username) {
|
||||||
|
|
||||||
|
if (! isset($users['allowed'][$user_id])) {
|
||||||
|
$users['not_allowed'][$user_id] = $username;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $users;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow a specific user for a given project
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $project_id Project id
|
||||||
|
* @param integer $user_id User id
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function allowUser($project_id, $user_id)
|
||||||
|
{
|
||||||
|
return $this->db
|
||||||
|
->table(self::TABLE)
|
||||||
|
->save(array('project_id' => $project_id, 'user_id' => $user_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Revoke a specific user for a given project
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $project_id Project id
|
||||||
|
* @param integer $user_id User id
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function revokeUser($project_id, $user_id)
|
||||||
|
{
|
||||||
|
return $this->db
|
||||||
|
->table(self::TABLE)
|
||||||
|
->eq('project_id', $project_id)
|
||||||
|
->eq('user_id', $user_id)
|
||||||
|
->remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a specific user is allowed to access to a given project
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $project_id Project id
|
||||||
|
* @param integer $user_id User id
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isUserAllowed($project_id, $user_id)
|
||||||
|
{
|
||||||
|
if ($this->user->isAdmin($user_id)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->isEverybodyAllowed($project_id)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (bool) $this->db
|
||||||
|
->table(self::TABLE)
|
||||||
|
->eq('project_id', $project_id)
|
||||||
|
->eq('user_id', $user_id)
|
||||||
|
->count();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if everybody is allowed for the project
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $project_id Project id
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isEverybodyAllowed($project_id)
|
||||||
|
{
|
||||||
|
return (bool) $this->db
|
||||||
|
->table(Project::TABLE)
|
||||||
|
->eq('id', $project_id)
|
||||||
|
->eq('is_everybody_allowed', 1)
|
||||||
|
->count();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a specific user is allowed to manage a project
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $project_id Project id
|
||||||
|
* @param integer $user_id User id
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function adminAllowed($project_id, $user_id)
|
||||||
|
{
|
||||||
|
if ($this->isUserAllowed($project_id, $user_id) && $this->project->isPrivate($project_id)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter a list of projects for a given user
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $projects Project list: ['project_id' => 'project_name']
|
||||||
|
* @param integer $user_id User id
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function filterProjects(array $projects, $user_id)
|
||||||
|
{
|
||||||
|
foreach ($projects as $project_id => $project_name) {
|
||||||
|
if (! $this->isUserAllowed($project_id, $user_id)) {
|
||||||
|
unset($projects[$project_id]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $projects;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a list of projects for a given user
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $user_id User id
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAllowedProjects($user_id)
|
||||||
|
{
|
||||||
|
return $this->filterProjects($this->project->getListByStatus(Project::ACTIVE), $user_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy user access from a project to another one
|
||||||
|
*
|
||||||
|
* @author Antonio Rabelo
|
||||||
|
* @param integer $project_from Project Template
|
||||||
|
* @return integer $project_to Project that receives the copy
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function duplicate($project_from, $project_to)
|
||||||
|
{
|
||||||
|
$users = $this->getAllowedUsers($project_from);
|
||||||
|
|
||||||
|
foreach ($users as $user_id => $name) {
|
||||||
|
if (! $this->allowUser($project_to, $user_id)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate allow user
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $values Form values
|
||||||
|
* @return array $valid, $errors [0] = Success or not, [1] = List of errors
|
||||||
|
*/
|
||||||
|
public function validateUserModification(array $values)
|
||||||
|
{
|
||||||
|
$v = new Validator($values, array(
|
||||||
|
new Validators\Required('project_id', t('The project id is required')),
|
||||||
|
new Validators\Integer('project_id', t('This value must be an integer')),
|
||||||
|
new Validators\Required('user_id', t('The user id is required')),
|
||||||
|
new Validators\Integer('user_id', t('This value must be an integer')),
|
||||||
|
));
|
||||||
|
|
||||||
|
return array(
|
||||||
|
$v->execute(),
|
||||||
|
$v->getErrors()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate allow everybody
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $values Form values
|
||||||
|
* @return array $valid, $errors [0] = Success or not, [1] = List of errors
|
||||||
|
*/
|
||||||
|
public function validateProjectModification(array $values)
|
||||||
|
{
|
||||||
|
$v = new Validator($values, array(
|
||||||
|
new Validators\Required('id', t('The project id is required')),
|
||||||
|
new Validators\Integer('id', t('This value must be an integer')),
|
||||||
|
new Validators\Integer('is_everybody_allowed', t('This value must be an integer')),
|
||||||
|
));
|
||||||
|
|
||||||
|
return array(
|
||||||
|
$v->execute(),
|
||||||
|
$v->getErrors()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -82,6 +82,7 @@ class SubTask extends Base
|
||||||
->eq('task_id', $task_id)
|
->eq('task_id', $task_id)
|
||||||
->columns(self::TABLE.'.*', User::TABLE.'.username', User::TABLE.'.name')
|
->columns(self::TABLE.'.*', User::TABLE.'.username', User::TABLE.'.name')
|
||||||
->join(User::TABLE, 'id', 'user_id')
|
->join(User::TABLE, 'id', 'user_id')
|
||||||
|
->asc(self::TABLE.'.id')
|
||||||
->findAll();
|
->findAll();
|
||||||
|
|
||||||
foreach ($subtasks as &$subtask) {
|
foreach ($subtasks as &$subtask) {
|
||||||
|
@ -128,17 +129,8 @@ class SubTask extends Base
|
||||||
*/
|
*/
|
||||||
public function prepare(array &$values)
|
public function prepare(array &$values)
|
||||||
{
|
{
|
||||||
if (isset($values['another_subtask'])) {
|
$this->removeFields($values, array('another_subtask'));
|
||||||
unset($values['another_subtask']);
|
$this->resetFields($values, array('time_estimated', 'time_spent'));
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($values['time_estimated']) && empty($values['time_estimated'])) {
|
|
||||||
$values['time_estimated'] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($values['time_spent']) && empty($values['time_spent'])) {
|
|
||||||
$values['time_spent'] = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,161 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Model;
|
|
||||||
|
|
||||||
use PDO;
|
|
||||||
use Core\Registry;
|
|
||||||
use Event\SubtaskHistoryListener;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Comment history model
|
|
||||||
*
|
|
||||||
* @package model
|
|
||||||
* @author Frederic Guillot
|
|
||||||
*/
|
|
||||||
class SubtaskHistory extends BaseHistory
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* SQL table name
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
const TABLE = 'subtask_has_events';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Maximum number of events
|
|
||||||
*
|
|
||||||
* @var integer
|
|
||||||
*/
|
|
||||||
const MAX_EVENTS = 5000;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param \Core\Registry $registry Registry instance
|
|
||||||
*/
|
|
||||||
public function __construct(Registry $registry)
|
|
||||||
{
|
|
||||||
parent::__construct($registry);
|
|
||||||
$this->table = self::TABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new event
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param integer $project_id Project id
|
|
||||||
* @param integer $task_id Task id
|
|
||||||
* @param integer $subtask_id Subtask id
|
|
||||||
* @param integer $creator_id Author of the event (user id)
|
|
||||||
* @param string $event_name Task event name
|
|
||||||
* @param string $data Current comment
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function create($project_id, $task_id, $subtask_id, $creator_id, $event_name, $data)
|
|
||||||
{
|
|
||||||
$values = array(
|
|
||||||
'project_id' => $project_id,
|
|
||||||
'task_id' => $task_id,
|
|
||||||
'subtask_id' => $subtask_id,
|
|
||||||
'creator_id' => $creator_id,
|
|
||||||
'event_name' => $event_name,
|
|
||||||
'date_creation' => time(),
|
|
||||||
'data' => $data,
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->db->startTransaction();
|
|
||||||
|
|
||||||
$this->cleanup(self::MAX_EVENTS - 1);
|
|
||||||
$result = $this->db->table(self::TABLE)->insert($values);
|
|
||||||
|
|
||||||
$this->db->closeTransaction();
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all necessary content to display activity feed
|
|
||||||
*
|
|
||||||
* $author_name
|
|
||||||
* $author_username
|
|
||||||
* $task['id', 'title', 'position', 'column_name']
|
|
||||||
*/
|
|
||||||
public function getAllContentByProjectId($project_id, $limit = 50)
|
|
||||||
{
|
|
||||||
$sql = '
|
|
||||||
SELECT
|
|
||||||
subtask_has_events.id,
|
|
||||||
subtask_has_events.date_creation,
|
|
||||||
subtask_has_events.event_name,
|
|
||||||
subtask_has_events.task_id,
|
|
||||||
tasks.title as task_title,
|
|
||||||
users.username as author_username,
|
|
||||||
users.name as author_name,
|
|
||||||
assignees.name as subtask_assignee_name,
|
|
||||||
assignees.username as subtask_assignee_username,
|
|
||||||
task_has_subtasks.title as subtask_title,
|
|
||||||
task_has_subtasks.status as subtask_status,
|
|
||||||
task_has_subtasks.time_spent as subtask_time_spent,
|
|
||||||
task_has_subtasks.time_estimated as subtask_time_estimated
|
|
||||||
FROM subtask_has_events
|
|
||||||
LEFT JOIN users ON users.id=subtask_has_events.creator_id
|
|
||||||
LEFT JOIN tasks ON tasks.id=subtask_has_events.task_id
|
|
||||||
LEFT JOIN task_has_subtasks ON task_has_subtasks.id=subtask_has_events.subtask_id
|
|
||||||
LEFT JOIN users AS assignees ON assignees.id=task_has_subtasks.user_id
|
|
||||||
WHERE subtask_has_events.project_id = ?
|
|
||||||
ORDER BY subtask_has_events.id DESC
|
|
||||||
LIMIT '.$limit.' OFFSET 0
|
|
||||||
';
|
|
||||||
|
|
||||||
$rq = $this->db->execute($sql, array($project_id));
|
|
||||||
$events = $rq->fetchAll(PDO::FETCH_ASSOC);
|
|
||||||
|
|
||||||
foreach ($events as &$event) {
|
|
||||||
$event['author'] = $event['author_name'] ?: $event['author_username'];
|
|
||||||
$event['subtask_assignee'] = $event['subtask_assignee_name'] ?: $event['subtask_assignee_username'];
|
|
||||||
$event['subtask_status_list'] = $this->subTask->getStatusList();
|
|
||||||
$event['event_title'] = $this->getTitle($event);
|
|
||||||
$event['event_content'] = $this->getContent($event);
|
|
||||||
$event['event_type'] = 'subtask';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $events;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the event title (translated)
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param array $event Event properties
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getTitle(array $event)
|
|
||||||
{
|
|
||||||
$titles = array(
|
|
||||||
SubTask::EVENT_UPDATE => t('%s updated a subtask for the task #%d', $event['author'], $event['task_id']),
|
|
||||||
SubTask::EVENT_CREATE => t('%s created a subtask for the task #%d', $event['author'], $event['task_id']),
|
|
||||||
);
|
|
||||||
|
|
||||||
return isset($titles[$event['event_name']]) ? $titles[$event['event_name']] : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attach events to be able to record the history
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
*/
|
|
||||||
public function attachEvents()
|
|
||||||
{
|
|
||||||
$events = array(
|
|
||||||
SubTask::EVENT_UPDATE,
|
|
||||||
SubTask::EVENT_CREATE,
|
|
||||||
);
|
|
||||||
|
|
||||||
$listener = new SubtaskHistoryListener($this);
|
|
||||||
|
|
||||||
foreach ($events as $event_name) {
|
|
||||||
$this->event->attach($event_name, $listener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,11 +2,6 @@
|
||||||
|
|
||||||
namespace Model;
|
namespace Model;
|
||||||
|
|
||||||
use SimpleValidator\Validator;
|
|
||||||
use SimpleValidator\Validators;
|
|
||||||
use DateTime;
|
|
||||||
use PDO;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Task model
|
* Task model
|
||||||
*
|
*
|
||||||
|
@ -44,321 +39,6 @@ class Task extends Base
|
||||||
const EVENT_CREATE_UPDATE = 'task.create_update';
|
const EVENT_CREATE_UPDATE = 'task.create_update';
|
||||||
const EVENT_ASSIGNEE_CHANGE = 'task.assignee_change';
|
const EVENT_ASSIGNEE_CHANGE = 'task.assignee_change';
|
||||||
|
|
||||||
/**
|
|
||||||
* Get available colors
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getColors()
|
|
||||||
{
|
|
||||||
return array(
|
|
||||||
'yellow' => t('Yellow'),
|
|
||||||
'blue' => t('Blue'),
|
|
||||||
'green' => t('Green'),
|
|
||||||
'purple' => t('Purple'),
|
|
||||||
'red' => t('Red'),
|
|
||||||
'orange' => t('Orange'),
|
|
||||||
'grey' => t('Grey'),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a list of due tasks for all projects
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getOverdueTasks()
|
|
||||||
{
|
|
||||||
$tasks = $this->db->table(self::TABLE)
|
|
||||||
->columns(
|
|
||||||
self::TABLE.'.id',
|
|
||||||
self::TABLE.'.title',
|
|
||||||
self::TABLE.'.date_due',
|
|
||||||
self::TABLE.'.project_id',
|
|
||||||
Project::TABLE.'.name AS project_name',
|
|
||||||
User::TABLE.'.username AS assignee_username',
|
|
||||||
User::TABLE.'.name AS assignee_name'
|
|
||||||
)
|
|
||||||
->join(Project::TABLE, 'id', 'project_id')
|
|
||||||
->join(User::TABLE, 'id', 'owner_id')
|
|
||||||
->eq(Project::TABLE.'.is_active', 1)
|
|
||||||
->eq(self::TABLE.'.is_active', 1)
|
|
||||||
->neq(self::TABLE.'.date_due', 0)
|
|
||||||
->lte(self::TABLE.'.date_due', mktime(23, 59, 59))
|
|
||||||
->findAll();
|
|
||||||
|
|
||||||
return $tasks;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch one task
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param integer $task_id Task id
|
|
||||||
* @param boolean $more If true, fetch all related information
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getById($task_id, $more = false)
|
|
||||||
{
|
|
||||||
if ($more) {
|
|
||||||
|
|
||||||
$sql = '
|
|
||||||
SELECT
|
|
||||||
tasks.id,
|
|
||||||
tasks.title,
|
|
||||||
tasks.description,
|
|
||||||
tasks.date_creation,
|
|
||||||
tasks.date_completed,
|
|
||||||
tasks.date_modification,
|
|
||||||
tasks.date_due,
|
|
||||||
tasks.color_id,
|
|
||||||
tasks.project_id,
|
|
||||||
tasks.column_id,
|
|
||||||
tasks.owner_id,
|
|
||||||
tasks.creator_id,
|
|
||||||
tasks.position,
|
|
||||||
tasks.is_active,
|
|
||||||
tasks.score,
|
|
||||||
tasks.category_id,
|
|
||||||
project_has_categories.name AS category_name,
|
|
||||||
projects.name AS project_name,
|
|
||||||
columns.title AS column_title,
|
|
||||||
users.username AS assignee_username,
|
|
||||||
users.name AS assignee_name,
|
|
||||||
creators.username AS creator_username,
|
|
||||||
creators.name AS creator_name
|
|
||||||
FROM tasks
|
|
||||||
LEFT JOIN users ON users.id = tasks.owner_id
|
|
||||||
LEFT JOIN users AS creators ON creators.id = tasks.creator_id
|
|
||||||
LEFT JOIN project_has_categories ON project_has_categories.id = tasks.category_id
|
|
||||||
LEFT JOIN projects ON projects.id = tasks.project_id
|
|
||||||
LEFT JOIN columns ON columns.id = tasks.column_id
|
|
||||||
WHERE tasks.id = ?
|
|
||||||
';
|
|
||||||
|
|
||||||
$rq = $this->db->execute($sql, array($task_id));
|
|
||||||
return $rq->fetch(PDO::FETCH_ASSOC);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
return $this->db->table(self::TABLE)->eq('id', $task_id)->findOne();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Count all tasks for a given project and status
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param integer $project_id Project id
|
|
||||||
* @param integer $status_id Status id
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getAll($project_id, $status_id = self::STATUS_OPEN)
|
|
||||||
{
|
|
||||||
return $this->db
|
|
||||||
->table(self::TABLE)
|
|
||||||
->eq('project_id', $project_id)
|
|
||||||
->eq('is_active', $status_id)
|
|
||||||
->findAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Count all tasks for a given project and status
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param integer $project_id Project id
|
|
||||||
* @param array $status List of status id
|
|
||||||
* @return integer
|
|
||||||
*/
|
|
||||||
public function countByProjectId($project_id, array $status = array(self::STATUS_OPEN, self::STATUS_CLOSED))
|
|
||||||
{
|
|
||||||
return $this->db
|
|
||||||
->table(self::TABLE)
|
|
||||||
->eq('project_id', $project_id)
|
|
||||||
->in('is_active', $status)
|
|
||||||
->count();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get tasks that match defined filters
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param array $filters Filters: [ ['column' => '...', 'operator' => '...', 'value' => '...'], ... ]
|
|
||||||
* @param array $sorting Sorting: [ 'column' => 'date_creation', 'direction' => 'asc']
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function find(array $filters, array $sorting = array())
|
|
||||||
{
|
|
||||||
$table = $this->db
|
|
||||||
->table(self::TABLE)
|
|
||||||
->columns(
|
|
||||||
'(SELECT count(*) FROM comments WHERE task_id=tasks.id) AS nb_comments',
|
|
||||||
'(SELECT count(*) FROM task_has_files WHERE task_id=tasks.id) AS nb_files',
|
|
||||||
'(SELECT count(*) FROM task_has_subtasks WHERE task_id=tasks.id) AS nb_subtasks',
|
|
||||||
'(SELECT count(*) FROM task_has_subtasks WHERE task_id=tasks.id AND status=2) AS nb_completed_subtasks',
|
|
||||||
'tasks.id',
|
|
||||||
'tasks.title',
|
|
||||||
'tasks.description',
|
|
||||||
'tasks.date_creation',
|
|
||||||
'tasks.date_modification',
|
|
||||||
'tasks.date_completed',
|
|
||||||
'tasks.date_due',
|
|
||||||
'tasks.color_id',
|
|
||||||
'tasks.project_id',
|
|
||||||
'tasks.column_id',
|
|
||||||
'tasks.owner_id',
|
|
||||||
'tasks.creator_id',
|
|
||||||
'tasks.position',
|
|
||||||
'tasks.is_active',
|
|
||||||
'tasks.score',
|
|
||||||
'tasks.category_id',
|
|
||||||
'users.username AS assignee_username',
|
|
||||||
'users.name AS assignee_name'
|
|
||||||
)
|
|
||||||
->join(User::TABLE, 'id', 'owner_id');
|
|
||||||
|
|
||||||
foreach ($filters as $key => $filter) {
|
|
||||||
|
|
||||||
if ($key === 'or') {
|
|
||||||
|
|
||||||
$table->beginOr();
|
|
||||||
|
|
||||||
foreach ($filter as $subfilter) {
|
|
||||||
$table->$subfilter['operator']($subfilter['column'], $subfilter['value']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$table->closeOr();
|
|
||||||
}
|
|
||||||
else if (isset($filter['operator']) && isset($filter['column']) && isset($filter['value'])) {
|
|
||||||
$table->$filter['operator']($filter['column'], $filter['value']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty($sorting)) {
|
|
||||||
$table->orderBy('tasks.position', 'ASC');
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$table->orderBy($sorting['column'], $sorting['direction']);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $table->findAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Count the number of tasks for a given column and status
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param integer $project_id Project id
|
|
||||||
* @param integer $column_id Column id
|
|
||||||
* @param array $status List of status id
|
|
||||||
* @return integer
|
|
||||||
*/
|
|
||||||
public function countByColumnId($project_id, $column_id, array $status = array(self::STATUS_OPEN))
|
|
||||||
{
|
|
||||||
return $this->db
|
|
||||||
->table(self::TABLE)
|
|
||||||
->eq('project_id', $project_id)
|
|
||||||
->eq('column_id', $column_id)
|
|
||||||
->in('is_active', $status)
|
|
||||||
->count();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generic method to duplicate a task
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param array $task Task data
|
|
||||||
* @param array $override Task properties to override
|
|
||||||
* @return integer|boolean
|
|
||||||
*/
|
|
||||||
public function copy(array $task, array $override = array())
|
|
||||||
{
|
|
||||||
// Values to override
|
|
||||||
if (! empty($override)) {
|
|
||||||
$task = $override + $task;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->db->startTransaction();
|
|
||||||
|
|
||||||
// Assign new values
|
|
||||||
$values = array();
|
|
||||||
$values['title'] = $task['title'];
|
|
||||||
$values['description'] = $task['description'];
|
|
||||||
$values['date_creation'] = time();
|
|
||||||
$values['date_modification'] = $values['date_creation'];
|
|
||||||
$values['date_due'] = $task['date_due'];
|
|
||||||
$values['color_id'] = $task['color_id'];
|
|
||||||
$values['project_id'] = $task['project_id'];
|
|
||||||
$values['column_id'] = $task['column_id'];
|
|
||||||
$values['owner_id'] = 0;
|
|
||||||
$values['creator_id'] = $task['creator_id'];
|
|
||||||
$values['position'] = $this->countByColumnId($values['project_id'], $values['column_id']) + 1;
|
|
||||||
$values['score'] = $task['score'];
|
|
||||||
$values['category_id'] = 0;
|
|
||||||
|
|
||||||
// Check if the assigned user is allowed for the new project
|
|
||||||
if ($task['owner_id'] && $this->project->isUserAllowed($values['project_id'], $task['owner_id'])) {
|
|
||||||
$values['owner_id'] = $task['owner_id'];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the category exists
|
|
||||||
if ($task['category_id'] && $this->category->exists($task['category_id'], $task['project_id'])) {
|
|
||||||
$values['category_id'] = $task['category_id'];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save task
|
|
||||||
if (! $this->db->table(self::TABLE)->save($values)) {
|
|
||||||
$this->db->cancelTransaction();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$task_id = $this->db->getConnection()->getLastId();
|
|
||||||
|
|
||||||
// Duplicate subtasks
|
|
||||||
if (! $this->subTask->duplicate($task['id'], $task_id)) {
|
|
||||||
$this->db->cancelTransaction();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->db->closeTransaction();
|
|
||||||
|
|
||||||
// Trigger events
|
|
||||||
$this->event->trigger(self::EVENT_CREATE_UPDATE, array('task_id' => $task_id) + $values);
|
|
||||||
$this->event->trigger(self::EVENT_CREATE, array('task_id' => $task_id) + $values);
|
|
||||||
|
|
||||||
return $task_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Duplicate a task to the same project
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param array $task Task data
|
|
||||||
* @return integer|boolean
|
|
||||||
*/
|
|
||||||
public function duplicateSameProject($task)
|
|
||||||
{
|
|
||||||
return $this->copy($task);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Duplicate a task to another project (always copy to the first column)
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param integer $project_id Destination project id
|
|
||||||
* @param array $task Task data
|
|
||||||
* @return integer|boolean
|
|
||||||
*/
|
|
||||||
public function duplicateToAnotherProject($project_id, array $task)
|
|
||||||
{
|
|
||||||
return $this->copy($task, array(
|
|
||||||
'project_id' => $project_id,
|
|
||||||
'column_id' => $this->board->getFirstColumn($project_id),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare data before task creation or modification
|
* Prepare data before task creation or modification
|
||||||
*
|
*
|
||||||
|
@ -367,40 +47,20 @@ class Task extends Base
|
||||||
*/
|
*/
|
||||||
public function prepare(array &$values)
|
public function prepare(array &$values)
|
||||||
{
|
{
|
||||||
if (isset($values['another_task'])) {
|
$this->dateParser->convert($values, array('date_due', 'date_started'));
|
||||||
unset($values['another_task']);
|
$this->removeFields($values, array('another_task', 'id'));
|
||||||
}
|
$this->resetFields($values, array('date_due', 'date_started', 'score', 'category_id', 'time_estimated', 'time_spent'));
|
||||||
|
$this->convertIntegerFields($values, array('is_active'));
|
||||||
if (! empty($values['date_due']) && ! is_numeric($values['date_due'])) {
|
|
||||||
$values['date_due'] = $this->parseDate($values['date_due']);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Force integer fields at 0 (for Postgresql)
|
|
||||||
if (isset($values['date_due']) && empty($values['date_due'])) {
|
|
||||||
$values['date_due'] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($values['score']) && empty($values['score'])) {
|
|
||||||
$values['score'] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($values['is_active'])) {
|
|
||||||
$values['is_active'] = (int) $values['is_active'];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a task
|
* Prepare data before task creation
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @param array $values Form values
|
* @param array $values Form values
|
||||||
* @return boolean
|
|
||||||
*/
|
*/
|
||||||
public function create(array $values)
|
public function prepareCreation(array &$values)
|
||||||
{
|
{
|
||||||
$this->db->startTransaction();
|
|
||||||
|
|
||||||
// Prepare data
|
|
||||||
$this->prepare($values);
|
$this->prepare($values);
|
||||||
|
|
||||||
if (empty($values['column_id'])) {
|
if (empty($values['column_id'])) {
|
||||||
|
@ -408,15 +68,40 @@ class Task extends Base
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($values['color_id'])) {
|
if (empty($values['color_id'])) {
|
||||||
$colors = $this->getColors();
|
$colors = $this->color->getList();
|
||||||
$values['color_id'] = key($colors);
|
$values['color_id'] = key($colors);
|
||||||
}
|
}
|
||||||
|
|
||||||
$values['date_creation'] = time();
|
$values['date_creation'] = time();
|
||||||
$values['date_modification'] = $values['date_creation'];
|
$values['date_modification'] = $values['date_creation'];
|
||||||
$values['position'] = $this->countByColumnId($values['project_id'], $values['column_id']) + 1;
|
$values['position'] = $this->taskFinder->countByColumnId($values['project_id'], $values['column_id']) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare data before task modification
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $values Form values
|
||||||
|
*/
|
||||||
|
public function prepareModification(array &$values)
|
||||||
|
{
|
||||||
|
$this->prepare($values);
|
||||||
|
$values['date_modification'] = time();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a task
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $values Form values
|
||||||
|
* @return boolean|integer
|
||||||
|
*/
|
||||||
|
public function create(array $values)
|
||||||
|
{
|
||||||
|
$this->db->startTransaction();
|
||||||
|
|
||||||
|
$this->prepareCreation($values);
|
||||||
|
|
||||||
// Save task
|
|
||||||
if (! $this->db->table(self::TABLE)->save($values)) {
|
if (! $this->db->table(self::TABLE)->save($values)) {
|
||||||
$this->db->cancelTransaction();
|
$this->db->cancelTransaction();
|
||||||
return false;
|
return false;
|
||||||
|
@ -444,17 +129,15 @@ class Task extends Base
|
||||||
public function update(array $values, $trigger_events = true)
|
public function update(array $values, $trigger_events = true)
|
||||||
{
|
{
|
||||||
// Fetch original task
|
// Fetch original task
|
||||||
$original_task = $this->getById($values['id']);
|
$original_task = $this->taskFinder->getById($values['id']);
|
||||||
|
|
||||||
if (! $original_task) {
|
if (! $original_task) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare data
|
// Prepare data
|
||||||
$this->prepare($values);
|
|
||||||
$updated_task = $values;
|
$updated_task = $values;
|
||||||
$updated_task['date_modification'] = time();
|
$this->prepareModification($updated_task);
|
||||||
unset($updated_task['id']);
|
|
||||||
|
|
||||||
$result = $this->db->table(self::TABLE)->eq('id', $values['id'])->update($updated_task);
|
$result = $this->db->table(self::TABLE)->eq('id', $values['id'])->update($updated_task);
|
||||||
|
|
||||||
|
@ -498,18 +181,6 @@ class Task extends Base
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return true if the project exists
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param integer $task_id Task id
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function exists($task_id)
|
|
||||||
{
|
|
||||||
return $this->db->table(self::TABLE)->eq('id', $task_id)->count() === 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark a task closed
|
* Mark a task closed
|
||||||
*
|
*
|
||||||
|
@ -519,7 +190,7 @@ class Task extends Base
|
||||||
*/
|
*/
|
||||||
public function close($task_id)
|
public function close($task_id)
|
||||||
{
|
{
|
||||||
if (! $this->exists($task_id)) {
|
if (! $this->taskFinder->exists($task_id)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -532,7 +203,7 @@ class Task extends Base
|
||||||
));
|
));
|
||||||
|
|
||||||
if ($result) {
|
if ($result) {
|
||||||
$this->event->trigger(self::EVENT_CLOSE, array('task_id' => $task_id) + $this->getById($task_id));
|
$this->event->trigger(self::EVENT_CLOSE, array('task_id' => $task_id) + $this->taskFinder->getById($task_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
|
@ -547,7 +218,7 @@ class Task extends Base
|
||||||
*/
|
*/
|
||||||
public function open($task_id)
|
public function open($task_id)
|
||||||
{
|
{
|
||||||
if (! $this->exists($task_id)) {
|
if (! $this->taskFinder->exists($task_id)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -560,7 +231,7 @@ class Task extends Base
|
||||||
));
|
));
|
||||||
|
|
||||||
if ($result) {
|
if ($result) {
|
||||||
$this->event->trigger(self::EVENT_OPEN, array('task_id' => $task_id) + $this->getById($task_id));
|
$this->event->trigger(self::EVENT_OPEN, array('task_id' => $task_id) + $this->taskFinder->getById($task_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
|
@ -575,7 +246,7 @@ class Task extends Base
|
||||||
*/
|
*/
|
||||||
public function remove($task_id)
|
public function remove($task_id)
|
||||||
{
|
{
|
||||||
if (! $this->exists($task_id)) {
|
if (! $this->taskFinder->exists($task_id)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -693,15 +364,18 @@ class Task extends Base
|
||||||
$values['owner_id'] = 0;
|
$values['owner_id'] = 0;
|
||||||
|
|
||||||
// Check if the assigned user is allowed for the new project
|
// Check if the assigned user is allowed for the new project
|
||||||
if ($task['owner_id'] && $this->project->isUserAllowed($project_id, $task['owner_id'])) {
|
if ($task['owner_id'] && $this->projectPermission->isUserAllowed($project_id, $task['owner_id'])) {
|
||||||
$values['owner_id'] = $task['owner_id'];
|
$values['owner_id'] = $task['owner_id'];
|
||||||
}
|
}
|
||||||
|
|
||||||
// We use the first column of the new project
|
// We use the first column of the new project
|
||||||
$values['column_id'] = $this->board->getFirstColumn($project_id);
|
$values['column_id'] = $this->board->getFirstColumn($project_id);
|
||||||
$values['position'] = $this->countByColumnId($project_id, $values['column_id']) + 1;
|
$values['position'] = $this->taskFinder->countByColumnId($project_id, $values['column_id']) + 1;
|
||||||
$values['project_id'] = $project_id;
|
$values['project_id'] = $project_id;
|
||||||
|
|
||||||
|
// The task will be open (close event binding)
|
||||||
|
$values['is_active'] = 1;
|
||||||
|
|
||||||
if ($this->db->table(self::TABLE)->eq('id', $task['id'])->update($values)) {
|
if ($this->db->table(self::TABLE)->eq('id', $task['id'])->update($values)) {
|
||||||
return $task['id'];
|
return $task['id'];
|
||||||
}
|
}
|
||||||
|
@ -710,324 +384,114 @@ class Task extends Base
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Common validation rules
|
* Generic method to duplicate a task
|
||||||
*
|
*
|
||||||
* @access private
|
* @access public
|
||||||
* @return array
|
* @param array $task Task data
|
||||||
|
* @param array $override Task properties to override
|
||||||
|
* @return integer|boolean
|
||||||
*/
|
*/
|
||||||
private function commonValidationRules()
|
public function copy(array $task, array $override = array())
|
||||||
{
|
{
|
||||||
return array(
|
// Values to override
|
||||||
new Validators\Integer('id', t('This value must be an integer')),
|
if (! empty($override)) {
|
||||||
new Validators\Integer('project_id', t('This value must be an integer')),
|
$task = $override + $task;
|
||||||
new Validators\Integer('column_id', t('This value must be an integer')),
|
}
|
||||||
new Validators\Integer('owner_id', t('This value must be an integer')),
|
|
||||||
new Validators\Integer('creator_id', t('This value must be an integer')),
|
$this->db->startTransaction();
|
||||||
new Validators\Integer('score', t('This value must be an integer')),
|
|
||||||
new Validators\Integer('category_id', t('This value must be an integer')),
|
// Assign new values
|
||||||
new Validators\MaxLength('title', t('The maximum length is %d characters', 200), 200),
|
$values = array();
|
||||||
new Validators\Date('date_due', t('Invalid date'), $this->getDateFormats()),
|
$values['title'] = $task['title'];
|
||||||
);
|
$values['description'] = $task['description'];
|
||||||
|
$values['date_creation'] = time();
|
||||||
|
$values['date_modification'] = $values['date_creation'];
|
||||||
|
$values['date_due'] = $task['date_due'];
|
||||||
|
$values['color_id'] = $task['color_id'];
|
||||||
|
$values['project_id'] = $task['project_id'];
|
||||||
|
$values['column_id'] = $task['column_id'];
|
||||||
|
$values['owner_id'] = 0;
|
||||||
|
$values['creator_id'] = $task['creator_id'];
|
||||||
|
$values['position'] = $this->taskFinder->countByColumnId($values['project_id'], $values['column_id']) + 1;
|
||||||
|
$values['score'] = $task['score'];
|
||||||
|
$values['category_id'] = 0;
|
||||||
|
|
||||||
|
// Check if the assigned user is allowed for the new project
|
||||||
|
if ($task['owner_id'] && $this->projectPermission->isUserAllowed($values['project_id'], $task['owner_id'])) {
|
||||||
|
$values['owner_id'] = $task['owner_id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the category exists
|
||||||
|
if ($task['category_id'] && $this->category->exists($task['category_id'], $task['project_id'])) {
|
||||||
|
$values['category_id'] = $task['category_id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save task
|
||||||
|
if (! $this->db->table(Task::TABLE)->save($values)) {
|
||||||
|
$this->db->cancelTransaction();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$task_id = $this->db->getConnection()->getLastId();
|
||||||
|
|
||||||
|
// Duplicate subtasks
|
||||||
|
if (! $this->subTask->duplicate($task['id'], $task_id)) {
|
||||||
|
$this->db->cancelTransaction();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->db->closeTransaction();
|
||||||
|
|
||||||
|
// Trigger events
|
||||||
|
$this->event->trigger(Task::EVENT_CREATE_UPDATE, array('task_id' => $task_id) + $values);
|
||||||
|
$this->event->trigger(Task::EVENT_CREATE, array('task_id' => $task_id) + $values);
|
||||||
|
|
||||||
|
return $task_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate task creation
|
* Duplicate a task to the same project
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @param array $values Form values
|
* @param array $task Task data
|
||||||
* @return array $valid, $errors [0] = Success or not, [1] = List of errors
|
* @return integer|boolean
|
||||||
*/
|
*/
|
||||||
public function validateCreation(array $values)
|
public function duplicateToSameProject($task)
|
||||||
{
|
{
|
||||||
$rules = array(
|
return $this->copy($task);
|
||||||
new Validators\Required('project_id', t('The project is required')),
|
|
||||||
new Validators\Required('title', t('The title is required')),
|
|
||||||
);
|
|
||||||
|
|
||||||
$v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
|
|
||||||
|
|
||||||
return array(
|
|
||||||
$v->execute(),
|
|
||||||
$v->getErrors()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate description creation
|
* Duplicate a task to another project (always copy to the first column)
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @param array $values Form values
|
* @param integer $project_id Destination project id
|
||||||
* @return array $valid, $errors [0] = Success or not, [1] = List of errors
|
* @param array $task Task data
|
||||||
|
* @return integer|boolean
|
||||||
*/
|
*/
|
||||||
public function validateDescriptionCreation(array $values)
|
public function duplicateToAnotherProject($project_id, array $task)
|
||||||
{
|
{
|
||||||
$rules = array(
|
return $this->copy($task, array(
|
||||||
new Validators\Required('id', t('The id is required')),
|
'project_id' => $project_id,
|
||||||
new Validators\Required('description', t('The description is required')),
|
'column_id' => $this->board->getFirstColumn($project_id),
|
||||||
);
|
));
|
||||||
|
|
||||||
$v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
|
|
||||||
|
|
||||||
return array(
|
|
||||||
$v->execute(),
|
|
||||||
$v->getErrors()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate task modification
|
* Get a the task id from a text
|
||||||
|
*
|
||||||
|
* Example: "Fix bug #1234" will return 1234
|
||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @param array $values Form values
|
* @param string $message Text
|
||||||
* @return array $valid, $errors [0] = Success or not, [1] = List of errors
|
|
||||||
*/
|
|
||||||
public function validateModification(array $values)
|
|
||||||
{
|
|
||||||
$rules = array(
|
|
||||||
new Validators\Required('id', t('The id is required')),
|
|
||||||
);
|
|
||||||
|
|
||||||
$v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
|
|
||||||
|
|
||||||
return array(
|
|
||||||
$v->execute(),
|
|
||||||
$v->getErrors()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate assignee change
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param array $values Form values
|
|
||||||
* @return array $valid, $errors [0] = Success or not, [1] = List of errors
|
|
||||||
*/
|
|
||||||
public function validateAssigneeModification(array $values)
|
|
||||||
{
|
|
||||||
$rules = array(
|
|
||||||
new Validators\Required('id', t('The id is required')),
|
|
||||||
new Validators\Required('project_id', t('The project is required')),
|
|
||||||
new Validators\Required('owner_id', t('This value is required')),
|
|
||||||
);
|
|
||||||
|
|
||||||
$v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
|
|
||||||
|
|
||||||
return array(
|
|
||||||
$v->execute(),
|
|
||||||
$v->getErrors()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate category change
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param array $values Form values
|
|
||||||
* @return array $valid, $errors [0] = Success or not, [1] = List of errors
|
|
||||||
*/
|
|
||||||
public function validateCategoryModification(array $values)
|
|
||||||
{
|
|
||||||
$rules = array(
|
|
||||||
new Validators\Required('id', t('The id is required')),
|
|
||||||
new Validators\Required('project_id', t('The project is required')),
|
|
||||||
new Validators\Required('category_id', t('This value is required')),
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
$v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
|
|
||||||
|
|
||||||
return array(
|
|
||||||
$v->execute(),
|
|
||||||
$v->getErrors()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate project modification
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param array $values Form values
|
|
||||||
* @return array $valid, $errors [0] = Success or not, [1] = List of errors
|
|
||||||
*/
|
|
||||||
public function validateProjectModification(array $values)
|
|
||||||
{
|
|
||||||
$rules = array(
|
|
||||||
new Validators\Required('id', t('The id is required')),
|
|
||||||
new Validators\Required('project_id', t('The project is required')),
|
|
||||||
);
|
|
||||||
|
|
||||||
$v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
|
|
||||||
|
|
||||||
return array(
|
|
||||||
$v->execute(),
|
|
||||||
$v->getErrors()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a timestamp if the given date format is correct otherwise return 0
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param string $value Date to parse
|
|
||||||
* @param string $format Date format
|
|
||||||
* @return integer
|
* @return integer
|
||||||
*/
|
*/
|
||||||
public function getValidDate($value, $format)
|
public function getTaskIdFromText($message)
|
||||||
{
|
{
|
||||||
$date = DateTime::createFromFormat($format, $value);
|
if (preg_match('!#(\d+)!i', $message, $matches) && isset($matches[1])) {
|
||||||
|
return $matches[1];
|
||||||
if ($date !== false) {
|
|
||||||
$errors = DateTime::getLastErrors();
|
|
||||||
if ($errors['error_count'] === 0 && $errors['warning_count'] === 0) {
|
|
||||||
$timestamp = $date->getTimestamp();
|
|
||||||
return $timestamp > 0 ? $timestamp : 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse a date ad return a unix timestamp, try different date formats
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param string $value Date to parse
|
|
||||||
* @return integer
|
|
||||||
*/
|
|
||||||
public function parseDate($value)
|
|
||||||
{
|
|
||||||
foreach ($this->getDateFormats() as $format) {
|
|
||||||
|
|
||||||
$timestamp = $this->getValidDate($value, $format);
|
|
||||||
|
|
||||||
if ($timestamp !== 0) {
|
|
||||||
return $timestamp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the list of supported date formats
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getDateFormats()
|
|
||||||
{
|
|
||||||
return array(
|
|
||||||
t('m/d/Y'),
|
|
||||||
'Y-m-d',
|
|
||||||
'Y_m_d',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For a given timestamp, reset the date to midnight
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param integer $timestamp Timestamp
|
|
||||||
* @return integer
|
|
||||||
*/
|
|
||||||
public function resetDateToMidnight($timestamp)
|
|
||||||
{
|
|
||||||
return mktime(0, 0, 0, date('m', $timestamp), date('d', $timestamp), date('Y', $timestamp));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Export a list of tasks for a given project and date range
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param integer $project_id Project id
|
|
||||||
* @param mixed $from Start date (timestamp or user formatted date)
|
|
||||||
* @param mixed $to End date (timestamp or user formatted date)
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function export($project_id, $from, $to)
|
|
||||||
{
|
|
||||||
$sql = '
|
|
||||||
SELECT
|
|
||||||
tasks.id,
|
|
||||||
projects.name AS project_name,
|
|
||||||
tasks.is_active,
|
|
||||||
project_has_categories.name AS category_name,
|
|
||||||
columns.title AS column_title,
|
|
||||||
tasks.position,
|
|
||||||
tasks.color_id,
|
|
||||||
tasks.date_due,
|
|
||||||
creators.username AS creator_username,
|
|
||||||
users.username AS assignee_username,
|
|
||||||
tasks.score,
|
|
||||||
tasks.title,
|
|
||||||
tasks.date_creation,
|
|
||||||
tasks.date_modification,
|
|
||||||
tasks.date_completed
|
|
||||||
FROM tasks
|
|
||||||
LEFT JOIN users ON users.id = tasks.owner_id
|
|
||||||
LEFT JOIN users AS creators ON creators.id = tasks.creator_id
|
|
||||||
LEFT JOIN project_has_categories ON project_has_categories.id = tasks.category_id
|
|
||||||
LEFT JOIN columns ON columns.id = tasks.column_id
|
|
||||||
LEFT JOIN projects ON projects.id = tasks.project_id
|
|
||||||
WHERE tasks.date_creation >= ? AND tasks.date_creation <= ? AND tasks.project_id = ?
|
|
||||||
';
|
|
||||||
|
|
||||||
if (! is_numeric($from)) {
|
|
||||||
$from = $this->resetDateToMidnight($this->parseDate($from));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! is_numeric($to)) {
|
|
||||||
$to = $this->resetDateToMidnight(strtotime('+1 day', $this->parseDate($to)));
|
|
||||||
}
|
|
||||||
|
|
||||||
$rq = $this->db->execute($sql, array($from, $to, $project_id));
|
|
||||||
$tasks = $rq->fetchAll(PDO::FETCH_ASSOC);
|
|
||||||
|
|
||||||
$columns = array(
|
|
||||||
e('Task Id'),
|
|
||||||
e('Project'),
|
|
||||||
e('Status'),
|
|
||||||
e('Category'),
|
|
||||||
e('Column'),
|
|
||||||
e('Position'),
|
|
||||||
e('Color'),
|
|
||||||
e('Due date'),
|
|
||||||
e('Creator'),
|
|
||||||
e('Assignee'),
|
|
||||||
e('Complexity'),
|
|
||||||
e('Title'),
|
|
||||||
e('Creation date'),
|
|
||||||
e('Modification date'),
|
|
||||||
e('Completion date'),
|
|
||||||
);
|
|
||||||
|
|
||||||
$results = array($columns);
|
|
||||||
|
|
||||||
foreach ($tasks as &$task) {
|
|
||||||
$results[] = array_values($this->formatOutput($task));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $results;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Format the output of a task array
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param array $task Task properties
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function formatOutput(array &$task)
|
|
||||||
{
|
|
||||||
$colors = $this->getColors();
|
|
||||||
$task['score'] = $task['score'] ?: '';
|
|
||||||
$task['is_active'] = $task['is_active'] == self::STATUS_OPEN ? e('Open') : e('Closed');
|
|
||||||
$task['color_id'] = $colors[$task['color_id']];
|
|
||||||
$task['date_creation'] = date('Y-m-d', $task['date_creation']);
|
|
||||||
$task['date_due'] = $task['date_due'] ? date('Y-m-d', $task['date_due']) : '';
|
|
||||||
$task['date_modification'] = $task['date_modification'] ? date('Y-m-d', $task['date_modification']) : '';
|
|
||||||
$task['date_completed'] = $task['date_completed'] ? date('Y-m-d', $task['date_completed']) : '';
|
|
||||||
|
|
||||||
return $task;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
136
sources/app/Model/TaskExport.php
Normal file
136
sources/app/Model/TaskExport.php
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Model;
|
||||||
|
|
||||||
|
use PDO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task Export model
|
||||||
|
*
|
||||||
|
* @package model
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
class TaskExport extends Base
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Fetch tasks and return the prepared CSV
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $project_id Project id
|
||||||
|
* @param mixed $from Start date (timestamp or user formatted date)
|
||||||
|
* @param mixed $to End date (timestamp or user formatted date)
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function export($project_id, $from, $to)
|
||||||
|
{
|
||||||
|
$tasks = $this->getTasks($project_id, $from, $to);
|
||||||
|
$results = array($this->getColumns());
|
||||||
|
|
||||||
|
foreach ($tasks as &$task) {
|
||||||
|
$results[] = array_values($this->format($task));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the list of tasks for a given project and date range
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $project_id Project id
|
||||||
|
* @param mixed $from Start date (timestamp or user formatted date)
|
||||||
|
* @param mixed $to End date (timestamp or user formatted date)
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getTasks($project_id, $from, $to)
|
||||||
|
{
|
||||||
|
$sql = '
|
||||||
|
SELECT
|
||||||
|
tasks.id,
|
||||||
|
projects.name AS project_name,
|
||||||
|
tasks.is_active,
|
||||||
|
project_has_categories.name AS category_name,
|
||||||
|
columns.title AS column_title,
|
||||||
|
tasks.position,
|
||||||
|
tasks.color_id,
|
||||||
|
tasks.date_due,
|
||||||
|
creators.username AS creator_username,
|
||||||
|
users.username AS assignee_username,
|
||||||
|
tasks.score,
|
||||||
|
tasks.title,
|
||||||
|
tasks.date_creation,
|
||||||
|
tasks.date_modification,
|
||||||
|
tasks.date_completed,
|
||||||
|
tasks.date_started,
|
||||||
|
tasks.time_estimated,
|
||||||
|
tasks.time_spent
|
||||||
|
FROM tasks
|
||||||
|
LEFT JOIN users ON users.id = tasks.owner_id
|
||||||
|
LEFT JOIN users AS creators ON creators.id = tasks.creator_id
|
||||||
|
LEFT JOIN project_has_categories ON project_has_categories.id = tasks.category_id
|
||||||
|
LEFT JOIN columns ON columns.id = tasks.column_id
|
||||||
|
LEFT JOIN projects ON projects.id = tasks.project_id
|
||||||
|
WHERE tasks.date_creation >= ? AND tasks.date_creation <= ? AND tasks.project_id = ?
|
||||||
|
';
|
||||||
|
|
||||||
|
if (! is_numeric($from)) {
|
||||||
|
$from = $this->dateParser->resetDateToMidnight($this->dateParser->getTimestamp($from));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! is_numeric($to)) {
|
||||||
|
$to = $this->dateParser->resetDateToMidnight(strtotime('+1 day', $this->dateParser->getTimestamp($to)));
|
||||||
|
}
|
||||||
|
|
||||||
|
$rq = $this->db->execute($sql, array($from, $to, $project_id));
|
||||||
|
return $rq->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format the output of a task array
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $task Task properties
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function format(array &$task)
|
||||||
|
{
|
||||||
|
$colors = $this->color->getList();
|
||||||
|
|
||||||
|
$task['is_active'] = $task['is_active'] == Task::STATUS_OPEN ? e('Open') : e('Closed');
|
||||||
|
$task['color_id'] = $colors[$task['color_id']];
|
||||||
|
|
||||||
|
$this->dateParser->format($task, array('date_due', 'date_modification', 'date_creation', 'date_started', 'date_completed'), 'Y-m-d');
|
||||||
|
|
||||||
|
return $task;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get column titles
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getColumns()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
e('Task Id'),
|
||||||
|
e('Project'),
|
||||||
|
e('Status'),
|
||||||
|
e('Category'),
|
||||||
|
e('Column'),
|
||||||
|
e('Position'),
|
||||||
|
e('Color'),
|
||||||
|
e('Due date'),
|
||||||
|
e('Creator'),
|
||||||
|
e('Assignee'),
|
||||||
|
e('Complexity'),
|
||||||
|
e('Title'),
|
||||||
|
e('Creation date'),
|
||||||
|
e('Modification date'),
|
||||||
|
e('Completion date'),
|
||||||
|
e('Start date'),
|
||||||
|
e('Time estimated'),
|
||||||
|
e('Time spent'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
325
sources/app/Model/TaskFinder.php
Normal file
325
sources/app/Model/TaskFinder.php
Normal file
|
@ -0,0 +1,325 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Model;
|
||||||
|
|
||||||
|
use PDO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task Finder model
|
||||||
|
*
|
||||||
|
* @package model
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
class TaskFinder extends Base
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Common request to fetch a list of tasks
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @return \PicoDb\Table
|
||||||
|
*/
|
||||||
|
private function prepareRequestList()
|
||||||
|
{
|
||||||
|
return $this->db
|
||||||
|
->table(Task::TABLE)
|
||||||
|
->columns(
|
||||||
|
'(SELECT count(*) FROM comments WHERE task_id=tasks.id) AS nb_comments',
|
||||||
|
'(SELECT count(*) FROM task_has_files WHERE task_id=tasks.id) AS nb_files',
|
||||||
|
'(SELECT count(*) FROM task_has_subtasks WHERE task_id=tasks.id) AS nb_subtasks',
|
||||||
|
'(SELECT count(*) FROM task_has_subtasks WHERE task_id=tasks.id AND status=2) AS nb_completed_subtasks',
|
||||||
|
'tasks.id',
|
||||||
|
'tasks.reference',
|
||||||
|
'tasks.title',
|
||||||
|
'tasks.description',
|
||||||
|
'tasks.date_creation',
|
||||||
|
'tasks.date_modification',
|
||||||
|
'tasks.date_completed',
|
||||||
|
'tasks.date_due',
|
||||||
|
'tasks.color_id',
|
||||||
|
'tasks.project_id',
|
||||||
|
'tasks.column_id',
|
||||||
|
'tasks.owner_id',
|
||||||
|
'tasks.creator_id',
|
||||||
|
'tasks.position',
|
||||||
|
'tasks.is_active',
|
||||||
|
'tasks.score',
|
||||||
|
'tasks.category_id',
|
||||||
|
'users.username AS assignee_username',
|
||||||
|
'users.name AS assignee_name'
|
||||||
|
)
|
||||||
|
->join(User::TABLE, 'id', 'owner_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task search with pagination
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $project_id Project id
|
||||||
|
* @param string $search Search terms
|
||||||
|
* @param integer $offset Offset
|
||||||
|
* @param integer $limit Limit
|
||||||
|
* @param string $column Sorting column
|
||||||
|
* @param string $direction Sorting direction
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function search($project_id, $search, $offset = 0, $limit = 25, $column = 'tasks.id', $direction = 'DESC')
|
||||||
|
{
|
||||||
|
return $this->prepareRequestList()
|
||||||
|
->eq('project_id', $project_id)
|
||||||
|
->like('title', '%'.$search.'%')
|
||||||
|
->offset($offset)
|
||||||
|
->limit($limit)
|
||||||
|
->orderBy($column, $direction)
|
||||||
|
->findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all completed tasks with pagination
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $project_id Project id
|
||||||
|
* @param integer $offset Offset
|
||||||
|
* @param integer $limit Limit
|
||||||
|
* @param string $column Sorting column
|
||||||
|
* @param string $direction Sorting direction
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getClosedTasks($project_id, $offset = 0, $limit = 25, $column = 'tasks.date_completed', $direction = 'DESC')
|
||||||
|
{
|
||||||
|
return $this->prepareRequestList()
|
||||||
|
->eq('project_id', $project_id)
|
||||||
|
->eq('is_active', Task::STATUS_CLOSED)
|
||||||
|
->offset($offset)
|
||||||
|
->limit($limit)
|
||||||
|
->orderBy($column, $direction)
|
||||||
|
->findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all tasks shown on the board (sorted by position)
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $project_id Project id
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getTasksOnBoard($project_id)
|
||||||
|
{
|
||||||
|
return $this->prepareRequestList()
|
||||||
|
->eq('project_id', $project_id)
|
||||||
|
->eq('is_active', Task::STATUS_OPEN)
|
||||||
|
->asc('tasks.position')
|
||||||
|
->findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all open tasks for a given user
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $user_id User id
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAllTasksByUser($user_id)
|
||||||
|
{
|
||||||
|
return $this->db
|
||||||
|
->table(Task::TABLE)
|
||||||
|
->columns(
|
||||||
|
'tasks.id',
|
||||||
|
'tasks.title',
|
||||||
|
'tasks.date_due',
|
||||||
|
'tasks.date_creation',
|
||||||
|
'tasks.project_id',
|
||||||
|
'tasks.color_id',
|
||||||
|
'projects.name AS project_name'
|
||||||
|
)
|
||||||
|
->join(Project::TABLE, 'id', 'project_id')
|
||||||
|
->eq('tasks.owner_id', $user_id)
|
||||||
|
->eq('tasks.is_active', Task::STATUS_OPEN)
|
||||||
|
->asc('tasks.id')
|
||||||
|
->findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all tasks for a given project and status
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $project_id Project id
|
||||||
|
* @param integer $status_id Status id
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAll($project_id, $status_id = Task::STATUS_OPEN)
|
||||||
|
{
|
||||||
|
return $this->db
|
||||||
|
->table(Task::TABLE)
|
||||||
|
->eq('project_id', $project_id)
|
||||||
|
->eq('is_active', $status_id)
|
||||||
|
->findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of overdue tasks for all projects
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getOverdueTasks()
|
||||||
|
{
|
||||||
|
$tasks = $this->db->table(Task::TABLE)
|
||||||
|
->columns(
|
||||||
|
Task::TABLE.'.id',
|
||||||
|
Task::TABLE.'.title',
|
||||||
|
Task::TABLE.'.date_due',
|
||||||
|
Task::TABLE.'.project_id',
|
||||||
|
Project::TABLE.'.name AS project_name',
|
||||||
|
User::TABLE.'.username AS assignee_username',
|
||||||
|
User::TABLE.'.name AS assignee_name'
|
||||||
|
)
|
||||||
|
->join(Project::TABLE, 'id', 'project_id')
|
||||||
|
->join(User::TABLE, 'id', 'owner_id')
|
||||||
|
->eq(Project::TABLE.'.is_active', 1)
|
||||||
|
->eq(Task::TABLE.'.is_active', 1)
|
||||||
|
->neq(Task::TABLE.'.date_due', 0)
|
||||||
|
->lte(Task::TABLE.'.date_due', mktime(23, 59, 59))
|
||||||
|
->findAll();
|
||||||
|
|
||||||
|
return $tasks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch a task by the id
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $task_id Task id
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getById($task_id)
|
||||||
|
{
|
||||||
|
return $this->db->table(Task::TABLE)->eq('id', $task_id)->findOne();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch a task by the reference (external id)
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param string $reference Task reference
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getByReference($reference)
|
||||||
|
{
|
||||||
|
return $this->db->table(Task::TABLE)->eq('reference', $reference)->findOne();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get task details (fetch more information from other tables)
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $task_id Task id
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getDetails($task_id)
|
||||||
|
{
|
||||||
|
$sql = '
|
||||||
|
SELECT
|
||||||
|
tasks.id,
|
||||||
|
tasks.reference,
|
||||||
|
tasks.title,
|
||||||
|
tasks.description,
|
||||||
|
tasks.date_creation,
|
||||||
|
tasks.date_completed,
|
||||||
|
tasks.date_modification,
|
||||||
|
tasks.date_due,
|
||||||
|
tasks.date_started,
|
||||||
|
tasks.time_estimated,
|
||||||
|
tasks.time_spent,
|
||||||
|
tasks.color_id,
|
||||||
|
tasks.project_id,
|
||||||
|
tasks.column_id,
|
||||||
|
tasks.owner_id,
|
||||||
|
tasks.creator_id,
|
||||||
|
tasks.position,
|
||||||
|
tasks.is_active,
|
||||||
|
tasks.score,
|
||||||
|
tasks.category_id,
|
||||||
|
project_has_categories.name AS category_name,
|
||||||
|
projects.name AS project_name,
|
||||||
|
columns.title AS column_title,
|
||||||
|
users.username AS assignee_username,
|
||||||
|
users.name AS assignee_name,
|
||||||
|
creators.username AS creator_username,
|
||||||
|
creators.name AS creator_name
|
||||||
|
FROM tasks
|
||||||
|
LEFT JOIN users ON users.id = tasks.owner_id
|
||||||
|
LEFT JOIN users AS creators ON creators.id = tasks.creator_id
|
||||||
|
LEFT JOIN project_has_categories ON project_has_categories.id = tasks.category_id
|
||||||
|
LEFT JOIN projects ON projects.id = tasks.project_id
|
||||||
|
LEFT JOIN columns ON columns.id = tasks.column_id
|
||||||
|
WHERE tasks.id = ?
|
||||||
|
';
|
||||||
|
|
||||||
|
$rq = $this->db->execute($sql, array($task_id));
|
||||||
|
return $rq->fetch(PDO::FETCH_ASSOC);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count all tasks for a given project and status
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $project_id Project id
|
||||||
|
* @param array $status List of status id
|
||||||
|
* @return integer
|
||||||
|
*/
|
||||||
|
public function countByProjectId($project_id, array $status = array(Task::STATUS_OPEN, Task::STATUS_CLOSED))
|
||||||
|
{
|
||||||
|
return $this->db
|
||||||
|
->table(Task::TABLE)
|
||||||
|
->eq('project_id', $project_id)
|
||||||
|
->in('is_active', $status)
|
||||||
|
->count();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count the number of tasks for a given column and status
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $project_id Project id
|
||||||
|
* @param integer $column_id Column id
|
||||||
|
* @param array $status List of status id
|
||||||
|
* @return integer
|
||||||
|
*/
|
||||||
|
public function countByColumnId($project_id, $column_id, array $status = array(Task::STATUS_OPEN))
|
||||||
|
{
|
||||||
|
return $this->db
|
||||||
|
->table(Task::TABLE)
|
||||||
|
->eq('project_id', $project_id)
|
||||||
|
->eq('column_id', $column_id)
|
||||||
|
->in('is_active', $status)
|
||||||
|
->count();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count the number of tasks for a custom search
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $project_id Project id
|
||||||
|
* @param string $search Search terms
|
||||||
|
* @return integer
|
||||||
|
*/
|
||||||
|
public function countSearch($project_id, $search)
|
||||||
|
{
|
||||||
|
return $this->db->table(Task::TABLE)
|
||||||
|
->eq('project_id', $project_id)
|
||||||
|
->like('title', '%'.$search.'%')
|
||||||
|
->count();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the task exists
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $task_id Task id
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function exists($task_id)
|
||||||
|
{
|
||||||
|
return $this->db->table(Task::TABLE)->eq('id', $task_id)->count() === 1;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,160 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Model;
|
|
||||||
|
|
||||||
use PDO;
|
|
||||||
use Core\Registry;
|
|
||||||
use Event\TaskHistoryListener;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Task history model
|
|
||||||
*
|
|
||||||
* @package model
|
|
||||||
* @author Frederic Guillot
|
|
||||||
*/
|
|
||||||
class TaskHistory extends BaseHistory
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* SQL table name
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
const TABLE = 'task_has_events';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Maximum number of events
|
|
||||||
*
|
|
||||||
* @var integer
|
|
||||||
*/
|
|
||||||
const MAX_EVENTS = 5000;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param \Core\Registry $registry Registry instance
|
|
||||||
*/
|
|
||||||
public function __construct(Registry $registry)
|
|
||||||
{
|
|
||||||
parent::__construct($registry);
|
|
||||||
$this->table = self::TABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new event
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param integer $project_id Project id
|
|
||||||
* @param integer $task_id Task id
|
|
||||||
* @param integer $creator_id Author of the event (user id)
|
|
||||||
* @param string $event_name Task event name
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function create($project_id, $task_id, $creator_id, $event_name)
|
|
||||||
{
|
|
||||||
$values = array(
|
|
||||||
'project_id' => $project_id,
|
|
||||||
'task_id' => $task_id,
|
|
||||||
'creator_id' => $creator_id,
|
|
||||||
'event_name' => $event_name,
|
|
||||||
'date_creation' => time(),
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->db->startTransaction();
|
|
||||||
|
|
||||||
$this->cleanup(self::MAX_EVENTS - 1);
|
|
||||||
$result = $this->db->table(self::TABLE)->insert($values);
|
|
||||||
|
|
||||||
$this->db->closeTransaction();
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all necessary content to display activity feed
|
|
||||||
*
|
|
||||||
* $author_name
|
|
||||||
* $author_username
|
|
||||||
* $task['id', 'title', 'position', 'column_name']
|
|
||||||
*/
|
|
||||||
public function getAllContentByProjectId($project_id, $limit = 50)
|
|
||||||
{
|
|
||||||
$sql = '
|
|
||||||
SELECT
|
|
||||||
task_has_events.id,
|
|
||||||
task_has_events.date_creation,
|
|
||||||
task_has_events.event_name,
|
|
||||||
task_has_events.task_id,
|
|
||||||
tasks.title as task_title,
|
|
||||||
tasks.position as task_position,
|
|
||||||
columns.title as task_column_name,
|
|
||||||
users.username as author_username,
|
|
||||||
users.name as author_name
|
|
||||||
FROM task_has_events
|
|
||||||
LEFT JOIN users ON users.id=task_has_events.creator_id
|
|
||||||
LEFT JOIN tasks ON tasks.id=task_has_events.task_id
|
|
||||||
LEFT JOIN columns ON columns.id=tasks.column_id
|
|
||||||
WHERE task_has_events.project_id = ?
|
|
||||||
ORDER BY task_has_events.id DESC
|
|
||||||
LIMIT '.$limit.' OFFSET 0
|
|
||||||
';
|
|
||||||
|
|
||||||
$rq = $this->db->execute($sql, array($project_id));
|
|
||||||
$events = $rq->fetchAll(PDO::FETCH_ASSOC);
|
|
||||||
|
|
||||||
foreach ($events as &$event) {
|
|
||||||
$event['author'] = $event['author_name'] ?: $event['author_username'];
|
|
||||||
$event['event_title'] = $this->getTitle($event);
|
|
||||||
$event['event_content'] = $this->getContent($event);
|
|
||||||
$event['event_type'] = 'task';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $events;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the event title (translated)
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param array $event Event properties
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getTitle(array $event)
|
|
||||||
{
|
|
||||||
$titles = array(
|
|
||||||
Task::EVENT_ASSIGNEE_CHANGE => t('%s change the assignee of the task #%d', $event['author'], $event['task_id']),
|
|
||||||
Task::EVENT_UPDATE => t('%s updated the task #%d', $event['author'], $event['task_id']),
|
|
||||||
Task::EVENT_CREATE => t('%s created the task #%d', $event['author'], $event['task_id']),
|
|
||||||
Task::EVENT_CLOSE => t('%s closed the task #%d', $event['author'], $event['task_id']),
|
|
||||||
Task::EVENT_OPEN => t('%s open the task #%d', $event['author'], $event['task_id']),
|
|
||||||
Task::EVENT_MOVE_COLUMN => t('%s moved the task #%d to the column "%s"', $event['author'], $event['task_id'], $event['task_column_name']),
|
|
||||||
Task::EVENT_MOVE_POSITION => t('%s moved the task #%d to the position %d in the column "%s"', $event['author'], $event['task_id'], $event['task_position'], $event['task_column_name']),
|
|
||||||
);
|
|
||||||
|
|
||||||
return isset($titles[$event['event_name']]) ? $titles[$event['event_name']] : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attach events to be able to record the history
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
*/
|
|
||||||
public function attachEvents()
|
|
||||||
{
|
|
||||||
$events = array(
|
|
||||||
Task::EVENT_ASSIGNEE_CHANGE,
|
|
||||||
Task::EVENT_UPDATE,
|
|
||||||
Task::EVENT_CREATE,
|
|
||||||
Task::EVENT_CLOSE,
|
|
||||||
Task::EVENT_OPEN,
|
|
||||||
Task::EVENT_MOVE_COLUMN,
|
|
||||||
Task::EVENT_MOVE_POSITION,
|
|
||||||
);
|
|
||||||
|
|
||||||
$listener = new TaskHistoryListener($this);
|
|
||||||
|
|
||||||
foreach ($events as $event_name) {
|
|
||||||
$this->event->attach($event_name, $listener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
32
sources/app/Model/TaskPermission.php
Normal file
32
sources/app/Model/TaskPermission.php
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task permission model
|
||||||
|
*
|
||||||
|
* @package model
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
class TaskPermission extends Base
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Return true if the user can remove a task
|
||||||
|
*
|
||||||
|
* Regular users can't remove tasks from other people
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function canRemoveTask(array $task)
|
||||||
|
{
|
||||||
|
if ($this->acl->isAdminUser()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (isset($task['creator_id']) && $task['creator_id'] == $this->acl->getUserId()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
216
sources/app/Model/TaskValidator.php
Normal file
216
sources/app/Model/TaskValidator.php
Normal file
|
@ -0,0 +1,216 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Model;
|
||||||
|
|
||||||
|
use SimpleValidator\Validator;
|
||||||
|
use SimpleValidator\Validators;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task validator model
|
||||||
|
*
|
||||||
|
* @package model
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
class TaskValidator extends Base
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Common validation rules
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function commonValidationRules()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
new Validators\Integer('id', t('This value must be an integer')),
|
||||||
|
new Validators\Integer('project_id', t('This value must be an integer')),
|
||||||
|
new Validators\Integer('column_id', t('This value must be an integer')),
|
||||||
|
new Validators\Integer('owner_id', t('This value must be an integer')),
|
||||||
|
new Validators\Integer('creator_id', t('This value must be an integer')),
|
||||||
|
new Validators\Integer('score', t('This value must be an integer')),
|
||||||
|
new Validators\Integer('category_id', t('This value must be an integer')),
|
||||||
|
new Validators\MaxLength('title', t('The maximum length is %d characters', 200), 200),
|
||||||
|
new Validators\Date('date_due', t('Invalid date'), $this->dateParser->getDateFormats()),
|
||||||
|
new Validators\Date('date_started', t('Invalid date'), $this->dateParser->getDateFormats()),
|
||||||
|
new Validators\Numeric('time_spent', t('This value must be numeric')),
|
||||||
|
new Validators\Numeric('time_estimated', t('This value must be numeric')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate task creation
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $values Form values
|
||||||
|
* @return array $valid, $errors [0] = Success or not, [1] = List of errors
|
||||||
|
*/
|
||||||
|
public function validateCreation(array $values)
|
||||||
|
{
|
||||||
|
$rules = array(
|
||||||
|
new Validators\Required('project_id', t('The project is required')),
|
||||||
|
new Validators\Required('title', t('The title is required')),
|
||||||
|
);
|
||||||
|
|
||||||
|
$v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
|
||||||
|
|
||||||
|
return array(
|
||||||
|
$v->execute(),
|
||||||
|
$v->getErrors()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate description creation
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $values Form values
|
||||||
|
* @return array $valid, $errors [0] = Success or not, [1] = List of errors
|
||||||
|
*/
|
||||||
|
public function validateDescriptionCreation(array $values)
|
||||||
|
{
|
||||||
|
$rules = array(
|
||||||
|
new Validators\Required('id', t('The id is required')),
|
||||||
|
new Validators\Required('description', t('The description is required')),
|
||||||
|
);
|
||||||
|
|
||||||
|
$v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
|
||||||
|
|
||||||
|
return array(
|
||||||
|
$v->execute(),
|
||||||
|
$v->getErrors()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate task modification (form)
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $values Form values
|
||||||
|
* @return array $valid, $errors [0] = Success or not, [1] = List of errors
|
||||||
|
*/
|
||||||
|
public function validateModification(array $values)
|
||||||
|
{
|
||||||
|
$rules = array(
|
||||||
|
new Validators\Required('id', t('The id is required')),
|
||||||
|
new Validators\Required('title', t('The title is required')),
|
||||||
|
);
|
||||||
|
|
||||||
|
$v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
|
||||||
|
|
||||||
|
return array(
|
||||||
|
$v->execute(),
|
||||||
|
$v->getErrors()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate task modification (Api)
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $values Form values
|
||||||
|
* @return array $valid, $errors [0] = Success or not, [1] = List of errors
|
||||||
|
*/
|
||||||
|
public function validateApiModification(array $values)
|
||||||
|
{
|
||||||
|
$rules = array(
|
||||||
|
new Validators\Required('id', t('The id is required')),
|
||||||
|
);
|
||||||
|
|
||||||
|
$v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
|
||||||
|
|
||||||
|
return array(
|
||||||
|
$v->execute(),
|
||||||
|
$v->getErrors()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate assignee change
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $values Form values
|
||||||
|
* @return array $valid, $errors [0] = Success or not, [1] = List of errors
|
||||||
|
*/
|
||||||
|
public function validateAssigneeModification(array $values)
|
||||||
|
{
|
||||||
|
$rules = array(
|
||||||
|
new Validators\Required('id', t('The id is required')),
|
||||||
|
new Validators\Required('project_id', t('The project is required')),
|
||||||
|
new Validators\Required('owner_id', t('This value is required')),
|
||||||
|
);
|
||||||
|
|
||||||
|
$v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
|
||||||
|
|
||||||
|
return array(
|
||||||
|
$v->execute(),
|
||||||
|
$v->getErrors()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate category change
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $values Form values
|
||||||
|
* @return array $valid, $errors [0] = Success or not, [1] = List of errors
|
||||||
|
*/
|
||||||
|
public function validateCategoryModification(array $values)
|
||||||
|
{
|
||||||
|
$rules = array(
|
||||||
|
new Validators\Required('id', t('The id is required')),
|
||||||
|
new Validators\Required('project_id', t('The project is required')),
|
||||||
|
new Validators\Required('category_id', t('This value is required')),
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
$v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
|
||||||
|
|
||||||
|
return array(
|
||||||
|
$v->execute(),
|
||||||
|
$v->getErrors()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate project modification
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $values Form values
|
||||||
|
* @return array $valid, $errors [0] = Success or not, [1] = List of errors
|
||||||
|
*/
|
||||||
|
public function validateProjectModification(array $values)
|
||||||
|
{
|
||||||
|
$rules = array(
|
||||||
|
new Validators\Required('id', t('The id is required')),
|
||||||
|
new Validators\Required('project_id', t('The project is required')),
|
||||||
|
);
|
||||||
|
|
||||||
|
$v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
|
||||||
|
|
||||||
|
return array(
|
||||||
|
$v->execute(),
|
||||||
|
$v->getErrors()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate time tracking modification (form)
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $values Form values
|
||||||
|
* @return array $valid, $errors [0] = Success or not, [1] = List of errors
|
||||||
|
*/
|
||||||
|
public function validateTimeModification(array $values)
|
||||||
|
{
|
||||||
|
$rules = array(
|
||||||
|
new Validators\Required('id', t('The id is required')),
|
||||||
|
);
|
||||||
|
|
||||||
|
$v = new Validator($values, array_merge($rules, $this->commonValidationRules()));
|
||||||
|
|
||||||
|
return array(
|
||||||
|
$v->execute(),
|
||||||
|
$v->getErrors()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
45
sources/app/Model/TimeTracking.php
Normal file
45
sources/app/Model/TimeTracking.php
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time tracking model
|
||||||
|
*
|
||||||
|
* @package model
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
class TimeTracking extends Base
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Calculate time metrics for a task
|
||||||
|
*
|
||||||
|
* Use subtasks time metrics if not empty otherwise return task time metrics
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $task Task properties
|
||||||
|
* @param array $subtasks Subtasks list
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getTaskTimesheet(array $task, array $subtasks)
|
||||||
|
{
|
||||||
|
$timesheet = array(
|
||||||
|
'time_spent' => 0,
|
||||||
|
'time_estimated' => 0,
|
||||||
|
'time_remaining' => 0,
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($subtasks as &$subtask) {
|
||||||
|
$timesheet['time_estimated'] += $subtask['time_estimated'];
|
||||||
|
$timesheet['time_spent'] += $subtask['time_spent'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($timesheet['time_estimated'] == 0 && $timesheet['time_spent'] == 0) {
|
||||||
|
$timesheet['time_estimated'] = $task['time_estimated'];
|
||||||
|
$timesheet['time_spent'] = $task['time_spent'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$timesheet['time_remaining'] = $timesheet['time_estimated'] - $timesheet['time_spent'];
|
||||||
|
|
||||||
|
return $timesheet;
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ namespace Model;
|
||||||
|
|
||||||
use SimpleValidator\Validator;
|
use SimpleValidator\Validator;
|
||||||
use SimpleValidator\Validators;
|
use SimpleValidator\Validators;
|
||||||
|
use Core\Session;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User model
|
* User model
|
||||||
|
@ -27,6 +28,24 @@ class User extends Base
|
||||||
*/
|
*/
|
||||||
const EVERYBODY_ID = -1;
|
const EVERYBODY_ID = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true is the given user id is administrator
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $user_id User id
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function isAdmin($user_id)
|
||||||
|
{
|
||||||
|
$result = $this->db
|
||||||
|
->table(User::TABLE)
|
||||||
|
->eq('id', $user_id)
|
||||||
|
->eq('is_admin', 1)
|
||||||
|
->count();
|
||||||
|
|
||||||
|
return $result > 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the default project from the session
|
* Get the default project from the session
|
||||||
*
|
*
|
||||||
|
@ -119,10 +138,64 @@ class User extends Base
|
||||||
return $this->db
|
return $this->db
|
||||||
->table(self::TABLE)
|
->table(self::TABLE)
|
||||||
->asc('username')
|
->asc('username')
|
||||||
->columns('id', 'username', 'name', 'email', 'is_admin', 'default_project_id', 'is_ldap_user', 'notifications_enabled', 'google_id', 'github_id')
|
->columns(
|
||||||
|
'id',
|
||||||
|
'username',
|
||||||
|
'name',
|
||||||
|
'email',
|
||||||
|
'is_admin',
|
||||||
|
'default_project_id',
|
||||||
|
'is_ldap_user',
|
||||||
|
'notifications_enabled',
|
||||||
|
'google_id',
|
||||||
|
'github_id'
|
||||||
|
)
|
||||||
->findAll();
|
->findAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all users with pagination
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $offset Offset
|
||||||
|
* @param integer $limit Limit
|
||||||
|
* @param string $column Sorting column
|
||||||
|
* @param string $direction Sorting direction
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function paginate($offset = 0, $limit = 25, $column = 'username', $direction = 'ASC')
|
||||||
|
{
|
||||||
|
return $this->db
|
||||||
|
->table(self::TABLE)
|
||||||
|
->columns(
|
||||||
|
'id',
|
||||||
|
'username',
|
||||||
|
'name',
|
||||||
|
'email',
|
||||||
|
'is_admin',
|
||||||
|
'default_project_id',
|
||||||
|
'is_ldap_user',
|
||||||
|
'notifications_enabled',
|
||||||
|
'google_id',
|
||||||
|
'github_id'
|
||||||
|
)
|
||||||
|
->offset($offset)
|
||||||
|
->limit($limit)
|
||||||
|
->orderBy($column, $direction)
|
||||||
|
->findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the number of users
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return integer
|
||||||
|
*/
|
||||||
|
public function count()
|
||||||
|
{
|
||||||
|
return $this->db->table(self::TABLE)->count();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List all users (key-value pairs with id/username)
|
* List all users (key-value pairs with id/username)
|
||||||
*
|
*
|
||||||
|
@ -132,7 +205,18 @@ class User extends Base
|
||||||
public function getList()
|
public function getList()
|
||||||
{
|
{
|
||||||
$users = $this->db->table(self::TABLE)->columns('id', 'username', 'name')->findAll();
|
$users = $this->db->table(self::TABLE)->columns('id', 'username', 'name')->findAll();
|
||||||
|
return $this->prepareList($users);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common method to prepare a user list
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $users Users list (from database)
|
||||||
|
* @return array Formated list
|
||||||
|
*/
|
||||||
|
public function prepareList(array $users)
|
||||||
|
{
|
||||||
$result = array();
|
$result = array();
|
||||||
|
|
||||||
foreach ($users as $user) {
|
foreach ($users as $user) {
|
||||||
|
@ -162,21 +246,8 @@ class User extends Base
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($values['confirmation'])) {
|
$this->removeFields($values, array('confirmation', 'current_password'));
|
||||||
unset($values['confirmation']);
|
$this->resetFields($values, array('is_admin', 'is_ldap_user'));
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($values['current_password'])) {
|
|
||||||
unset($values['current_password']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($values['is_admin']) && empty($values['is_admin'])) {
|
|
||||||
$values['is_admin'] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($values['is_ldap_user']) && empty($values['is_ldap_user'])) {
|
|
||||||
$values['is_ldap_user'] = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -205,7 +276,7 @@ class User extends Base
|
||||||
$result = $this->db->table(self::TABLE)->eq('id', $values['id'])->update($values);
|
$result = $this->db->table(self::TABLE)->eq('id', $values['id'])->update($values);
|
||||||
|
|
||||||
// If the user is connected refresh his session
|
// If the user is connected refresh his session
|
||||||
if (session_id() !== '' && $_SESSION['user']['id'] == $values['id']) {
|
if (Session::isOpen() && $_SESSION['user']['id'] == $values['id']) {
|
||||||
$this->updateSession();
|
$this->updateSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,60 +453,4 @@ class User extends Base
|
||||||
|
|
||||||
return array(false, $v->getErrors());
|
return array(false, $v->getErrors());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the user agent of the connected user
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getUserAgent()
|
|
||||||
{
|
|
||||||
return empty($_SERVER['HTTP_USER_AGENT']) ? t('Unknown') : $_SERVER['HTTP_USER_AGENT'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the real IP address of the connected user
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param bool $only_public Return only public IP address
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getIpAddress($only_public = false)
|
|
||||||
{
|
|
||||||
$keys = array(
|
|
||||||
'HTTP_CLIENT_IP',
|
|
||||||
'HTTP_X_FORWARDED_FOR',
|
|
||||||
'HTTP_X_FORWARDED',
|
|
||||||
'HTTP_X_CLUSTER_CLIENT_IP',
|
|
||||||
'HTTP_FORWARDED_FOR',
|
|
||||||
'HTTP_FORWARDED',
|
|
||||||
'REMOTE_ADDR'
|
|
||||||
);
|
|
||||||
|
|
||||||
foreach ($keys as $key) {
|
|
||||||
|
|
||||||
if (isset($_SERVER[$key])) {
|
|
||||||
|
|
||||||
foreach (explode(',', $_SERVER[$key]) as $ip_address) {
|
|
||||||
|
|
||||||
$ip_address = trim($ip_address);
|
|
||||||
|
|
||||||
if ($only_public) {
|
|
||||||
|
|
||||||
// Return only public IP address
|
|
||||||
if (filter_var($ip_address, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false) {
|
|
||||||
return $ip_address;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
return $ip_address;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return t('Unknown');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,9 +64,9 @@ class Webhook extends Base
|
||||||
*/
|
*/
|
||||||
public function attachEvents()
|
public function attachEvents()
|
||||||
{
|
{
|
||||||
$this->url_task_creation = $this->config->get('webhooks_url_task_creation');
|
$this->url_task_creation = $this->config->get('webhook_url_task_creation');
|
||||||
$this->url_task_modification = $this->config->get('webhooks_url_task_modification');
|
$this->url_task_modification = $this->config->get('webhook_url_task_modification');
|
||||||
$this->token = $this->config->get('webhooks_token');
|
$this->token = $this->config->get('webhook_token');
|
||||||
|
|
||||||
if ($this->url_task_creation) {
|
if ($this->url_task_creation) {
|
||||||
$this->attachCreateEvents();
|
$this->attachCreateEvents();
|
||||||
|
@ -88,9 +88,13 @@ class Webhook extends Base
|
||||||
Task::EVENT_UPDATE,
|
Task::EVENT_UPDATE,
|
||||||
Task::EVENT_CLOSE,
|
Task::EVENT_CLOSE,
|
||||||
Task::EVENT_OPEN,
|
Task::EVENT_OPEN,
|
||||||
|
Task::EVENT_MOVE_COLUMN,
|
||||||
|
Task::EVENT_MOVE_POSITION,
|
||||||
|
Task::EVENT_ASSIGNEE_CHANGE,
|
||||||
);
|
);
|
||||||
|
|
||||||
$listener = new WebhookListener($this->url_task_modification, $this);
|
$listener = new WebhookListener($this->registry);
|
||||||
|
$listener->setUrl($this->url_task_modification);
|
||||||
|
|
||||||
foreach ($events as $event_name) {
|
foreach ($events as $event_name) {
|
||||||
$this->event->attach($event_name, $listener);
|
$this->event->attach($event_name, $listener);
|
||||||
|
@ -104,7 +108,10 @@ class Webhook extends Base
|
||||||
*/
|
*/
|
||||||
public function attachCreateEvents()
|
public function attachCreateEvents()
|
||||||
{
|
{
|
||||||
$this->event->attach(Task::EVENT_CREATE, new WebhookListener($this->url_task_creation, $this));
|
$listener = new WebhookListener($this->registry);
|
||||||
|
$listener->setUrl($this->url_task_creation);
|
||||||
|
|
||||||
|
$this->event->attach(Task::EVENT_CREATE, $listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -2,9 +2,98 @@
|
||||||
|
|
||||||
namespace Schema;
|
namespace Schema;
|
||||||
|
|
||||||
|
use PDO;
|
||||||
use Core\Security;
|
use Core\Security;
|
||||||
|
|
||||||
const VERSION = 27;
|
const VERSION = 34;
|
||||||
|
|
||||||
|
function version_34($pdo)
|
||||||
|
{
|
||||||
|
$pdo->exec("ALTER TABLE projects ADD COLUMN is_everybody_allowed TINYINT(1) DEFAULT '0'");
|
||||||
|
}
|
||||||
|
|
||||||
|
function version_33($pdo)
|
||||||
|
{
|
||||||
|
$pdo->exec("
|
||||||
|
CREATE TABLE project_activities (
|
||||||
|
id INT NOT NULL AUTO_INCREMENT,
|
||||||
|
date_creation INT NOT NULL,
|
||||||
|
event_name VARCHAR(50) NOT NULL,
|
||||||
|
creator_id INT,
|
||||||
|
project_id INT,
|
||||||
|
task_id INT,
|
||||||
|
data TEXT,
|
||||||
|
PRIMARY KEY(id),
|
||||||
|
FOREIGN KEY(creator_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY(task_id) REFERENCES tasks(id) ON DELETE CASCADE
|
||||||
|
) ENGINE=InnoDB CHARSET=utf8
|
||||||
|
");
|
||||||
|
|
||||||
|
$pdo->exec('DROP TABLE task_has_events');
|
||||||
|
$pdo->exec('DROP TABLE comment_has_events');
|
||||||
|
$pdo->exec('DROP TABLE subtask_has_events');
|
||||||
|
}
|
||||||
|
|
||||||
|
function version_32($pdo)
|
||||||
|
{
|
||||||
|
$pdo->exec("ALTER TABLE tasks ADD COLUMN date_started INTEGER");
|
||||||
|
$pdo->exec("ALTER TABLE tasks ADD COLUMN time_spent FLOAT DEFAULT 0");
|
||||||
|
$pdo->exec("ALTER TABLE tasks ADD COLUMN time_estimated FLOAT DEFAULT 0");
|
||||||
|
|
||||||
|
$pdo->exec("ALTER TABLE task_has_subtasks MODIFY time_estimated FLOAT");
|
||||||
|
$pdo->exec("ALTER TABLE task_has_subtasks MODIFY time_spent FLOAT");
|
||||||
|
}
|
||||||
|
|
||||||
|
function version_31($pdo)
|
||||||
|
{
|
||||||
|
$pdo->exec("ALTER TABLE projects ADD COLUMN is_private TINYINT(1) DEFAULT '0'");
|
||||||
|
}
|
||||||
|
|
||||||
|
function version_30($pdo)
|
||||||
|
{
|
||||||
|
$rq = $pdo->prepare('INSERT INTO settings VALUES (?, ?)');
|
||||||
|
$rq->execute(array('application_date_format', 'm/d/Y'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function version_29($pdo)
|
||||||
|
{
|
||||||
|
$pdo->exec("
|
||||||
|
CREATE TABLE settings (
|
||||||
|
`option` VARCHAR(100) PRIMARY KEY,
|
||||||
|
`value` VARCHAR(255) DEFAULT ''
|
||||||
|
)
|
||||||
|
");
|
||||||
|
|
||||||
|
// Migrate old config parameters
|
||||||
|
$rq = $pdo->prepare('SELECT * FROM config');
|
||||||
|
$rq->execute();
|
||||||
|
$parameters = $rq->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
$rq = $pdo->prepare('INSERT INTO settings VALUES (?, ?)');
|
||||||
|
$rq->execute(array('board_highlight_period', defined('RECENT_TASK_PERIOD') ? RECENT_TASK_PERIOD : 48*60*60));
|
||||||
|
$rq->execute(array('board_public_refresh_interval', defined('BOARD_PUBLIC_CHECK_INTERVAL') ? BOARD_PUBLIC_CHECK_INTERVAL : 60));
|
||||||
|
$rq->execute(array('board_private_refresh_interval', defined('BOARD_CHECK_INTERVAL') ? BOARD_CHECK_INTERVAL : 10));
|
||||||
|
$rq->execute(array('board_columns', $parameters['default_columns']));
|
||||||
|
$rq->execute(array('webhook_url_task_creation', $parameters['webhooks_url_task_creation']));
|
||||||
|
$rq->execute(array('webhook_url_task_modification', $parameters['webhooks_url_task_modification']));
|
||||||
|
$rq->execute(array('webhook_token', $parameters['webhooks_token']));
|
||||||
|
$rq->execute(array('api_token', $parameters['api_token']));
|
||||||
|
$rq->execute(array('application_language', $parameters['language']));
|
||||||
|
$rq->execute(array('application_timezone', $parameters['timezone']));
|
||||||
|
$rq->execute(array('application_url', defined('KANBOARD_URL') ? KANBOARD_URL : ''));
|
||||||
|
|
||||||
|
$pdo->exec('DROP TABLE config');
|
||||||
|
}
|
||||||
|
|
||||||
|
function version_28($pdo)
|
||||||
|
{
|
||||||
|
$pdo->exec("ALTER TABLE tasks ADD COLUMN reference VARCHAR(50) DEFAULT ''");
|
||||||
|
$pdo->exec("ALTER TABLE comments ADD COLUMN reference VARCHAR(50) DEFAULT ''");
|
||||||
|
|
||||||
|
$pdo->exec('CREATE INDEX tasks_reference_idx ON tasks(reference)');
|
||||||
|
$pdo->exec('CREATE INDEX comments_reference_idx ON comments(reference)');
|
||||||
|
}
|
||||||
|
|
||||||
function version_27($pdo)
|
function version_27($pdo)
|
||||||
{
|
{
|
||||||
|
@ -294,7 +383,7 @@ function version_1($pdo)
|
||||||
id INT NOT NULL AUTO_INCREMENT,
|
id INT NOT NULL AUTO_INCREMENT,
|
||||||
task_id INT,
|
task_id INT,
|
||||||
user_id INT,
|
user_id INT,
|
||||||
date INT,
|
`date` INT,
|
||||||
comment TEXT,
|
comment TEXT,
|
||||||
PRIMARY KEY (id),
|
PRIMARY KEY (id),
|
||||||
FOREIGN KEY(task_id) REFERENCES tasks(id) ON DELETE CASCADE,
|
FOREIGN KEY(task_id) REFERENCES tasks(id) ON DELETE CASCADE,
|
||||||
|
|
|
@ -2,9 +2,97 @@
|
||||||
|
|
||||||
namespace Schema;
|
namespace Schema;
|
||||||
|
|
||||||
|
use PDO;
|
||||||
use Core\Security;
|
use Core\Security;
|
||||||
|
|
||||||
const VERSION = 8;
|
const VERSION = 15;
|
||||||
|
|
||||||
|
function version_15($pdo)
|
||||||
|
{
|
||||||
|
$pdo->exec("ALTER TABLE projects ADD COLUMN is_everybody_allowed BOOLEAN DEFAULT '0'");
|
||||||
|
}
|
||||||
|
|
||||||
|
function version_14($pdo)
|
||||||
|
{
|
||||||
|
$pdo->exec("
|
||||||
|
CREATE TABLE project_activities (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
date_creation INTEGER NOT NULL,
|
||||||
|
event_name VARCHAR(50) NOT NULL,
|
||||||
|
creator_id INTEGER,
|
||||||
|
project_id INTEGER,
|
||||||
|
task_id INTEGER,
|
||||||
|
data TEXT,
|
||||||
|
FOREIGN KEY(creator_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY(task_id) REFERENCES tasks(id) ON DELETE CASCADE
|
||||||
|
)
|
||||||
|
");
|
||||||
|
|
||||||
|
$pdo->exec('DROP TABLE task_has_events');
|
||||||
|
$pdo->exec('DROP TABLE comment_has_events');
|
||||||
|
$pdo->exec('DROP TABLE subtask_has_events');
|
||||||
|
}
|
||||||
|
|
||||||
|
function version_13($pdo)
|
||||||
|
{
|
||||||
|
$pdo->exec("ALTER TABLE tasks ADD COLUMN date_started INTEGER");
|
||||||
|
$pdo->exec("ALTER TABLE tasks ADD COLUMN time_spent FLOAT DEFAULT 0");
|
||||||
|
$pdo->exec("ALTER TABLE tasks ADD COLUMN time_estimated FLOAT DEFAULT 0");
|
||||||
|
|
||||||
|
$pdo->exec("ALTER TABLE task_has_subtasks ALTER COLUMN time_estimated TYPE FLOAT");
|
||||||
|
$pdo->exec("ALTER TABLE task_has_subtasks ALTER COLUMN time_spent TYPE FLOAT");
|
||||||
|
}
|
||||||
|
|
||||||
|
function version_12($pdo)
|
||||||
|
{
|
||||||
|
$pdo->exec("ALTER TABLE projects ADD COLUMN is_private BOOLEAN DEFAULT '0'");
|
||||||
|
}
|
||||||
|
|
||||||
|
function version_11($pdo)
|
||||||
|
{
|
||||||
|
$rq = $pdo->prepare('INSERT INTO settings VALUES (?, ?)');
|
||||||
|
$rq->execute(array('application_date_format', 'm/d/Y'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function version_10($pdo)
|
||||||
|
{
|
||||||
|
$pdo->exec("
|
||||||
|
CREATE TABLE settings (
|
||||||
|
option VARCHAR(100) PRIMARY KEY,
|
||||||
|
value VARCHAR(255) DEFAULT ''
|
||||||
|
)
|
||||||
|
");
|
||||||
|
|
||||||
|
// Migrate old config parameters
|
||||||
|
$rq = $pdo->prepare('SELECT * FROM config');
|
||||||
|
$rq->execute();
|
||||||
|
$parameters = $rq->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
$rq = $pdo->prepare('INSERT INTO settings VALUES (?, ?)');
|
||||||
|
$rq->execute(array('board_highlight_period', defined('RECENT_TASK_PERIOD') ? RECENT_TASK_PERIOD : 48*60*60));
|
||||||
|
$rq->execute(array('board_public_refresh_interval', defined('BOARD_PUBLIC_CHECK_INTERVAL') ? BOARD_PUBLIC_CHECK_INTERVAL : 60));
|
||||||
|
$rq->execute(array('board_private_refresh_interval', defined('BOARD_CHECK_INTERVAL') ? BOARD_CHECK_INTERVAL : 10));
|
||||||
|
$rq->execute(array('board_columns', $parameters['default_columns']));
|
||||||
|
$rq->execute(array('webhook_url_task_creation', $parameters['webhooks_url_task_creation']));
|
||||||
|
$rq->execute(array('webhook_url_task_modification', $parameters['webhooks_url_task_modification']));
|
||||||
|
$rq->execute(array('webhook_token', $parameters['webhooks_token']));
|
||||||
|
$rq->execute(array('api_token', $parameters['api_token']));
|
||||||
|
$rq->execute(array('application_language', $parameters['language']));
|
||||||
|
$rq->execute(array('application_timezone', $parameters['timezone']));
|
||||||
|
$rq->execute(array('application_url', defined('KANBOARD_URL') ? KANBOARD_URL : ''));
|
||||||
|
|
||||||
|
$pdo->exec('DROP TABLE config');
|
||||||
|
}
|
||||||
|
|
||||||
|
function version_9($pdo)
|
||||||
|
{
|
||||||
|
$pdo->exec("ALTER TABLE tasks ADD COLUMN reference VARCHAR(50) DEFAULT ''");
|
||||||
|
$pdo->exec("ALTER TABLE comments ADD COLUMN reference VARCHAR(50) DEFAULT ''");
|
||||||
|
|
||||||
|
$pdo->exec('CREATE INDEX tasks_reference_idx ON tasks(reference)');
|
||||||
|
$pdo->exec('CREATE INDEX comments_reference_idx ON comments(reference)');
|
||||||
|
}
|
||||||
|
|
||||||
function version_8($pdo)
|
function version_8($pdo)
|
||||||
{
|
{
|
||||||
|
@ -22,7 +110,7 @@ function version_6($pdo)
|
||||||
CREATE TABLE task_has_events (
|
CREATE TABLE task_has_events (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
date_creation INTEGER NOT NULL,
|
date_creation INTEGER NOT NULL,
|
||||||
event_name TEXT NOT NULL,
|
event_name VARCHAR(50) NOT NULL,
|
||||||
creator_id INTEGER,
|
creator_id INTEGER,
|
||||||
project_id INTEGER,
|
project_id INTEGER,
|
||||||
task_id INTEGER,
|
task_id INTEGER,
|
||||||
|
@ -37,7 +125,7 @@ function version_6($pdo)
|
||||||
CREATE TABLE subtask_has_events (
|
CREATE TABLE subtask_has_events (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
date_creation INTEGER NOT NULL,
|
date_creation INTEGER NOT NULL,
|
||||||
event_name TEXT NOT NULL,
|
event_name VARCHAR(50) NOT NULL,
|
||||||
creator_id INTEGER,
|
creator_id INTEGER,
|
||||||
project_id INTEGER,
|
project_id INTEGER,
|
||||||
subtask_id INTEGER,
|
subtask_id INTEGER,
|
||||||
|
@ -54,7 +142,7 @@ function version_6($pdo)
|
||||||
CREATE TABLE comment_has_events (
|
CREATE TABLE comment_has_events (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
date_creation INTEGER NOT NULL,
|
date_creation INTEGER NOT NULL,
|
||||||
event_name TEXT NOT NULL,
|
event_name VARCHAR(50) NOT NULL,
|
||||||
creator_id INTEGER,
|
creator_id INTEGER,
|
||||||
project_id INTEGER,
|
project_id INTEGER,
|
||||||
comment_id INTEGER,
|
comment_id INTEGER,
|
||||||
|
|
|
@ -3,8 +3,93 @@
|
||||||
namespace Schema;
|
namespace Schema;
|
||||||
|
|
||||||
use Core\Security;
|
use Core\Security;
|
||||||
|
use PDO;
|
||||||
|
|
||||||
const VERSION = 27;
|
const VERSION = 34;
|
||||||
|
|
||||||
|
function version_34($pdo)
|
||||||
|
{
|
||||||
|
$pdo->exec('ALTER TABLE projects ADD COLUMN is_everybody_allowed INTEGER DEFAULT "0"');
|
||||||
|
}
|
||||||
|
|
||||||
|
function version_33($pdo)
|
||||||
|
{
|
||||||
|
$pdo->exec("
|
||||||
|
CREATE TABLE project_activities (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
date_creation INTEGER NOT NULL,
|
||||||
|
event_name TEXT NOT NULL,
|
||||||
|
creator_id INTEGER,
|
||||||
|
project_id INTEGER,
|
||||||
|
task_id INTEGER,
|
||||||
|
data TEXT,
|
||||||
|
FOREIGN KEY(creator_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY(task_id) REFERENCES tasks(id) ON DELETE CASCADE
|
||||||
|
)
|
||||||
|
");
|
||||||
|
|
||||||
|
$pdo->exec('DROP TABLE task_has_events');
|
||||||
|
$pdo->exec('DROP TABLE comment_has_events');
|
||||||
|
$pdo->exec('DROP TABLE subtask_has_events');
|
||||||
|
}
|
||||||
|
|
||||||
|
function version_32($pdo)
|
||||||
|
{
|
||||||
|
$pdo->exec("ALTER TABLE tasks ADD COLUMN date_started INTEGER");
|
||||||
|
$pdo->exec("ALTER TABLE tasks ADD COLUMN time_spent NUMERIC DEFAULT 0");
|
||||||
|
$pdo->exec("ALTER TABLE tasks ADD COLUMN time_estimated NUMERIC DEFAULT 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
function version_31($pdo)
|
||||||
|
{
|
||||||
|
$pdo->exec('ALTER TABLE projects ADD COLUMN is_private INTEGER DEFAULT "0"');
|
||||||
|
}
|
||||||
|
|
||||||
|
function version_30($pdo)
|
||||||
|
{
|
||||||
|
$rq = $pdo->prepare('INSERT INTO settings VALUES (?, ?)');
|
||||||
|
$rq->execute(array('application_date_format', 'm/d/Y'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function version_29($pdo)
|
||||||
|
{
|
||||||
|
$pdo->exec("
|
||||||
|
CREATE TABLE settings (
|
||||||
|
option TEXT PRIMARY KEY,
|
||||||
|
value TEXT DEFAULT ''
|
||||||
|
)
|
||||||
|
");
|
||||||
|
|
||||||
|
// Migrate old config parameters
|
||||||
|
$rq = $pdo->prepare('SELECT * FROM config');
|
||||||
|
$rq->execute();
|
||||||
|
$parameters = $rq->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
$rq = $pdo->prepare('INSERT INTO settings VALUES (?, ?)');
|
||||||
|
$rq->execute(array('board_highlight_period', defined('RECENT_TASK_PERIOD') ? RECENT_TASK_PERIOD : 48*60*60));
|
||||||
|
$rq->execute(array('board_public_refresh_interval', defined('BOARD_PUBLIC_CHECK_INTERVAL') ? BOARD_PUBLIC_CHECK_INTERVAL : 60));
|
||||||
|
$rq->execute(array('board_private_refresh_interval', defined('BOARD_CHECK_INTERVAL') ? BOARD_CHECK_INTERVAL : 10));
|
||||||
|
$rq->execute(array('board_columns', $parameters['default_columns']));
|
||||||
|
$rq->execute(array('webhook_url_task_creation', $parameters['webhooks_url_task_creation']));
|
||||||
|
$rq->execute(array('webhook_url_task_modification', $parameters['webhooks_url_task_modification']));
|
||||||
|
$rq->execute(array('webhook_token', $parameters['webhooks_token']));
|
||||||
|
$rq->execute(array('api_token', $parameters['api_token']));
|
||||||
|
$rq->execute(array('application_language', $parameters['language']));
|
||||||
|
$rq->execute(array('application_timezone', $parameters['timezone']));
|
||||||
|
$rq->execute(array('application_url', defined('KANBOARD_URL') ? KANBOARD_URL : ''));
|
||||||
|
|
||||||
|
$pdo->exec('DROP TABLE config');
|
||||||
|
}
|
||||||
|
|
||||||
|
function version_28($pdo)
|
||||||
|
{
|
||||||
|
$pdo->exec("ALTER TABLE tasks ADD COLUMN reference TEXT DEFAULT ''");
|
||||||
|
$pdo->exec("ALTER TABLE comments ADD COLUMN reference TEXT DEFAULT ''");
|
||||||
|
|
||||||
|
$pdo->exec('CREATE INDEX tasks_reference_idx ON tasks(reference)');
|
||||||
|
$pdo->exec('CREATE INDEX comments_reference_idx ON comments(reference)');
|
||||||
|
}
|
||||||
|
|
||||||
function version_27($pdo)
|
function version_27($pdo)
|
||||||
{
|
{
|
||||||
|
@ -118,8 +203,8 @@ function version_18($pdo)
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
title TEXT COLLATE NOCASE,
|
title TEXT COLLATE NOCASE,
|
||||||
status INTEGER DEFAULT 0,
|
status INTEGER DEFAULT 0,
|
||||||
time_estimated INTEGER DEFAULT 0,
|
time_estimated NUMERIC DEFAULT 0,
|
||||||
time_spent INTEGER DEFAULT 0,
|
time_spent NUMERIC DEFAULT 0,
|
||||||
task_id INTEGER NOT NULL,
|
task_id INTEGER NOT NULL,
|
||||||
user_id INTEGER,
|
user_id INTEGER,
|
||||||
FOREIGN KEY(task_id) REFERENCES tasks(id) ON DELETE CASCADE
|
FOREIGN KEY(task_id) REFERENCES tasks(id) ON DELETE CASCADE
|
||||||
|
|
22
sources/app/Template/action_event.php
Normal file
22
sources/app/Template/action_event.php
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<div class="page-header">
|
||||||
|
<h2><?= t('Automatic actions for the project "%s"', $project['name']) ?></h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3><?= t('Choose an event') ?></h3>
|
||||||
|
<form method="post" action="?controller=action&action=params&project_id=<?= $project['id'] ?>" autocomplete="off">
|
||||||
|
<?= Helper\form_csrf() ?>
|
||||||
|
<?= Helper\form_hidden('project_id', $values) ?>
|
||||||
|
<?= Helper\form_hidden('action_name', $values) ?>
|
||||||
|
|
||||||
|
<?= Helper\form_label(t('Event'), 'event_name') ?>
|
||||||
|
<?= Helper\form_select('event_name', $events, $values) ?><br/>
|
||||||
|
|
||||||
|
<div class="form-help">
|
||||||
|
<?= t('When the selected event occurs execute the corresponding action.') ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-actions">
|
||||||
|
<input type="submit" value="<?= t('Next step') ?>" class="btn btn-blue"/>
|
||||||
|
<?= t('or') ?> <a href="?controller=action&action=index&project_id=<?= $project['id'] ?>"><?= t('cancel') ?></a>
|
||||||
|
</div>
|
||||||
|
</form>
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue