diff options
Diffstat (limited to 'app/Core')
-rw-r--r-- | app/Core/HttpClient.php | 21 | ||||
-rw-r--r-- | app/Core/Lexer.php | 2 | ||||
-rw-r--r-- | app/Core/OAuth2.php | 120 | ||||
-rw-r--r-- | app/Core/Request.php | 11 | ||||
-rw-r--r-- | app/Core/Router.php | 195 | ||||
-rw-r--r-- | app/Core/Session.php | 2 |
6 files changed, 304 insertions, 47 deletions
diff --git a/app/Core/HttpClient.php b/app/Core/HttpClient.php index 805c1e5a..b808f756 100644 --- a/app/Core/HttpClient.php +++ b/app/Core/HttpClient.php @@ -32,6 +32,20 @@ class HttpClient extends Base const HTTP_USER_AGENT = 'Kanboard'; /** + * Send a GET HTTP request and parse JSON response + * + * @access public + * @param string $url + * @param string[] $headers + * @return array + */ + public function getJson($url, array $headers = array()) + { + $response = $this->doRequest('GET', $url, '', array_merge(array('Accept: application/json'), $headers)); + return json_decode($response, true) ?: array(); + } + + /** * Send a POST HTTP request encoded in JSON * * @access public @@ -43,6 +57,7 @@ class HttpClient extends Base public function postJson($url, array $data, array $headers = array()) { return $this->doRequest( + 'POST', $url, json_encode($data), array_merge(array('Content-type: application/json'), $headers) @@ -61,6 +76,7 @@ class HttpClient extends Base public function postForm($url, array $data, array $headers = array()) { return $this->doRequest( + 'POST', $url, http_build_query($data), array_merge(array('Content-type: application/x-www-form-urlencoded'), $headers) @@ -71,12 +87,13 @@ class HttpClient extends Base * Make the HTTP request * * @access private + * @param string $method * @param string $url * @param string $content * @param string[] $headers * @return string */ - private function doRequest($url, $content, array $headers) + private function doRequest($method, $url, $content, array $headers) { if (empty($url)) { return ''; @@ -86,7 +103,7 @@ class HttpClient extends Base $context = stream_context_create(array( 'http' => array( - 'method' => 'POST', + 'method' => $method, 'protocol_version' => 1.1, 'timeout' => self::HTTP_TIMEOUT, 'max_redirects' => self::HTTP_MAX_REDIRECTS, diff --git a/app/Core/Lexer.php b/app/Core/Lexer.php index 3887dc82..0a237254 100644 --- a/app/Core/Lexer.php +++ b/app/Core/Lexer.php @@ -33,6 +33,7 @@ class Lexer "/^(category:)/" => 'T_CATEGORY', "/^(column:)/" => 'T_COLUMN', "/^(project:)/" => 'T_PROJECT', + "/^(swimlane:)/" => 'T_SWIMLANE', "/^(ref:)/" => 'T_REFERENCE', "/^(reference:)/" => 'T_REFERENCE', "/^(\s+)/" => 'T_WHITESPACE', @@ -116,6 +117,7 @@ class Lexer case 'T_CATEGORY': case 'T_COLUMN': case 'T_PROJECT': + case 'T_SWIMLANE': $next = next($tokens); if ($next !== false && $next['token'] === 'T_STRING') { diff --git a/app/Core/OAuth2.php b/app/Core/OAuth2.php new file mode 100644 index 00000000..a7d04f33 --- /dev/null +++ b/app/Core/OAuth2.php @@ -0,0 +1,120 @@ +<?php + +namespace Core; + +/** + * OAuth2 client + * + * @package core + * @author Frederic Guillot + */ +class OAuth2 extends Base +{ + private $clientId; + private $secret; + private $callbackUrl; + private $authUrl; + private $tokenUrl; + private $scopes; + private $tokenType; + private $accessToken; + + /** + * Create OAuth2 service + * + * @access public + * @param string $clientId + * @param string $secret + * @param string $callbackUrl + * @param string $authUrl + * @param string $tokenUrl + * @param array $scopes + * @return OAuth2 + */ + public function createService($clientId, $secret, $callbackUrl, $authUrl, $tokenUrl, array $scopes) + { + $this->clientId = $clientId; + $this->secret = $secret; + $this->callbackUrl = $callbackUrl; + $this->authUrl = $authUrl; + $this->tokenUrl = $tokenUrl; + $this->scopes = $scopes; + + return $this; + } + + /** + * Get authorization url + * + * @access public + * @return string + */ + public function getAuthorizationUrl() + { + $params = array( + 'response_type' => 'code', + 'client_id' => $this->clientId, + 'redirect_uri' => $this->callbackUrl, + 'scope' => implode(' ', $this->scopes), + ); + + return $this->authUrl.'?'.http_build_query($params); + } + + /** + * Get authorization header + * + * @access public + * @return string + */ + public function getAuthorizationHeader() + { + if (strtolower($this->tokenType) === 'bearer') { + return 'Authorization: Bearer '.$this->accessToken; + } + + return ''; + } + + /** + * Get access token + * + * @access public + * @param string $code + * @return string + */ + public function getAccessToken($code) + { + if (empty($this->accessToken) && ! empty($code)) { + + $params = array( + 'code' => $code, + 'client_id' => $this->clientId, + 'client_secret' => $this->secret, + 'redirect_uri' => $this->callbackUrl, + 'grant_type' => 'authorization_code', + ); + + $response = json_decode($this->httpClient->postForm($this->tokenUrl, $params, array('Accept: application/json')), true); + + $this->tokenType = isset($response['token_type']) ? $response['token_type'] : ''; + $this->accessToken = isset($response['access_token']) ? $response['access_token'] : ''; + } + + return $this->accessToken; + } + + /** + * Set access token + * + * @access public + * @param string $token + * @param string $type + * @return string + */ + public function setAccessToken($token, $type = 'bearer') + { + $this->accessToken = $token; + $this->tokenType = $type; + } +} diff --git a/app/Core/Request.php b/app/Core/Request.php index b399a1f0..1eff66fa 100644 --- a/app/Core/Request.php +++ b/app/Core/Request.php @@ -163,6 +163,17 @@ class Request } /** + * Returns uri + * + * @access public + * @return string + */ + public function getUri() + { + return isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : ''; + } + + /** * Get the user agent * * @static diff --git a/app/Core/Router.php b/app/Core/Router.php index 36c11a0a..ae989de5 100644 --- a/app/Core/Router.php +++ b/app/Core/Router.php @@ -2,53 +2,151 @@ namespace Core; -use Pimple\Container; - /** * Router class * * @package core * @author Frederic Guillot */ -class Router +class Router extends Base { /** - * Controller name + * Store routes for path lookup * * @access private - * @var string + * @var array */ - private $controller = ''; + private $paths = array(); /** - * Action name + * Store routes for url lookup * * @access private - * @var string + * @var array */ - private $action = ''; + private $urls = array(); /** - * Container instance + * Get the path to compare patterns * - * @access private - * @var \Pimple\Container + * @access public + * @param string $uri + * @param string $query_string + * @return string */ - private $container; + public function getPath($uri, $query_string = '') + { + $path = substr($uri, strlen($this->helper->url->dir())); + + if (! empty($query_string)) { + $path = substr($path, 0, - strlen($query_string) - 1); + } + + if ($path{0} === '/') { + $path = substr($path, 1); + } + + return $path; + } + + /** + * Add route + * + * @access public + * @param string $path + * @param string $controller + * @param string $action + * @param array $params + */ + public function addRoute($path, $controller, $action, array $params = array()) + { + $pattern = explode('/', $path); + + $this->paths[] = array( + 'pattern' => $pattern, + 'count' => count($pattern), + 'controller' => $controller, + 'action' => $action, + ); + + $this->urls[$controller][$action][] = array( + 'path' => $path, + 'params' => array_flip($params), + 'count' => count($params), + ); + } + + /** + * Find a route according to the given path + * + * @access public + * @param string $path + * @return array + */ + public function findRoute($path) + { + $parts = explode('/', $path); + $count = count($parts); + + foreach ($this->paths as $route) { + + if ($count === $route['count']) { + + $params = array(); + + for ($i = 0; $i < $count; $i++) { + + if ($route['pattern'][$i]{0} === ':') { + $params[substr($route['pattern'][$i], 1)] = $parts[$i]; + } + else if ($route['pattern'][$i] !== $parts[$i]) { + break; + } + } + + if ($i === $count) { + $_GET = array_merge($_GET, $params); + return array($route['controller'], $route['action']); + } + } + } + + return array('app', 'index'); + } /** - * Constructor + * Find route url * * @access public - * @param \Pimple\Container $container Container instance - * @param string $controller Controller name - * @param string $action Action name + * @param string $controller + * @param string $action + * @param array $params + * @return string */ - public function __construct(Container $container, $controller = '', $action = '') + public function findUrl($controller, $action, array $params = array()) { - $this->container = $container; - $this->controller = empty($_GET['controller']) ? $controller : $_GET['controller']; - $this->action = empty($_GET['action']) ? $action : $_GET['action']; + if (! isset($this->urls[$controller][$action])) { + return ''; + } + + foreach ($this->urls[$controller][$action] as $pattern) { + + if (array_diff_key($params, $pattern['params']) === array()) { + $url = $pattern['path']; + $i = 0; + + foreach ($params as $variable => $value) { + $url = str_replace(':'.$variable, $value, $url); + $i++; + } + + if ($i === $pattern['count']) { + return $url; + } + } + } + + return ''; } /** @@ -65,15 +163,42 @@ class Router } /** - * Load a controller and execute the action + * Find controller/action from the route table or from get arguments * * @access public - * @param string $filename Controller filename - * @param string $class Class name - * @param string $method Method name + * @param string $uri + * @param string $query_string + * @return boolean + */ + public function dispatch($uri, $query_string = '') + { + if (! empty($_GET['controller']) && ! empty($_GET['action'])) { + $controller = $this->sanitize($_GET['controller'], 'app'); + $action = $this->sanitize($_GET['action'], 'index'); + } + else { + list($controller, $action) = $this->findRoute($this->getPath($uri, $query_string)); + } + + return $this->load( + __DIR__.'/../Controller/'.ucfirst($controller).'.php', + $controller, + '\Controller\\'.ucfirst($controller), + $action + ); + } + + /** + * Load a controller and execute the action + * + * @access private + * @param string $filename + * @param string $controller + * @param string $class + * @param string $method * @return bool */ - public function load($filename, $class, $method) + private function load($filename, $controller, $class, $method) { if (file_exists($filename)) { @@ -84,7 +209,7 @@ class Router } $instance = new $class($this->container); - $instance->beforeAction($this->controller, $this->action); + $instance->beforeAction($controller, $method); $instance->$method(); return true; @@ -92,20 +217,4 @@ class Router return false; } - - /** - * Find a route - * - * @access public - */ - public function execute() - { - $this->controller = $this->sanitize($this->controller, 'app'); - $this->action = $this->sanitize($this->action, 'index'); - $filename = __DIR__.'/../Controller/'.ucfirst($this->controller).'.php'; - - if (! $this->load($filename, '\Controller\\'.$this->controller, $this->action)) { - die('Page not found!'); - } - } } diff --git a/app/Core/Session.php b/app/Core/Session.php index c35014cd..0e5f7426 100644 --- a/app/Core/Session.php +++ b/app/Core/Session.php @@ -41,8 +41,6 @@ class Session implements ArrayAccess */ public function open($base_path = '/') { - $base_path = str_replace('\\', '/', $base_path); - // HttpOnly and secure flags for session cookie session_set_cookie_params( self::SESSION_LIFETIME, |