diff options
Diffstat (limited to 'app/Core')
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; } |