summaryrefslogtreecommitdiff
path: root/app/Core
diff options
context:
space:
mode:
Diffstat (limited to 'app/Core')
-rw-r--r--app/Core/Base.php21
-rw-r--r--app/Core/Cache/Base.php20
-rw-r--r--app/Core/Csv.php3
-rw-r--r--app/Core/DateParser.php218
-rw-r--r--app/Core/Event/EventManager.php1
-rw-r--r--app/Core/ExternalLink/ExternalLinkInterface.php36
-rw-r--r--app/Core/ExternalLink/ExternalLinkManager.php173
-rw-r--r--app/Core/ExternalLink/ExternalLinkProviderInterface.php71
-rw-r--r--app/Core/ExternalLink/ExternalLinkProviderNotFound.php15
-rw-r--r--app/Core/Helper.php72
-rw-r--r--app/Core/Http/Client.php13
-rw-r--r--app/Core/Http/Request.php13
-rw-r--r--app/Core/Http/Response.php7
-rw-r--r--app/Core/Ldap/Client.php5
-rw-r--r--app/Core/Ldap/Query.php2
-rw-r--r--app/Core/Mail/Client.php6
-rw-r--r--app/Core/ObjectStorage/FileStorage.php5
-rw-r--r--app/Core/Plugin/Loader.php1
-rw-r--r--app/Core/Security/AccessMap.php10
-rw-r--r--app/Core/Security/OAuthAuthenticationProviderInterface.php4
-rw-r--r--app/Core/Security/PasswordAuthenticationProviderInterface.php2
-rw-r--r--app/Core/Security/PreAuthenticationProviderInterface.php2
-rw-r--r--app/Core/Template.php76
-rw-r--r--app/Core/Translator.php28
-rw-r--r--app/Core/User/UserProfile.php2
25 files changed, 571 insertions, 235 deletions
diff --git a/app/Core/Base.php b/app/Core/Base.php
index 2821e5ae..e53f299a 100644
--- a/app/Core/Base.php
+++ b/app/Core/Base.php
@@ -16,6 +16,7 @@ use Pimple\Container;
* @property \Kanboard\Analytic\AverageLeadCycleTimeAnalytic $averageLeadCycleTimeAnalytic
* @property \Kanboard\Analytic\AverageTimeSpentColumnAnalytic $averageTimeSpentColumnAnalytic
* @property \Kanboard\Core\Action\ActionManager $actionManager
+ * @property \Kanboard\Core\ExternalLink\ExternalLinkManager $externalLinkManager
* @property \Kanboard\Core\Cache\MemoryCache $memoryCache
* @property \Kanboard\Core\Event\EventManager $eventManager
* @property \Kanboard\Core\Group\GroupManager $groupManager
@@ -30,7 +31,6 @@ use Pimple\Container;
* @property \Kanboard\Core\ObjectStorage\ObjectStorageInterface $objectStorage
* @property \Kanboard\Core\Plugin\Hook $hook
* @property \Kanboard\Core\Plugin\Loader $pluginLoader
- * @property \Kanboard\Core\Security\AccessMap $projectAccessMap
* @property \Kanboard\Core\Security\AuthenticationManager $authenticationManager
* @property \Kanboard\Core\Security\AccessMap $applicationAccessMap
* @property \Kanboard\Core\Security\AccessMap $projectAccessMap
@@ -62,21 +62,21 @@ use Pimple\Container;
* @property \Kanboard\Model\Board $board
* @property \Kanboard\Model\Category $category
* @property \Kanboard\Model\Color $color
+ * @property \Kanboard\Model\Column $column
* @property \Kanboard\Model\Comment $comment
* @property \Kanboard\Model\Config $config
* @property \Kanboard\Model\Currency $currency
* @property \Kanboard\Model\CustomFilter $customFilter
- * @property \Kanboard\Model\File $file
+ * @property \Kanboard\Model\TaskFile $taskFile
+ * @property \Kanboard\Model\ProjectFile $projectFile
* @property \Kanboard\Model\Group $group
* @property \Kanboard\Model\GroupMember $groupMember
* @property \Kanboard\Model\LastLogin $lastLogin
* @property \Kanboard\Model\Link $link
* @property \Kanboard\Model\Notification $notification
- * @property \Kanboard\Model\OverdueNotification $overdueNotification
* @property \Kanboard\Model\PasswordReset $passwordReset
* @property \Kanboard\Model\Project $project
* @property \Kanboard\Model\ProjectActivity $projectActivity
- * @property \Kanboard\Model\ProjectAnalytic $projectAnalytic
* @property \Kanboard\Model\ProjectDuplication $projectDuplication
* @property \Kanboard\Model\ProjectDailyColumnStats $projectDailyColumnStats
* @property \Kanboard\Model\ProjectDailyStats $projectDailyStats
@@ -89,15 +89,13 @@ use Pimple\Container;
* @property \Kanboard\Model\ProjectNotificationType $projectNotificationType
* @property \Kanboard\Model\RememberMeSession $rememberMeSession
* @property \Kanboard\Model\Subtask $subtask
- * @property \Kanboard\Model\SubtaskExport $subtaskExport
* @property \Kanboard\Model\SubtaskTimeTracking $subtaskTimeTracking
* @property \Kanboard\Model\Swimlane $swimlane
* @property \Kanboard\Model\Task $task
* @property \Kanboard\Model\TaskAnalytic $taskAnalytic
* @property \Kanboard\Model\TaskCreation $taskCreation
* @property \Kanboard\Model\TaskDuplication $taskDuplication
- * @property \Kanboard\Model\TaskExport $taskExport
- * @property \Kanboard\Model\TaskImport $taskImport
+ * @property \Kanboard\Model\TaskExternalLink $taskExternalLink
* @property \Kanboard\Model\TaskFinder $taskFinder
* @property \Kanboard\Model\TaskFilter $taskFilter
* @property \Kanboard\Model\TaskLink $taskLink
@@ -108,7 +106,6 @@ use Pimple\Container;
* @property \Kanboard\Model\TaskMetadata $taskMetadata
* @property \Kanboard\Model\Transition $transition
* @property \Kanboard\Model\User $user
- * @property \Kanboard\Model\UserImport $userImport
* @property \Kanboard\Model\UserLocking $userLocking
* @property \Kanboard\Model\UserMention $userMention
* @property \Kanboard\Model\UserNotification $userNotification
@@ -116,12 +113,10 @@ use Pimple\Container;
* @property \Kanboard\Model\UserNotificationFilter $userNotificationFilter
* @property \Kanboard\Model\UserUnreadNotification $userUnreadNotification
* @property \Kanboard\Model\UserMetadata $userMetadata
- * @property \Kanboard\Model\Webhook $webhook
* @property \Kanboard\Validator\ActionValidator $actionValidator
* @property \Kanboard\Validator\AuthValidator $authValidator
* @property \Kanboard\Validator\ColumnValidator $columnValidator
* @property \Kanboard\Validator\CategoryValidator $categoryValidator
- * @property \Kanboard\Validator\ColumnValidator $columnValidator
* @property \Kanboard\Validator\CommentValidator $commentValidator
* @property \Kanboard\Validator\CurrencyValidator $currencyValidator
* @property \Kanboard\Validator\CustomFilterValidator $customFilterValidator
@@ -132,8 +127,14 @@ use Pimple\Container;
* @property \Kanboard\Validator\SubtaskValidator $subtaskValidator
* @property \Kanboard\Validator\SwimlaneValidator $swimlaneValidator
* @property \Kanboard\Validator\TaskLinkValidator $taskLinkValidator
+ * @property \Kanboard\Validator\ExternalLinkValidator $externalLinkValidator
* @property \Kanboard\Validator\TaskValidator $taskValidator
* @property \Kanboard\Validator\UserValidator $userValidator
+ * @property \Kanboard\Import\TaskImport $taskImport
+ * @property \Kanboard\Import\UserImport $userImport
+ * @property \Kanboard\Export\SubtaskExport $subtaskExport
+ * @property \Kanboard\Export\TaskExport $taskExport
+ * @property \Kanboard\Export\TransitionExport $transitionExport
* @property \Psr\Log\LoggerInterface $logger
* @property \PicoDb\Database $db
* @property \Symfony\Component\EventDispatcher\EventDispatcher $dispatcher
diff --git a/app/Core/Cache/Base.php b/app/Core/Cache/Base.php
index d62b8507..2879f1f1 100644
--- a/app/Core/Cache/Base.php
+++ b/app/Core/Cache/Base.php
@@ -11,6 +11,26 @@ namespace Kanboard\Core\Cache;
abstract class Base
{
/**
+ * Fetch value from cache
+ *
+ * @abstract
+ * @access public
+ * @param string $key
+ * @return mixed Null when not found, cached value otherwise
+ */
+ abstract public function get($key);
+
+ /**
+ * Save a new value in the cache
+ *
+ * @abstract
+ * @access public
+ * @param string $key
+ * @param mixed $value
+ */
+ abstract public function set($key, $value);
+
+ /**
* Proxy cache
*
* Note: Arguments must be scalar types
diff --git a/app/Core/Csv.php b/app/Core/Csv.php
index e45af24c..88010166 100644
--- a/app/Core/Csv.php
+++ b/app/Core/Csv.php
@@ -87,7 +87,8 @@ class Csv
*
* @static
* @access public
- * @return integer
+ * @param mixed $value
+ * @return int
*/
public static function getBooleanValue($value)
{
diff --git a/app/Core/DateParser.php b/app/Core/DateParser.php
index 6577af0f..835eb3e3 100644
--- a/app/Core/DateParser.php
+++ b/app/Core/DateParser.php
@@ -12,68 +12,95 @@ use DateTime;
*/
class DateParser extends Base
{
+ const DATE_FORMAT = 'm/d/Y';
+ const DATE_TIME_FORMAT = 'm/d/Y H:i';
+
/**
- * Return true if the date is within the date range
+ * List of time formats
*
* @access public
- * @param DateTime $date
- * @param DateTime $start
- * @param DateTime $end
- * @return boolean
+ * @return string[]
*/
- public function withinDateRange(DateTime $date, DateTime $start, DateTime $end)
+ public function getTimeFormats()
{
- return $date >= $start && $date <= $end;
+ return array(
+ 'H:i',
+ 'g:i a',
+ );
}
/**
- * Get the total number of hours between 2 datetime objects
- * Minutes are rounded to the nearest quarter
+ * List of date formats
*
* @access public
- * @param DateTime $d1
- * @param DateTime $d2
- * @return float
+ * @param boolean $iso
+ * @return string[]
*/
- public function getHours(DateTime $d1, DateTime $d2)
+ public function getDateFormats($iso = false)
{
- $seconds = $this->getRoundedSeconds(abs($d1->getTimestamp() - $d2->getTimestamp()));
- return round($seconds / 3600, 2);
+ $iso_formats = array(
+ 'Y-m-d',
+ 'Y_m_d',
+ );
+
+ $user_formats = array(
+ 'm/d/Y',
+ 'd/m/Y',
+ 'Y/m/d',
+ 'd.m.Y',
+ );
+
+ return $iso ? array_merge($iso_formats, $user_formats) : $user_formats;
}
/**
- * Round the timestamp to the nearest quarter
+ * List of datetime formats
*
* @access public
- * @param integer $seconds Timestamp
- * @return integer
+ * @param boolean $iso
+ * @return string[]
*/
- public function getRoundedSeconds($seconds)
+ public function getDateTimeFormats($iso = false)
{
- return (int) round($seconds / (15 * 60)) * (15 * 60);
+ $formats = array();
+
+ foreach ($this->getDateFormats($iso) as $date) {
+ foreach ($this->getTimeFormats() as $time) {
+ $formats[] = $date.' '.$time;
+ }
+ }
+
+ return $formats;
}
/**
- * Return a timestamp if the given date format is correct otherwise return 0
+ * List of all date formats
*
* @access public
- * @param string $value Date to parse
- * @param string $format Date format
- * @return integer
+ * @param boolean $iso
+ * @return string[]
*/
- public function getValidDate($value, $format)
+ public function getAllDateFormats($iso = false)
{
- $date = DateTime::createFromFormat($format, $value);
+ return array_merge($this->getDateFormats($iso), $this->getDateTimeFormats($iso));
+ }
- if ($date !== false) {
- $errors = DateTime::getLastErrors();
- if ($errors['error_count'] === 0 && $errors['warning_count'] === 0) {
- $timestamp = $date->getTimestamp();
- return $timestamp > 0 ? $timestamp : 0;
- }
+ /**
+ * Get available formats (visible in settings)
+ *
+ * @access public
+ * @param array $formats
+ * @return array
+ */
+ public function getAvailableFormats(array $formats)
+ {
+ $values = array();
+
+ foreach ($formats as $format) {
+ $values[$format] = date($format);
}
- return 0;
+ return $values;
}
/**
@@ -85,7 +112,11 @@ class DateParser extends Base
*/
public function getTimestamp($value)
{
- foreach ($this->getAllFormats() as $format) {
+ if (ctype_digit($value)) {
+ return (int) $value;
+ }
+
+ foreach ($this->getAllDateFormats(true) as $format) {
$timestamp = $this->getValidDate($value, $format);
if ($timestamp !== 0) {
@@ -97,104 +128,103 @@ class DateParser extends Base
}
/**
- * Get ISO8601 date from user input
+ * Return a timestamp if the given date format is correct otherwise return 0
*
- * @access public
- * @param string $value Date to parse
- * @return string
+ * @access private
+ * @param string $value Date to parse
+ * @param string $format Date format
+ * @return integer
*/
- public function getIsoDate($value)
+ private function getValidDate($value, $format)
{
- return date('Y-m-d', ctype_digit($value) ? $value : $this->getTimestamp($value));
+ $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;
}
/**
- * Get all combinations of date/time formats
+ * Return true if the date is within the date range
*
* @access public
- * @return string[]
+ * @param DateTime $date
+ * @param DateTime $start
+ * @param DateTime $end
+ * @return boolean
*/
- public function getAllFormats()
+ public function withinDateRange(DateTime $date, DateTime $start, DateTime $end)
{
- $formats = array();
-
- foreach ($this->getDateFormats() as $date) {
- foreach ($this->getTimeFormats() as $time) {
- $formats[] = $date.' '.$time;
- }
- }
-
- return array_merge($formats, $this->getDateFormats());
+ return $date >= $start && $date <= $end;
}
/**
- * Return the list of supported date formats (for the parser)
+ * Get the total number of hours between 2 datetime objects
+ * Minutes are rounded to the nearest quarter
*
* @access public
- * @return string[]
+ * @param DateTime $d1
+ * @param DateTime $d2
+ * @return float
*/
- public function getDateFormats()
+ public function getHours(DateTime $d1, DateTime $d2)
{
- return array(
- $this->config->get('application_date_format', 'm/d/Y'),
- 'Y-m-d',
- 'Y_m_d',
- );
+ $seconds = $this->getRoundedSeconds(abs($d1->getTimestamp() - $d2->getTimestamp()));
+ return round($seconds / 3600, 2);
}
/**
- * Return the list of supported time formats (for the parser)
+ * Round the timestamp to the nearest quarter
*
* @access public
- * @return string[]
+ * @param integer $seconds Timestamp
+ * @return integer
*/
- public function getTimeFormats()
+ public function getRoundedSeconds($seconds)
{
- return array(
- 'H:i',
- 'g:i A',
- 'g:iA',
- );
+ return (int) round($seconds / (15 * 60)) * (15 * 60);
}
/**
- * Return the list of available date formats (for the config page)
+ * Get ISO-8601 date from user input
*
* @access public
- * @return array
+ * @param string $value Date to parse
+ * @return string
*/
- public function getAvailableFormats()
+ public function getIsoDate($value)
{
- return array(
- 'm/d/Y' => date('m/d/Y'),
- 'd/m/Y' => date('d/m/Y'),
- 'Y/m/d' => date('Y/m/d'),
- 'd.m.Y' => date('d.m.Y'),
- );
+ return date('Y-m-d', $this->getTimestamp($value));
}
/**
- * Remove the time from a timestamp
+ * Get a timestamp from an ISO date format
*
* @access public
- * @param integer $timestamp Timestamp
+ * @param string $value
* @return integer
*/
- public function removeTimeFromTimestamp($timestamp)
+ public function getTimestampFromIsoFormat($value)
{
- return mktime(0, 0, 0, date('m', $timestamp), date('d', $timestamp), date('Y', $timestamp));
+ return $this->removeTimeFromTimestamp(ctype_digit($value) ? $value : strtotime($value));
}
/**
- * Get a timetstamp from an ISO date format
+ * Remove the time from a timestamp
*
* @access public
- * @param string $date
+ * @param integer $timestamp
* @return integer
*/
- public function getTimestampFromIsoFormat($date)
+ public function removeTimeFromTimestamp($timestamp)
{
- return $this->removeTimeFromTimestamp(ctype_digit($date) ? $date : strtotime($date));
+ return mktime(0, 0, 0, date('m', $timestamp), date('d', $timestamp), date('Y', $timestamp));
}
/**
@@ -204,13 +234,10 @@ class DateParser extends Base
* @param array $values Database values
* @param string[] $fields Date fields
* @param string $format Date format
+ * @return array
*/
- public function format(array &$values, array $fields, $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]);
@@ -218,23 +245,28 @@ class DateParser extends Base
$values[$field] = '';
}
}
+
+ return $values;
}
/**
- * Convert date (form input data)
+ * Convert date to timestamp
*
* @access public
* @param array $values Database values
* @param string[] $fields Date fields
* @param boolean $keep_time Keep time or not
+ * @return array
*/
- public function convert(array &$values, array $fields, $keep_time = false)
+ public function convert(array $values, array $fields, $keep_time = false)
{
foreach ($fields as $field) {
- if (! empty($values[$field]) && ! is_numeric($values[$field])) {
+ if (! empty($values[$field])) {
$timestamp = $this->getTimestamp($values[$field]);
$values[$field] = $keep_time ? $timestamp : $this->removeTimeFromTimestamp($timestamp);
}
}
+
+ return $values;
}
}
diff --git a/app/Core/Event/EventManager.php b/app/Core/Event/EventManager.php
index 8d76bfcb..162d23e8 100644
--- a/app/Core/Event/EventManager.php
+++ b/app/Core/Event/EventManager.php
@@ -52,6 +52,7 @@ class EventManager
Task::EVENT_CLOSE => t('Closing a task'),
Task::EVENT_CREATE_UPDATE => t('Task creation or modification'),
Task::EVENT_ASSIGNEE_CHANGE => t('Task assignee change'),
+ Task::EVENT_DAILY_CRONJOB => t('Daily background job for tasks'),
);
$events = array_merge($events, $this->events);
diff --git a/app/Core/ExternalLink/ExternalLinkInterface.php b/app/Core/ExternalLink/ExternalLinkInterface.php
new file mode 100644
index 00000000..2dbc0a19
--- /dev/null
+++ b/app/Core/ExternalLink/ExternalLinkInterface.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace Kanboard\Core\ExternalLink;
+
+/**
+ * External Link Interface
+ *
+ * @package externalLink
+ * @author Frederic Guillot
+ */
+interface ExternalLinkInterface
+{
+ /**
+ * Get link title
+ *
+ * @access public
+ * @return string
+ */
+ public function getTitle();
+
+ /**
+ * Get link URL
+ *
+ * @access public
+ * @return string
+ */
+ public function getUrl();
+
+ /**
+ * Set link URL
+ *
+ * @access public
+ * @param string $url
+ */
+ public function setUrl($url);
+}
diff --git a/app/Core/ExternalLink/ExternalLinkManager.php b/app/Core/ExternalLink/ExternalLinkManager.php
new file mode 100644
index 00000000..1fa423c2
--- /dev/null
+++ b/app/Core/ExternalLink/ExternalLinkManager.php
@@ -0,0 +1,173 @@
+<?php
+
+namespace Kanboard\Core\ExternalLink;
+
+use Kanboard\Core\Base;
+
+/**
+ * External Link Manager
+ *
+ * @package externalLink
+ * @author Frederic Guillot
+ */
+class ExternalLinkManager extends Base
+{
+ /**
+ * Automatic type value
+ *
+ * @var string
+ */
+ const TYPE_AUTO = 'auto';
+
+ /**
+ * Registered providers
+ *
+ * @access private
+ * @var array
+ */
+ private $providers = array();
+
+ /**
+ * Type chosen by the user
+ *
+ * @access private
+ * @var string
+ */
+ private $userInputType = '';
+
+ /**
+ * Text entered by the user
+ *
+ * @access private
+ * @var string
+ */
+ private $userInputText = '';
+
+ /**
+ * Register a new provider
+ *
+ * Providers are registered in a LIFO queue
+ *
+ * @access public
+ * @param ExternalLinkProviderInterface $provider
+ * @return ExternalLinkManager
+ */
+ public function register(ExternalLinkProviderInterface $provider)
+ {
+ array_unshift($this->providers, $provider);
+ return $this;
+ }
+
+ /**
+ * Get provider
+ *
+ * @access public
+ * @param string $type
+ * @throws ExternalLinkProviderNotFound
+ * @return ExternalLinkProviderInterface
+ */
+ public function getProvider($type)
+ {
+ foreach ($this->providers as $provider) {
+ if ($provider->getType() === $type) {
+ return $provider;
+ }
+ }
+
+ throw new ExternalLinkProviderNotFound('Unable to find link provider: '.$type);
+ }
+
+ /**
+ * Get link types
+ *
+ * @access public
+ * @return array
+ */
+ public function getTypes()
+ {
+ $types = array();
+
+ foreach ($this->providers as $provider) {
+ $types[$provider->getType()] = $provider->getName();
+ }
+
+ asort($types);
+
+ return array(self::TYPE_AUTO => t('Auto')) + $types;
+ }
+
+ /**
+ * Get dependency label from a provider
+ *
+ * @access public
+ * @param string $type
+ * @param string $dependency
+ * @return string
+ */
+ public function getDependencyLabel($type, $dependency)
+ {
+ $provider = $this->getProvider($type);
+ $dependencies = $provider->getDependencies();
+ return isset($dependencies[$dependency]) ? $dependencies[$dependency] : $dependency;
+ }
+
+ /**
+ * Find a provider that match
+ *
+ * @access public
+ * @throws ExternalLinkProviderNotFound
+ * @return ExternalLinkProviderInterface
+ */
+ public function find()
+ {
+ if ($this->userInputType === self::TYPE_AUTO) {
+ $provider = $this->findProvider();
+ } else {
+ $provider = $this->getProvider($this->userInputType);
+ $provider->setUserTextInput($this->userInputText);
+
+ if (! $provider->match()) {
+ throw new ExternalLinkProviderNotFound('Unable to parse URL with selected provider');
+ }
+ }
+
+ if ($provider === null) {
+ throw new ExternalLinkProviderNotFound('Unable to find link information from provided information');
+ }
+
+ return $provider;
+ }
+
+ /**
+ * Set form values
+ *
+ * @access public
+ * @param array $values
+ * @return ExternalLinkManager
+ */
+ public function setUserInput(array $values)
+ {
+ $this->userInputType = empty($values['type']) ? self::TYPE_AUTO : $values['type'];
+ $this->userInputText = empty($values['text']) ? '' : trim($values['text']);
+ return $this;
+ }
+
+ /**
+ * Find a provider that user input
+ *
+ * @access private
+ * @return ExternalLinkProviderInterface
+ */
+ private function findProvider()
+ {
+ foreach ($this->providers as $provider) {
+ $provider->setUserTextInput($this->userInputText);
+
+ if ($provider->match()) {
+ return $provider;
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/app/Core/ExternalLink/ExternalLinkProviderInterface.php b/app/Core/ExternalLink/ExternalLinkProviderInterface.php
new file mode 100644
index 00000000..c908e1eb
--- /dev/null
+++ b/app/Core/ExternalLink/ExternalLinkProviderInterface.php
@@ -0,0 +1,71 @@
+<?php
+
+namespace Kanboard\Core\ExternalLink;
+
+/**
+ * External Link Provider Interface
+ *
+ * @package externalLink
+ * @author Frederic Guillot
+ */
+interface ExternalLinkProviderInterface
+{
+ /**
+ * Get provider name (label)
+ *
+ * @access public
+ * @return string
+ */
+ public function getName();
+
+ /**
+ * Get link type (will be saved in the database)
+ *
+ * @access public
+ * @return string
+ */
+ public function getType();
+
+ /**
+ * Get a dictionary of supported dependency types by the provider
+ *
+ * Example:
+ *
+ * [
+ * 'related' => t('Related'),
+ * 'child' => t('Child'),
+ * 'parent' => t('Parent'),
+ * 'self' => t('Self'),
+ * ]
+ *
+ * The dictionary key is saved in the database.
+ *
+ * @access public
+ * @return array
+ */
+ public function getDependencies();
+
+ /**
+ * Set text entered by the user
+ *
+ * @access public
+ * @param string $input
+ */
+ public function setUserTextInput($input);
+
+ /**
+ * Return true if the provider can parse correctly the user input
+ *
+ * @access public
+ * @return boolean
+ */
+ public function match();
+
+ /**
+ * Get the link found with the properties
+ *
+ * @access public
+ * @return ExternalLinkInterface
+ */
+ public function getLink();
+}
diff --git a/app/Core/ExternalLink/ExternalLinkProviderNotFound.php b/app/Core/ExternalLink/ExternalLinkProviderNotFound.php
new file mode 100644
index 00000000..4fd05202
--- /dev/null
+++ b/app/Core/ExternalLink/ExternalLinkProviderNotFound.php
@@ -0,0 +1,15 @@
+<?php
+
+namespace Kanboard\Core\ExternalLink;
+
+use Exception;
+
+/**
+ * External Link Provider Not Found Exception
+ *
+ * @package externalLink
+ * @author Frederic Guillot
+ */
+class ExternalLinkProviderNotFound extends Exception
+{
+}
diff --git a/app/Core/Helper.php b/app/Core/Helper.php
index 5edaa3f0..3764a67c 100644
--- a/app/Core/Helper.php
+++ b/app/Core/Helper.php
@@ -10,16 +10,18 @@ use Pimple\Container;
* @package core
* @author Frederic Guillot
*
- * @property \Helper\App $app
- * @property \Helper\Asset $asset
- * @property \Helper\Dt $dt
- * @property \Helper\File $file
- * @property \Helper\Form $form
- * @property \Helper\Subtask $subtask
- * @property \Helper\Task $task
- * @property \Helper\Text $text
- * @property \Helper\Url $url
- * @property \Helper\User $user
+ * @property \Kanboard\Helper\AppHelper $app
+ * @property \Kanboard\Helper\AssetHelper $asset
+ * @property \Kanboard\Helper\DateHelper $dt
+ * @property \Kanboard\Helper\FileHelper $file
+ * @property \Kanboard\Helper\FormHelper $form
+ * @property \Kanboard\Helper\ModelHelper $model
+ * @property \Kanboard\Helper\SubtaskHelper $subtask
+ * @property \Kanboard\Helper\TaskHelper $task
+ * @property \Kanboard\Helper\TextHelper $text
+ * @property \Kanboard\Helper\UrlHelper $url
+ * @property \Kanboard\Helper\UserHelper $user
+ * @property \Kanboard\Helper\LayoutHelper $layout
*/
class Helper
{
@@ -27,17 +29,17 @@ class Helper
* Helper instances
*
* @access private
- * @var array
+ * @var \Pimple\Container
*/
- private $helpers = array();
+ private $helpers;
/**
* Container instance
*
- * @access protected
+ * @access private
* @var \Pimple\Container
*/
- protected $container;
+ private $container;
/**
* Constructor
@@ -48,33 +50,49 @@ class Helper
public function __construct(Container $container)
{
$this->container = $container;
+ $this->helpers = new Container;
}
/**
- * Load automatically helpers
+ * Expose helpers with magic getter
*
* @access public
- * @param string $name Helper name
+ * @param string $helper
* @return mixed
*/
- public function __get($name)
+ public function __get($helper)
{
- if (! isset($this->helpers[$name])) {
- $class = '\Kanboard\Helper\\'.ucfirst($name);
- $this->helpers[$name] = new $class($this->container);
- }
+ return $this->getHelper($helper);
+ }
- return $this->helpers[$name];
+ /**
+ * Expose helpers with method
+ *
+ * @access public
+ * @param string $helper
+ * @return mixed
+ */
+ public function getHelper($helper)
+ {
+ return $this->helpers[$helper];
}
/**
- * HTML escaping
+ * Register a new Helper
*
- * @param string $value Value to escape
- * @return string
+ * @access public
+ * @param string $property
+ * @param string $className
+ * @return Helper
*/
- public function e($value)
+ public function register($property, $className)
{
- return htmlspecialchars($value, ENT_QUOTES, 'UTF-8', false);
+ $container = $this->container;
+
+ $this->helpers[$property] = function() use($className, $container) {
+ return new $className($container);
+ };
+
+ return $this;
}
}
diff --git a/app/Core/Http/Client.php b/app/Core/Http/Client.php
index c6bf36a6..12b0a1cb 100644
--- a/app/Core/Http/Client.php
+++ b/app/Core/Http/Client.php
@@ -34,6 +34,19 @@ class Client extends Base
const HTTP_USER_AGENT = 'Kanboard';
/**
+ * Send a GET HTTP request
+ *
+ * @access public
+ * @param string $url
+ * @param string[] $headers
+ * @return string
+ */
+ public function get($url, array $headers = array())
+ {
+ return $this->doRequest('GET', $url, '', $headers);
+ }
+
+ /**
* Send a GET HTTP request and parse JSON response
*
* @access public
diff --git a/app/Core/Http/Request.php b/app/Core/Http/Request.php
index 1b3036d5..e0df2d3c 100644
--- a/app/Core/Http/Request.php
+++ b/app/Core/Http/Request.php
@@ -29,7 +29,12 @@ class Request extends Base
* Constructor
*
* @access public
- * @param \Pimple\Container $container
+ * @param \Pimple\Container $container
+ * @param array $server
+ * @param array $get
+ * @param array $post
+ * @param array $files
+ * @param array $cookies
*/
public function __construct(Container $container, array $server = array(), array $get = array(), array $post = array(), array $files = array(), array $cookies = array())
{
@@ -211,7 +216,11 @@ class Request extends Base
*/
public function isHTTPS()
{
- return isset($this->server['HTTPS']) && $this->server['HTTPS'] !== '' && $this->server['HTTPS'] !== 'off';
+ if ($this->getServerVariable('HTTP_X_FORWARDED_PROTO') === 'https') {
+ return true;
+ }
+
+ return $this->getServerVariable('HTTPS') !== '' && $this->server['HTTPS'] !== 'off';
}
/**
diff --git a/app/Core/Http/Response.php b/app/Core/Http/Response.php
index 7fefddeb..d098f519 100644
--- a/app/Core/Http/Response.php
+++ b/app/Core/Http/Response.php
@@ -68,11 +68,12 @@ class Response extends Base
*
* @access public
* @param string $url Redirection URL
+ * @param boolean $self If Ajax request and true: refresh the current page
*/
- public function redirect($url)
+ public function redirect($url, $self = false)
{
- if ($this->request->getServerVariable('HTTP_X_REQUESTED_WITH') === 'XMLHttpRequest') {
- header('X-Ajax-Redirect: '.$url);
+ if ($this->request->isAjax()) {
+ header('X-Ajax-Redirect: '.($self ? 'self' : $url));
} else {
header('Location: '.$url);
}
diff --git a/app/Core/Ldap/Client.php b/app/Core/Ldap/Client.php
index 63149ae3..05658190 100644
--- a/app/Core/Ldap/Client.php
+++ b/app/Core/Ldap/Client.php
@@ -31,7 +31,7 @@ class Client
*/
public static function connect($username = null, $password = null)
{
- $client = new self;
+ $client = new static;
$client->open($client->getLdapServer());
$username = $username ?: $client->getLdapUsername();
$password = $password ?: $client->getLdapPassword();
@@ -60,6 +60,7 @@ class Client
* Establish server connection
*
* @access public
+ * @throws ClientException
* @param string $server LDAP server hostname or IP
* @param integer $port LDAP port
* @param boolean $tls Start TLS
@@ -98,6 +99,7 @@ class Client
* Anonymous authentication
*
* @access public
+ * @throws ClientException
* @return boolean
*/
public function useAnonymousAuthentication()
@@ -113,6 +115,7 @@ class Client
* Authentication with username/password
*
* @access public
+ * @throws ClientException
* @param string $bind_rdn
* @param string $bind_password
* @return boolean
diff --git a/app/Core/Ldap/Query.php b/app/Core/Ldap/Query.php
index e03495ec..1779fa61 100644
--- a/app/Core/Ldap/Query.php
+++ b/app/Core/Ldap/Query.php
@@ -78,7 +78,7 @@ class Query
* Get LDAP Entries
*
* @access public
- * @return Entities
+ * @return Entries
*/
public function getEntries()
{
diff --git a/app/Core/Mail/Client.php b/app/Core/Mail/Client.php
index e1f31696..641b6abe 100644
--- a/app/Core/Mail/Client.php
+++ b/app/Core/Mail/Client.php
@@ -41,7 +41,7 @@ class Client extends Base
* @param string $name
* @param string $subject
* @param string $html
- * @return EmailClient
+ * @return Client
*/
public function send($email, $name, $subject, $html)
{
@@ -70,7 +70,7 @@ class Client extends Base
*
* @access public
* @param string $transport
- * @return EmailClientInterface
+ * @return ClientInterface
*/
public function getTransport($transport)
{
@@ -83,7 +83,7 @@ class Client extends Base
* @access public
* @param string $transport
* @param string $class
- * @return EmailClient
+ * @return Client
*/
public function setTransport($transport, $class)
{
diff --git a/app/Core/ObjectStorage/FileStorage.php b/app/Core/ObjectStorage/FileStorage.php
index dd049ca2..18453890 100644
--- a/app/Core/ObjectStorage/FileStorage.php
+++ b/app/Core/ObjectStorage/FileStorage.php
@@ -33,6 +33,7 @@ class FileStorage implements ObjectStorageInterface
* Fetch object contents
*
* @access public
+ * @throws ObjectStorageException
* @param string $key
* @return string
*/
@@ -51,6 +52,7 @@ class FileStorage implements ObjectStorageInterface
* Save object
*
* @access public
+ * @throws ObjectStorageException
* @param string $key
* @param string $blob
*/
@@ -67,6 +69,7 @@ class FileStorage implements ObjectStorageInterface
* Output directly object content
*
* @access public
+ * @throws ObjectStorageException
* @param string $key
*/
public function output($key)
@@ -84,6 +87,7 @@ class FileStorage implements ObjectStorageInterface
* Move local file to object storage
*
* @access public
+ * @throws ObjectStorageException
* @param string $src_filename
* @param string $key
* @return boolean
@@ -136,6 +140,7 @@ class FileStorage implements ObjectStorageInterface
* Create object folder
*
* @access private
+ * @throws ObjectStorageException
* @param string $key
*/
private function createFolder($key)
diff --git a/app/Core/Plugin/Loader.php b/app/Core/Plugin/Loader.php
index 530d9b40..ff4f2c14 100644
--- a/app/Core/Plugin/Loader.php
+++ b/app/Core/Plugin/Loader.php
@@ -55,6 +55,7 @@ class Loader extends \Kanboard\Core\Base
* Load plugin
*
* @access public
+ * @throws LogicException
* @param string $plugin
*/
public function load($plugin)
diff --git a/app/Core/Security/AccessMap.php b/app/Core/Security/AccessMap.php
index f34c4b00..2431a921 100644
--- a/app/Core/Security/AccessMap.php
+++ b/app/Core/Security/AccessMap.php
@@ -39,7 +39,7 @@ class AccessMap
*
* @access public
* @param string $role
- * @return Acl
+ * @return AccessMap
*/
public function setDefaultRole($role)
{
@@ -53,7 +53,7 @@ class AccessMap
* @access public
* @param string $role
* @param array $subroles
- * @return Acl
+ * @return AccessMap
*/
public function setRoleHierarchy($role, array $subroles)
{
@@ -113,7 +113,7 @@ class AccessMap
* @param string $controller Controller class name
* @param mixed $methods List of method name or just one method
* @param string $role Lowest role required
- * @return Acl
+ * @return AccessMap
*/
public function add($controller, $methods, $role)
{
@@ -135,7 +135,7 @@ class AccessMap
* @param string $controller
* @param string $method
* @param string $role
- * @return Acl
+ * @return AccessMap
*/
private function addRule($controller, $method, $role)
{
@@ -157,7 +157,7 @@ class AccessMap
* @access public
* @param string $controller
* @param string $method
- * @return boolean
+ * @return array
*/
public function getRoles($controller, $method)
{
diff --git a/app/Core/Security/OAuthAuthenticationProviderInterface.php b/app/Core/Security/OAuthAuthenticationProviderInterface.php
index c32339e0..3092672d 100644
--- a/app/Core/Security/OAuthAuthenticationProviderInterface.php
+++ b/app/Core/Security/OAuthAuthenticationProviderInterface.php
@@ -14,7 +14,7 @@ interface OAuthAuthenticationProviderInterface extends AuthenticationProviderInt
* Get user object
*
* @access public
- * @return UserProviderInterface
+ * @return \Kanboard\Core\User\UserProviderInterface
*/
public function getUser();
@@ -31,7 +31,7 @@ interface OAuthAuthenticationProviderInterface extends AuthenticationProviderInt
* Get configured OAuth2 service
*
* @access public
- * @return Kanboard\Core\Http\OAuth2
+ * @return \Kanboard\Core\Http\OAuth2
*/
public function getService();
diff --git a/app/Core/Security/PasswordAuthenticationProviderInterface.php b/app/Core/Security/PasswordAuthenticationProviderInterface.php
index 918a4aec..c2304546 100644
--- a/app/Core/Security/PasswordAuthenticationProviderInterface.php
+++ b/app/Core/Security/PasswordAuthenticationProviderInterface.php
@@ -14,7 +14,7 @@ interface PasswordAuthenticationProviderInterface extends AuthenticationProvider
* Get user object
*
* @access public
- * @return UserProviderInterface
+ * @return \Kanboard\Core\User\UserProviderInterface
*/
public function getUser();
diff --git a/app/Core/Security/PreAuthenticationProviderInterface.php b/app/Core/Security/PreAuthenticationProviderInterface.php
index 391e8d0f..c13b06c5 100644
--- a/app/Core/Security/PreAuthenticationProviderInterface.php
+++ b/app/Core/Security/PreAuthenticationProviderInterface.php
@@ -14,7 +14,7 @@ interface PreAuthenticationProviderInterface extends AuthenticationProviderInter
* Get user object
*
* @access public
- * @return UserProviderInterface
+ * @return \Kanboard\Core\User\UserProviderInterface
*/
public function getUser();
}
diff --git a/app/Core/Template.php b/app/Core/Template.php
index 8ded6f7c..f85c7f28 100644
--- a/app/Core/Template.php
+++ b/app/Core/Template.php
@@ -3,63 +3,50 @@
namespace Kanboard\Core;
/**
- * Template class
+ * Template
*
* @package core
* @author Frederic Guillot
*/
-class Template extends Helper
+class Template
{
/**
- * List of template overrides
+ * Helper object
*
* @access private
- * @var array
+ * @var Helper
*/
- private $overrides = array();
+ private $helper;
/**
- * Rendering start time
- *
- * @access private
- * @var float
- */
- private $startTime = 0;
-
- /**
- * Total rendering time
+ * List of template overrides
*
* @access private
- * @var float
+ * @var array
*/
- private $renderingTime = 0;
+ private $overrides = array();
/**
- * Method executed before the rendering
+ * Template constructor
*
- * @access protected
- * @param string $template
+ * @access public
+ * @param Helper $helper
*/
- protected function beforeRender($template)
+ public function __construct(Helper $helper)
{
- if (DEBUG) {
- $this->startTime = microtime(true);
- }
+ $this->helper = $helper;
}
/**
- * Method executed after the rendering
+ * Expose helpers with magic getter
*
- * @access protected
- * @param string $template
+ * @access public
+ * @param string $helper
+ * @return mixed
*/
- protected function afterRender($template)
+ public function __get($helper)
{
- if (DEBUG) {
- $duration = microtime(true) - $this->startTime;
- $this->renderingTime += $duration;
- $this->container['logger']->debug('Rendering '.$template.' in '.$duration.'s, total='.$this->renderingTime);
- }
+ return $this->helper->getHelper($helper);
}
/**
@@ -76,33 +63,10 @@ class Template extends Helper
*/
public function render($__template_name, array $__template_args = array())
{
- $this->beforeRender($__template_name);
-
extract($__template_args);
ob_start();
include $this->getTemplateFile($__template_name);
- $html = ob_get_clean();
-
- $this->afterRender($__template_name);
-
- return $html;
- }
-
- /**
- * Render a page layout
- *
- * @access public
- * @param string $template_name Template name
- * @param array $template_args Key/value map
- * @param string $layout_name Layout name
- * @return string
- */
- public function layout($template_name, array $template_args = array(), $layout_name = 'layout')
- {
- return $this->render(
- $layout_name,
- $template_args + array('content_for_layout' => $this->render($template_name, $template_args))
- );
+ return ob_get_clean();
}
/**
diff --git a/app/Core/Translator.php b/app/Core/Translator.php
index 96a481f6..113c0dc6 100644
--- a/app/Core/Translator.php
+++ b/app/Core/Translator.php
@@ -147,32 +147,6 @@ class Translator
}
/**
- * Get a formatted datetime
- *
- * $translator->datetime('%Y-%m-%d', time());
- *
- * @access public
- * @param string $format Format defined by the strftime function
- * @param integer $timestamp Unix timestamp
- * @return string
- */
- public function datetime($format, $timestamp)
- {
- if (! $timestamp) {
- return '';
- }
-
- $format = $this->get($format, $format);
-
- if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
- $format = str_replace('%e', '%d', $format);
- $format = str_replace('%k', '%H', $format);
- }
-
- return strftime($format, (int) $timestamp);
- }
-
- /**
* Get an identifier from the translations or return the default
*
* @access public
@@ -199,8 +173,6 @@ class Translator
*/
public static function load($language, $path = self::PATH)
{
- setlocale(LC_TIME, $language.'.UTF-8', $language);
-
$filename = $path.DIRECTORY_SEPARATOR.$language.DIRECTORY_SEPARATOR.'translations.php';
if (file_exists($filename)) {
diff --git a/app/Core/User/UserProfile.php b/app/Core/User/UserProfile.php
index ccbc7f06..ef325801 100644
--- a/app/Core/User/UserProfile.php
+++ b/app/Core/User/UserProfile.php
@@ -52,7 +52,7 @@ class UserProfile extends Base
$this->groupSync->synchronize($profile['id'], $user->getExternalGroupIds());
}
- if (! empty($profile)) {
+ if (! empty($profile) && $profile['is_active'] == 1) {
$this->userSession->initialize($profile);
return true;
}