diff --git a/application/Espo/Core/Acl.php b/application/Espo/Core/Acl.php new file mode 100644 index 0000000000..53d488fc0e --- /dev/null +++ b/application/Espo/Core/Acl.php @@ -0,0 +1,22 @@ +user = $user; + + } + + public function check($subject, $action) + { + + } + + +} diff --git a/application/Espo/Core/Application.php b/application/Espo/Core/Application.php index 330ee1dc91..8d48ce164e 100644 --- a/application/Espo/Core/Application.php +++ b/application/Espo/Core/Application.php @@ -54,7 +54,7 @@ class Application public function run($name = 'default') { $this->routeHooks(); - $this->routes(); + $this->initRoutes(); $this->getSlim()->run(); } @@ -63,11 +63,11 @@ class Application $container = $this->getContainer(); $slim = $this->getSlim(); $serviceFactory = $this->getServiceFactory(); + - //check user credentials - $this->getSlim()->add(new \Espo\Core\Utils\Api\Auth($container)); + $auth = new \Espo\Core\Utils\Api\Auth($container->get('entityManager'), $container); + $this->getSlim()->add($auth); - //convert all url params to camel case format $this->getSlim()->hook('slim.before.dispatch', function () use ($slim, $container) { $conditions = $slim->router()->getCurrentRoute()->getConditions(); @@ -87,7 +87,6 @@ class Application $slim->router()->getCurrentRoute()->setParams($routeParams); } }); - //END: convert all url params to camel case format $this->getSlim()->hook('slim.before.dispatch', function () use ($slim, $container, $serviceFactory) { @@ -102,7 +101,7 @@ class Application $routeKeys = is_array($routeOptions) ? array_keys($routeOptions) : array(); if (!in_array('controller', $routeKeys, true)) { - return $container->get('rest')->render($routeOptions); + return $container->get('output')->render($routeOptions); } $params = $route->getParams(); @@ -116,8 +115,7 @@ class Application $controllerParams[$key] = $value; } - $controllerName = ucfirst($controllerParams['controller']); - + $controllerName = ucfirst($controllerParams['controller']); if (!empty($controllerParams['action'])) { $actionName = $controllerParams['action']; @@ -142,7 +140,7 @@ class Application } - protected function routes() + protected function initRoutes() { //$this->getSlim()->get('/', '\Espo\Utils\Api\Rest::main')->conditions( array('useController' => false) ); diff --git a/application/Espo/Core/Container.php b/application/Espo/Core/Container.php index 58d6f16a82..0cd6d10635 100644 --- a/application/Espo/Core/Container.php +++ b/application/Espo/Core/Container.php @@ -140,13 +140,18 @@ class Container ) ); } - - private function loadUser() + + public function setUser($user) + { + $this->data['user'] = $user; + } + + /*private function loadUser() { $this->data['user'] = new \Espo\Core\Utils\User( $this->get('entityManager'), $this->get('config') ); - } + }*/ } diff --git a/application/Espo/Core/Controllers/Base.php b/application/Espo/Core/Controllers/Base.php index a5b905cffb..811920d305 100644 --- a/application/Espo/Core/Controllers/Base.php +++ b/application/Espo/Core/Controllers/Base.php @@ -2,15 +2,40 @@ namespace Espo\Core\Controllers; -class Base -{ - private $container; - private $serviceFactory; +use \Espo\Core\Container; +use \Espo\Core\ServiceFactory; - public function __construct(\Espo\Core\Container $container, \Espo\Core\ServiceFactory $serviceFactory) +abstract class Base +{ + protected $name; + + private $container; + + private $serviceFactory; + + private $serviceClassName = null; + + private $service = null; + + public function __construct(Container $container, ServiceFactory $serviceFactory) { $this->container = $container; $this->serviceFactory = $serviceFactory; + + $name = get_class($this); + if (preg_match('@\\\\([\w]+)$@', $name, $matches)) { + $name = $matches[1]; + } + $this->name = $name; + + if (empty($this->serviceClassName)) { + $moduleName = $this->getMetadata()->getScopeModuleName($this->name); + if ($moduleName) { + $className = '\\Espo\\Modules\\' . $moduleName . '\\Services\\' . $this->name; + } else { + $className = '\\Espo\\Services\\' . $this->name; + } + } } protected function getContainer() @@ -23,6 +48,11 @@ class Base return $this->container->get('user'); } + protected function getAcl() + { + return $this->container->get('acl'); + } + protected function getConfig() { return $this->container->get('config'); @@ -37,5 +67,15 @@ class Base { return $this->serviceFactory; } + + protected function getService() + { + if (!empty($this->service)) { + return $this->service; + } + $this->service = $this->getServiceFactory()->createByClassName($this->serviceClassName); + return $this->service; + + } } diff --git a/application/Espo/Core/Controllers/Record.php b/application/Espo/Core/Controllers/Record.php new file mode 100644 index 0000000000..1513361476 --- /dev/null +++ b/application/Espo/Core/Controllers/Record.php @@ -0,0 +1,180 @@ +getService(); + $entity = $service->getEntity($id); + + if (!$this->getAcl()->check($entity, 'read')) { + throw new Forbidden(); + } + + return $entity; + } + + protected function actionUpdate($params, $data) + { + $id = $params['id']; + $service = $this->getService(); + $entity = $service->getEntity($id); + + if (!$this->getAcl()->check($entity, 'edit')) { + throw new Forbidden(); + } + + if ($service->updateEntity($entity, $data)) { + return $entity; + } + + throw new Error(); + } + + protected function actionPost($params, $data) + { + if (!$this->getAcl()->check($this->name, 'edit')) { + throw new Forbidden(); + } + + $service = $this->getService(); + + if ($entity = $service->postEntity($data)) { + return $entity; + } + + throw new Error(); + } + + protected function actionList($params, $where) + { + if (!$this->getAcl()->check($this->name, 'read')) { + throw new Forbidden(); + } + $service = $this->getService(); + + $where = $data['where']; + $offset = $data['offset']; + $limit = $data['limit']; + $asc = $data['asc']; + $sortBy = $data['sortBy']; + + $entityList = $service->findEntities({ + 'where' => $where, + 'offset' => $offset, + 'limit' => $limit, + 'asc' => $asc, + 'sortBy' => $sortBy, + }); + + return $entityList; + } + + protected function actionDelete($params) + { + $id = $params['id']; + + $service = $this->getService(); + $entity = $service->getEntity($id); + + if (!$this->getAcl()->check($entity, 'delete')) { + throw new Forbidden(); + } + + if ($service->deleteEntity($entity)) { + return true; + } + throw new Error(); + } + + protected function actionMassUpdate($params, $data) + { + if (!$this->getAcl()->check($this->name, 'edit')) { + throw new Forbidden(); + } + $service = $this->getService(); + + $ids = $data['ids']; + $where = $data['where']; + + $idsUpdated = $service->massUpdate($ids, $where); + + return $idsUpdated; + } + + protected function actionMassDelete($params, $data) + { + if (!$this->getAcl()->check($this->name, 'delete')) { + throw new Forbidden(); + } + $service = $this->getService(); + + $ids = $data['ids']; + $where = $data['where']; + + $idsDeleted = $service->massDelete($ids, $where); + + return $idsDeleted; + } + + protected function actionListLinked($params, $data) + { + $id = $params['id']; + $link = $params['link']; + + $service = $this->getService(); + $entity = $service->getEntity($id); + $foreignEntityName = $entity->defs['links'][$link]['entity']; + + if (!$this->getAcl()->check($entity, 'read')) { + throw new Forbidden(); + } + if (!$this->getAcl()->check($foreignEntityName, 'read')) { + throw new Forbidden(); + } + + $where = $data['where']; + $offset = $data['offset']; + $limit = $data['limit']; + $asc = $data['asc']; + $sortBy = $data['sortBy']; + + $entityList = $service->findLinkedEntities($entity, $link, { + 'where' => $where, + 'offset' => $offset, + 'limit' => $limit, + 'asc' => $asc, + 'sortBy' => $sortBy, + }); + + return $entityList; + } + + protected function actionCreateLink($params) + { + $id = $params['id']; + $link = $params['link']; + $foreignId = $params['foreignId']; + + $service = $this->getService(); + $entity = $service->getEntity($id); + $foreignEntityName = $entity->defs['links'][$link]['entity']; + + if (!$this->getAcl()->check($entity, 'edit')) { + throw new Forbidden(); + } + + if ($service->linkEntity($entity, $link, $foreignId)) { + return true; + } + + throw new Error(); + } +} diff --git a/application/Espo/Core/ServiceFactory.php b/application/Espo/Core/ServiceFactory.php index 5d7ac6c7df..b9f44fec0e 100644 --- a/application/Espo/Core/ServiceFactory.php +++ b/application/Espo/Core/ServiceFactory.php @@ -2,9 +2,11 @@ namespace Espo\Core; +use \Espo\Core\Exceptions\Error; + class ServiceFactory { - + private $container; private $metadata; @@ -12,14 +14,8 @@ class ServiceFactory public function __construct(Container $container) { $this->container = $container; - $this->metadata = $this->container->get('metadata'); } - protected function getCotainer() - { - return $this->container; - } - public function createByClassName() { if (class_exists($className)) { @@ -31,20 +27,7 @@ class ServiceFactory } return $service; } - // TODO throw an exception - return null; + throw new Error("Class '$className' does not exist"); } - - public function create($name) - { - $moduleName = $this->metadata->getScopeModuleName($name); - if ($moduleName) { - $className = '\\Espo\\Modules\\' . $moduleName . '\\Services\\' . $name; - } else { - $className = '\\Espo\\Services\\' . $name; - } - return $this->createByClassName($className); - } - } diff --git a/application/Espo/Core/Utils/Api/Auth.php b/application/Espo/Core/Utils/Api/Auth.php index cdc46f5780..c37548665a 100644 --- a/application/Espo/Core/Utils/Api/Auth.php +++ b/application/Espo/Core/Utils/Api/Auth.php @@ -6,23 +6,18 @@ use \Slim\Slim; class Auth extends \Slim\Middleware { + private $entityManager; + private $container; protected $realm = 'Protected Area'; - - public function __construct(\Espo\Core\Container $container) + public function __construct(\Doctrine\ORM\EntityManager $entityManager, \Espo\Core\Container $container) { + $this->entityManager = $entityManager; $this->container = $container; } - protected function getContainer() - { - return $this->container; - } - - - function call() { $req = $this->app->request(); @@ -34,11 +29,11 @@ class Auth extends \Slim\Middleware /** * Check if user credentials are required for current route */ - $routes= $this->app->router()->getMatchedRoutes($httpMethod, $uri); + $routes = $this->app->router()->getMatchedRoutes($httpMethod, $uri); if (!empty($routes[0])) { $routeConditions = $routes[0]->getConditions(); - if (isset($routeConditions['auth']) && $routeConditions['auth']===false) { + if (isset($routeConditions['auth']) && $routeConditions['auth'] === false) { $this->next->call(); return; } @@ -49,20 +44,28 @@ class Auth extends \Slim\Middleware if ($authKey && $authSec) { - $isAuthenticated = $this->getContainer()->get('user')->authenticate($authKey, $authSec); + $isAuthenticated = false; + + $username = $authKey; + $password = $authSec; - if($isAuthenticated){ + $user = $this->entityManager->getRepository('\Espo\Entities\User')->findOneBy(array('username' => $username)); + if ($user) { + if ($password == $user->getPassword()) { + $this->container->setUser($user); + $isAuthenticated = true; + } + } + + if ($isAuthenticated) { $this->next->call(); - }else{ - $res->header('WWW-Authenticate', sprintf('Basic realm="%s"', $this->realm)); - $res->status(401); + } else { + $res->header('WWW-Authenticate', sprintf('Basic realm="%s"', $this->realm)); + $res->status(401); } } else { $res->header('WWW-Authenticate', sprintf('Basic realm="%s"', $this->realm)); $res->status(401); } - } } - -?> \ No newline at end of file diff --git a/application/Espo/Core/Utils/Metadata.php b/application/Espo/Core/Utils/Metadata.php index 8acd612011..d3bf295d1a 100644 --- a/application/Espo/Core/Utils/Metadata.php +++ b/application/Espo/Core/Utils/Metadata.php @@ -27,7 +27,6 @@ class Metadata $this->doctrineConverter = new \Espo\Core\Doctrine\EspoConverter($entityManager, $this); } - protected function getEntityManager() { return $this->entityManager; diff --git a/application/Espo/Core/Utils/User.php b/application/Espo/Core/Utils/User.php deleted file mode 100644 index 76ebf81982..0000000000 --- a/application/Espo/Core/Utils/User.php +++ /dev/null @@ -1,75 +0,0 @@ -entityManager = $entityManager; - $this->config = $config; - } - - protected function getEntityManager() - { - return $this->entityManager; - } - - protected function getConfig() - { - return $this->config; - } - - public function getCurrentUser() - { - return $this->currentUser; - } - - - protected function setCurrentUser(\Espo\Entities\User $user) - { - $this->currentUser = $user; - } - - - - public function authenticate($username, $password) - { - $user = $this->getEntityManager()->getRepository('\Espo\Entities\User')->findOneBy(array('username' => $username)); - - if ( $password == $user->getPassword() ) { - $this->setCurrentUser($user); - return true; - } - - return false; - } - - - public function isAdmin(\Espo\Entities\User $user = null) - { - if (is_null($user)) { - $user = $this->getCurrentUser(); - } - - if ($user instanceof \Espo\Entities\User) { - $id = $user->getId(); - if ( !empty($id) ) { - return $user->getIsAdmin(); - } - } - - return false; - } - - - -} - - -?> \ No newline at end of file diff --git a/application/Espo/Entities/User.php b/application/Espo/Entities/User.php index 068dec4f5c..120bb73082 100644 --- a/application/Espo/Entities/User.php +++ b/application/Espo/Entities/User.php @@ -18,13 +18,13 @@ class User * @var string */ protected $username; + protected $password; + protected $isAdmin; public function __construct() { - //$this->reportedBugs = new ArrayCollection(); - //$this->assignedBugs = new ArrayCollection(); } public function getId() @@ -42,7 +42,7 @@ class User return $this->password; } - public function getIsAdmin() + public function isAdmin() { return $this->isAdmin; } @@ -51,5 +51,5 @@ class User { $this->name = $name; } - + }