portal development

This commit is contained in:
yuri
2016-01-04 16:14:18 +02:00
parent 18423c0ba1
commit ef9c5da2d6
31 changed files with 842 additions and 136 deletions

12
api/v1/portal/.htaccess Executable file
View File

@@ -0,0 +1,12 @@
RewriteEngine On
# Some hosts may require you to use the `RewriteBase` directive.
# If you need to use the `RewriteBase` directive, it should be the
# absolute physical path to the directory that contains this htaccess file.
#
# RewriteBase /
RewriteRule .* - [E=HTTP_ESPO_CGI_AUTH:%{HTTP:Authorization}]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]

38
api/v1/portal/index.php Normal file
View File

@@ -0,0 +1,38 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2015 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
require_once('../../../bootstrap.php');
//print_r($_SERVER);
//die;
$portalId = '567d4a0503c88c061';
$app = new \Espo\Core\ApplicationPortal($portalId);
$app->run();

15
api/v1/portal/web.config Executable file
View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="rule 1G" stopProcessing="true">
<match url="^" />
<action type="Rewrite" url="index.php" appendQueryString="true" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>

View File

@@ -0,0 +1,71 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2015 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\AclPortal;
use \Espo\Entities\User;
use \Espo\ORM\Entity;
class Email extends \Espo\Core\Acl\Base
{
public function checkEntityRead(User $user, Entity $entity, $data)
{
if ($this->checkEntity($user, $entity, $data, 'read')) {
return true;
}
if ($data === false) {
return false;
}
if (is_object($data)) {
if ($data->read === false || $data->read === 'no') {
return false;
}
}
if (!$entity->has('usersIds')) {
$entity->loadLinkMultipleField('users');
}
$userIdList = $entity->get('usersIds');
if (is_array($userIdList) && in_array($user->id, $userIdList)) {
return true;
}
return false;
}
public function checkIsOwner(User $user, Entity $entity)
{
if ($user->id === $entity->get('createdById')) {
return true;
}
return false;
}
}

View File

@@ -114,6 +114,11 @@ class Table
$this->cacheFilePath = 'data/cache/application/acl/' . $this->user->id . '.php';
}
protected function getUser()
{
return $this->user;
}
protected function getMetadata()
{
return $this->metadata;
@@ -171,18 +176,15 @@ class Table
private function load()
{
$aclTableList = [];
$fieldTableList = [];
$valuePermissionLists = (object)[];
foreach ($this->valuePermissionList as $permission) {
$valuePermissionLists->$permission = [];
}
if (!$this->user->isAdmin()) {
$userRoles = $this->user->get('roles');
$roleList = $this->getRoleList();
foreach ($userRoles as $role) {
foreach ($roleList as $role) {
$aclTableList[] = $role->get('data');
$fieldTableList[] = $role->get('fieldData');
foreach ($this->valuePermissionList as $permission) {
@@ -190,18 +192,6 @@ class Table
}
}
$teams = $this->user->get('teams');
foreach ($teams as $team) {
$teamRoles = $team->get('roles');
foreach ($teamRoles as $role) {
$aclTableList[] = $role->get('data');
$fieldTableList[] = $role->get('fieldData');
foreach ($this->valuePermissionList as $permission) {
$valuePermissionLists->{$permission}[] = $role->get($permission);
}
}
}
$aclTable = $this->mergeTableList($aclTableList);
$fieldTable = $this->mergeFieldTableList($fieldTableList);
@@ -211,7 +201,7 @@ class Table
} else {
$aclTable = (object) [];
foreach ($this->getScopeList() as $scope) {
if ($this->metadata->get("scopes.{$scope}.acl") === 'boolean') {
if ($this->metadata->get("scopes.{$scope}.{$this->type}") === 'boolean') {
$aclTable->$scope = true;
} else {
if ($this->metadata->get("scopes.{$scope}.entity")) {
@@ -240,9 +230,9 @@ class Table
if (!$this->user->isAdmin()) {
foreach ($this->valuePermissionList as $permission) {
$this->data->$permission = $this->mergeValueList($valuePermissionLists->$permission, $this->metadata->get('app.acl.default.' . $permission, 'all'));
if ($this->metadata->get('app.acl.mandatory.' . $permission)) {
$this->data->$permission = $this->metadata->get('app.acl.mandatory.' . $permission);
$this->data->$permission = $this->mergeValueList($valuePermissionLists->$permission, $this->metadata->get('app.'.$this->type.'.default.' . $permission, 'all'));
if ($this->metadata->get('app.'.$this->type.'.mandatory.' . $permission)) {
$this->data->$permission = $this->metadata->get('app.'.$this->type.'.mandatory.' . $permission);
}
}
@@ -253,6 +243,26 @@ class Table
}
}
protected function getRoleList()
{
$roleList = [];
$userRoleList = $this->getUser()->get('roles');
foreach ($userRoleList as $role) {
$roleList[] = $role;
}
$teamList = $this->getUser()->get('teams');
foreach ($teamList as $team) {
$teamRoleList = $team->get('roles');
foreach ($teamRoleList as $role) {
$roleList[] = $role;
}
}
return $roleList;
}
public function getScopeForbiddenAttributeList($scope, $action = 'read', $thresholdLevel = 'no')
{
$key = $scope . '_'. $action . '_' . $thresholdLevel;
@@ -372,7 +382,7 @@ class Table
return;
}
$data = $this->metadata->get('app.acl.default.scopeLevel', array());
$data = $this->metadata->get('app.'.$this->type.'.default.scopeLevel', array());
foreach ($data as $scope => $item) {
if (isset($table->$scope)) continue;
@@ -383,11 +393,17 @@ class Table
$table->$scope = $value;
}
$fieldData = $this->metadata->get('app.acl.default.fieldLevel', array());
$defaultFieldData = $this->metadata->get('app.'.$this->type.'.default.fieldLevel', array());
foreach ($this->getScopeList() as $scope) {
if (isset($table->$scope) && $table->$scope === false) continue;
if (!$this->getMetadata()->get('scopes.' . $scope . '.entity')) continue;
if (!$this->getMetadata()->get('scopes.' . $scope . '.acl')) continue;
if (!$this->getMetadata()->get('scopes.' . $scope . '.aclPortal')) continue;
foreach ($fieldData as $scope => $s) {
$fieldList = array_keys($this->getMetadata()->get("entityDefs.{$scope}.fields", []));
foreach ($s as $field => $f) {
foreach ($defaultFieldData as $field => $f) {
if (!in_array($field, $fieldList)) continue;
if (!isset($fieldTable->$scope)) {
$fieldTable->$scope = (object) [];
@@ -411,7 +427,7 @@ class Table
$aclType = $this->defaultAclType;
}
if (!empty($aclType)) {
$defaultValue = $this->metadata->get('app.acl.scopeLevelTypesDefaults.' . $aclType, true);
$defaultValue = $this->metadata->get('app.'.$this->type.'.scopeLevelTypesDefaults.' . $aclType, $this->metadata->get('app.'.$this->type.'.scopeLevelTypesDefaults.record'));
if (is_array($defaultValue)) {
$defaultValue = (object) $defaultValue;
}
@@ -427,7 +443,7 @@ class Table
return;
}
$data = $this->metadata->get('app.acl.mandatory.scopeLevel', array());
$data = $this->metadata->get('app.'.$this->type.'.mandatory.scopeLevel', array());
foreach ($data as $scope => $item) {
$value = $item;
@@ -437,14 +453,17 @@ class Table
$table->$scope = $value;
}
$fieldData = $this->metadata->get('app.acl.mandatory.fieldLevel', array());
$mandatoryData = $this->metadata->get('app.'.$this->type.'.mandatory.fieldLevel', array());
foreach ($this->getScopeList() as $scope) {
if (isset($table->$scope) && $table->$scope === false) continue;
if (!$this->getMetadata()->get('scopes.' . $scope . '.entity')) continue;
if (!$this->getMetadata()->get('scopes.' . $scope . '.acl')) continue;
if (!$this->getMetadata()->get('scopes.' . $scope . '.aclPortal')) continue;
foreach ($fieldData as $scope => $s) {
$fieldList = array_keys($this->getMetadata()->get("entityDefs.{$scope}.fields", []));
if (!isset($fieldTable->$scope)) {
$fieldTable->$scope = (object) [];
}
foreach ($s as $field => $f) {
foreach ($mandatoryData as $field => $f) {
if (!in_array($field, $fieldList)) continue;
$fieldTable->$scope->$field = (object) [];
foreach ($this->fieldActionList as $action) {

View File

@@ -58,6 +58,11 @@ class AclManager
return $this->container;
}
protected function getMetadata()
{
return $this->metadata;
}
public function getImplementation($scope)
{
if (empty($this->implementationHashMap[$scope])) {

View File

@@ -29,20 +29,69 @@
namespace Espo\Core\AclPortal;
use \Espo\Core\Exceptions\Error;
use \Espo\ORM\Entity;
use \Espo\Entities\User;
use \Espo\Entities\Portal;
use \Espo\Core\Utils\Config;
use \Espo\Core\Utils\Metadata;
use \Espo\Core\Utils\FieldManager;
use \Espo\Core\Utils\File\Manager as FileManager;
class Table extends \Espo\Core\Acl\Table
{
protected $type = 'aclPortal';
protected $portal;
protected $defaultAclType = 'recordAllOwnNo';
protected $levelList = ['all', 'account', 'contact', 'own', 'no'];
protected $valuePermissionList = [];
public function __construct(User $user, Portal $portal, Config $config = null, FileManager $fileManager = null, Metadata $metadata = null, FieldManager $fieldManager = null)
{
if (empty($portal)) {
throw new Error("No portal was passed to AclPortal\\Table constructor.");
}
$this->portal = $portal;
parent::__construct($user, $config, $fileManager, $metadata, $fieldManager);
}
protected function getPortal()
{
return $this->portal;
}
protected function initCacheFilePath()
{
$this->cacheFilePath = 'data/cache/application/acl-portal/'.$this->getPortal()->id.'/' . $this->getUser()->id . '.php';
}
protected function getRoleList()
{
$roleList = [];
$userRoleList = $this->getUser()->get('portalRoles');
foreach ($userRoleList as $role) {
$roleList[] = $role;
}
$portalRoleList = $this->getPortal()->get('portalRoles');
foreach ($portalRoleList as $role) {
$roleList[] = $role;
}
return $roleList;
}
protected function getScopeWithAclList()
{
$scopeList = [];
$scopes = $this->metadata->get('scopes');
$scopes = $this->getMetadata()->get('scopes');
foreach ($scopes as $scope => $d) {
if (empty($d['acl'])) continue;
if (empty($d['aclPortal'])) continue;

View File

@@ -29,6 +29,9 @@
namespace Espo\Core;
use \Espo\ORM\Entity;
use \Espo\Entities\User;
use \Espo\Core\Utils\Util;
class AclPortalManager extends AclManager
{
@@ -41,7 +44,7 @@ class AclPortalManager extends AclManager
$className = '\\Espo\\Custom\\AclPortal\\' . $normalizedName;
if (!class_exists($className)) {
$moduleName = $this->metadata->getScopeModuleName($scope);
$moduleName = $this->getMetadata()->getScopeModuleName($scope);
if ($moduleName) {
$className = '\\Espo\\Modules\\' . $moduleName . '\\AclPortal\\' . $normalizedName;
} else {
@@ -67,6 +70,23 @@ class AclPortalManager extends AclManager
return $this->implementationHashMap[$scope];
}
protected function getTable(User $user)
{
$key = spl_object_hash($user);
if (empty($this->tableHashMap[$key])) {
$config = $this->getContainer()->get('config');
$fileManager = $this->getContainer()->get('fileManager');
$metadata = $this->getContainer()->get('metadata');
$fieldManager = $this->getContainer()->get('fieldManager');
$portal = $this->getContainer()->get('portal');
$this->tableHashMap[$key] = new $this->tableClassName($user, $portal, $config, $fileManager, $metadata, $fieldManager);
}
return $this->tableHashMap[$key];
}
public function checkReadOnlyAccount(User $user, $scope)
{
if ($user->isAdmin()) {

View File

@@ -33,22 +33,19 @@ class Application
{
private $metadata;
private $container;
protected $container;
private $slim;
private $auth;
/**
* Constructor
*/
public function __construct()
{
$this->initContainer();
date_default_timezone_set('UTC');
$GLOBALS['log'] = $this->container->get('log');
$this->initContainer();
$GLOBALS['log'] = $this->getContainer()->get('log');
$this->initAutoloads();
}
@@ -160,6 +157,11 @@ class Application
return false;
}
protected function createApiAuth($auth)
{
return new \Espo\Core\Utils\Api\Auth($auth);
}
protected function routeHooks()
{
$container = $this->getContainer();
@@ -171,9 +173,9 @@ class Application
$container->get('output')->processError($e->getMessage(), $e->getCode());
}
$apiAuth = new \Espo\Core\Utils\Api\Auth($auth);
$this->getSlim()->add($apiAuth);
$apiAuth = $this->createApiAuth($auth);
$this->getSlim()->add($apiAuth);
$this->getSlim()->hook('slim.before.dispatch', function () use ($slim, $container) {
$route = $slim->router()->getCurrentRoute();
@@ -233,13 +235,19 @@ class Application
});
}
protected function initRoutes()
protected function getRouteList()
{
$routes = new \Espo\Core\Utils\Route($this->getContainer()->get('config'), $this->getMetadata(), $this->getContainer()->get('fileManager'));
$crudList = array_keys( $this->getContainer()->get('config')->get('crud') );
foreach ($routes->getAll() as $route) {
return $routes->getAll();
}
protected function initRoutes()
{
$crudList = array_keys($this->getContainer()->get('config')->get('crud'));
foreach ($this->getRouteList() as $route) {
$method = strtolower($route['method']);
if (!in_array($method, $crudList)) {
$GLOBALS['log']->error('Route: Method ['.$method.'] does not exist. Please check your route ['.$route['route'].']');

View File

@@ -29,11 +29,77 @@
namespace Espo\Core;
class ApplicationPortal extends Appplication
use \Espo\Core\Exceptions\Error;
class ApplicationPortal extends Application
{
public function __construct($portalId)
{
date_default_timezone_set('UTC');
$this->initContainer();
if (empty($portalId)) {
throw new Error("Portal id was not passed to ApplicationPortal.");
}
$portal = $this->getContainer()->get('entityManager')->getEntity('Portal', $portalId);
if (!$portal) {
throw new NotFound();
}
if (!$portal->get('isActive')) {
throw new Forbidden("Portal is not active.");
}
$this->portal = $portal;
$this->getContainer()->setPortal($portal);
$GLOBALS['log'] = $this->getContainer()->get('log');
$this->initAutoloads();
}
protected function getAuth()
{
if (empty($this->auth)) {
$this->auth = new \Espo\Core\Utils\AuthPortal($this->getContainer());
}
return $this->auth;
}
protected function getPortal()
{
return $this->portal;
}
protected function initContainer()
{
$this->container = new ContainerPortal();
}
protected function getRouteList()
{
$routeList = parent::getRouteList();
foreach ($routeList as $i => $route) {
if (isset($route['route'])) {
if ($route['route']{0} !== '/') {
$route['route'] = '/' . $route['route'];
}
$route['route'] = '/:portalId' . $route['route'];
}
$routeList[$i] = $route;
}
return $routeList;
}
public function runClient()
{
$this->getContainer()->get('clientManager')->display(null, 'html/portal.html', array(
'portalId' => $this->getPortal()->id
));
}
}

View File

@@ -40,7 +40,6 @@ class Container
*/
public function __construct()
{
}
public function get($name)
@@ -51,6 +50,11 @@ class Container
return $this->data[$name];
}
protected function set($name, $obj)
{
$this->data[$name] = $obj;
}
private function load($name)
{
$loadMethod = 'load' . ucfirst($name);
@@ -304,9 +308,9 @@ class Container
);
}
public function setUser($user)
public function setUser(\Espo\Entities\User $user)
{
$this->data['user'] = $user;
$this->set('user', $user);
}
}

View File

@@ -54,5 +54,10 @@ class ContainerPortal extends Container
$this->get('user')
);
}
public function setPortal(\Espo\Entities\Portal $portal)
{
$this->set('portal', $portal);
}
}

View File

@@ -439,6 +439,17 @@ class Base
if ($this->getSeed()->hasAttribute('createdById')) {
$d['createdById'] = $this->getUser()->id;
}
if ($this->getSeed()->hasAttribute('parentId') && $this->getSeed()->hasRelation('parent')) {
$contactId = $this->getUser()->get('contactId');
if ($contactId) {
$d[] = array(
'parentType' => 'Contact',
'parentId' => $contactId
);
}
}
if (!empty($d)) {
$result['whereClause'][] = array(
'OR' => $d
@@ -466,6 +477,18 @@ class Base
$this->setDistinct(true, $result);
$d['accountsAccess.id'] = $accountIdList;
}
if ($this->getSeed()->hasAttribute('parentId') && $this->getSeed()->hasRelation('parent')) {
$d[] = array(
'parentType' => 'Account',
'parentId' => $accountIdList
);
if ($contactId) {
$d[] = array(
'parentType' => 'Contact',
'parentId' => $contactId
);
}
}
}
if ($contactId) {

View File

@@ -38,44 +38,51 @@ class Auth
protected $authentication;
protected $config;
protected $entityManager;
public function __construct(\Espo\Core\Container $container)
{
$this->container = $container;
$this->entityManager = $this->container->get('entityManager');
$this->config = $this->container->get('config');
$authenticationMethod = $this->config->get('authenticationMethod', 'Espo');
$authenticationMethod = $this->getConfig()->get('authenticationMethod', 'Espo');
$authenticationClassName = "\\Espo\\Core\\Utils\\Authentication\\" . $authenticationMethod;
$this->authentication = new $authenticationClassName($this->config, $this->entityManager, $this);
$this->authentication = new $authenticationClassName($this->getConfig(), $this->getEntityManager(), $this);
$this->request = $this->container->get('slim')->request();
$this->request = $container->get('slim')->request();
}
protected function getContainer()
{
return $this->container;
}
protected function getConfig()
{
return $this->getContainer()->get('config');
}
protected function getEntityManager()
{
return $this->getContainer()->get('entityManager');
}
public function useNoAuth($isAdmin = false)
{
$entityManager = $this->container->get('entityManager');
$entityManager = $this->getContainer()->get('entityManager');
$user = $entityManager->getRepository('User')->get('system');
if (!$user) {
throw new Error('System user is not found');
throw new Error("System user is not found");
}
$user->set('isAdmin', $isAdmin);
$entityManager->setUser($user);
$this->container->setUser($user);
$this->getContainer()->setUser($user);
}
public function login($username, $password)
{
$entityManager = $this->entityManager;
$authToken = $entityManager->getRepository('AuthToken')->where(array('token' => $password))->findOne();
$authToken = $this->getEntityManager()->getRepository('AuthToken')->where(array('token' => $password))->findOne();
$user = $this->authentication->login($username, $password, $authToken);
@@ -84,12 +91,16 @@ class Auth
$GLOBALS['log']->debug("AUTH: Trying to login as user '".$user->get('userName')."' which is not active.");
return false;
}
$entityManager->setUser($user);
$this->container->setUser($user);
if (!$user->isAdmin() && $user->get('isPortalUser')) {
$GLOBALS['log']->debug("AUTH: Trying to login to crm as a portal user '".$user->get('userName')."'.");
return false;
}
$this->getEntityManager()->setUser($user);
$this->getContainer()->setUser($user);
if ($this->request->headers->get('HTTP_ESPO_AUTHORIZATION')) {
if (!$authToken) {
$authToken = $entityManager->getEntity('AuthToken');
$authToken = $this->getEntityManager()->getEntity('AuthToken');
$token = $this->createToken($user);
$authToken->set('token', $token);
$authToken->set('hash', $user->get('password'));
@@ -98,7 +109,7 @@ class Auth
}
$authToken->set('lastAccess', date('Y-m-d H:i:s'));
$entityManager->saveEntity($authToken);
$this->getEntityManager()->saveEntity($authToken);
$user->set('token', $authToken->get('token'));
}
@@ -113,11 +124,9 @@ class Auth
public function destroyAuthToken($token)
{
$entityManager = $this->container->get('entityManager');
$authToken = $entityManager->getRepository('AuthToken')->where(array('token' => $token))->findOne();
$authToken = $this->getEntityManager()->getRepository('AuthToken')->where(array('token' => $token))->findOne();
if ($authToken) {
$entityManager->removeEntity($authToken);
$this->getEntityManager()->removeEntity($authToken);
return true;
}
}

View File

@@ -0,0 +1,95 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2015 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Core\Utils;
use \Espo\Core\Exceptions\Error;
use \Espo\Core\Exceptions\Forbidden;
class AuthPortal extends Auth
{
protected function getPortal()
{
return $this->getContainer()->get('portal');
}
public function login($username, $password)
{
$authToken = $this->getEntityManager()->getRepository('AuthToken')->where(array('token' => $password))->findOne();
if ($authToken) {
if ($authToken->get('portalId') !== $this->getPortal()->id) {
$GLOBALS['log']->debug("AUTH: Trying to login to portal with a token not related to portal.");
return false;
}
}
$user = $this->authentication->login($username, $password, $authToken);
if ($user) {
if (!$user->isActive()) {
$GLOBALS['log']->debug("AUTH: Trying to login to portal as user '".$user->get('userName')."' which is not active.");
return false;
}
if (!$user->isAdmin() && !$this->getEntityManager()->getRepository('Portal')->isRelated($this->getPortal(), 'users', $user)) {
$GLOBALS['log']->debug("AUTH: Trying to login to portal as user '".$user->get('userName')."' which is not related to portal.");
return false;
}
if (!$user->isAdmin() && !$user->get('isPortalUser')) {
$GLOBALS['log']->debug("AUTH: Trying to login to portal as user '".$user->get('userName')."' which is not portal user.");
return false;
}
$user->set('portalId', $this->getPortal()->id);
$this->getEntityManager()->setUser($user);
$this->getContainer()->setUser($user);
if ($this->request->headers->get('HTTP_ESPO_AUTHORIZATION')) {
if (!$authToken) {
$authToken = $this->getEntityManager()->getEntity('AuthToken');
$token = $this->createToken($user);
$authToken->set('token', $token);
$authToken->set('hash', $user->get('password'));
$authToken->set('ipAddress', $_SERVER['REMOTE_ADDR']);
$authToken->set('userId', $user->id);
$authToken->set('portalId', $this->getPortal()->id);
}
$authToken->set('lastAccess', date('Y-m-d H:i:s'));
$this->getEntityManager()->saveEntity($authToken);
$user->set('token', $authToken->get('token'));
}
return true;
}
}
}

View File

@@ -73,6 +73,5 @@ abstract class Base
return $this->passwordHash;
}
}

View File

@@ -45,7 +45,7 @@ class Espo extends Base
'whereClause' => array(
'userName' => $username,
'password' => $hash
),
)
));
return $user;

View File

@@ -45,10 +45,6 @@ class ClientManager
{
$this->config = $config;
$this->themeManager = $themeManager;
if ($this->config->get('isDeveloperMode')) {
$this->mainHtmlFilePath = $this->htmlFilePathForDeveloperMode;
}
}
protected function getThemeManager()
@@ -61,16 +57,25 @@ class ClientManager
return $this->config;
}
public function display($runScript = null, $mainHtmlFilePath = null)
public function display($runScript = null, $htmlFilePath = null, $vars = array())
{
if (is_null($runScript)) {
$runScript = $this->runScript;
}
if (is_null($mainHtmlFilePath)) {
$mainHtmlFilePath = $this->mainHtmlFilePath;
if (is_null($htmlFilePath)) {
$htmlFilePath = $this->mainHtmlFilePath;
}
$html = file_get_contents($mainHtmlFilePath);
if ($this->getConfig()->get('isDeveloperMode')) {
if (file_exists('frontend/' . $htmlFilePath)) {
$htmlFilePath = 'frontend/' . $htmlFilePath;
}
}
$html = file_get_contents($htmlFilePath);
foreach ($vars as $key => $value) {
$html = str_replace('{{'.$key.'}}', $value, $html);
}
$html = str_replace('{{cacheTimestamp}}', $this->getConfig()->get('cacheTimestamp', 0), $html);
$html = str_replace('{{useCache}}', $this->getConfig()->get('useCache') ? 'true' : 'false' , $html);
$html = str_replace('{{stylesheet}}', $this->getThemeManager()->getStylesheet(), $html);

View File

@@ -28,6 +28,7 @@
************************************************************************/
namespace Espo\Core\Utils;
class Route
{
protected $data = null;
@@ -66,7 +67,6 @@ class Route
return $this->metadata;
}
public function get($key = '', $returns = null)
{
if (!isset($this->data)) {
@@ -91,13 +91,11 @@ class Route
return $lastRoute;
}
public function getAll()
{
return $this->get();
}
protected function init()
{
if (file_exists($this->cacheFile) && $this->getConfig()->get('useCache')) {
@@ -146,17 +144,14 @@ class Route
return $currData;
}
protected function addToData($data, $newData)
{
if (!is_array($newData)) {
return $data;
}
foreach($newData as $route) {
foreach ($newData as $route) {
$route['route'] = $this->adjustPath($route['route']);
$data[] = $route;
}
@@ -174,11 +169,10 @@ class Route
{
$routePath = trim($routePath);
if ( substr($routePath,0,1) != '/') {
if (substr($routePath,0,1) != '/') {
return '/'.$routePath;
}
return $routePath;
}
}

View File

@@ -0,0 +1,51 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2015 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\EntryPoints;
use \Espo\Core\Exceptions\NotFound;
use \Espo\Core\Exceptions\Forbidden;
use \Espo\Core\Exceptions\BadRequest;
class Portal extends \Espo\Core\EntryPoints\Base
{
public static $authRequired = false;
public function run()
{
if (empty($_GET['id'])) {
throw new BadRequest();
}
$id = $_GET['id'];
$application = new \Espo\Core\ApplicationPortal($id);
$application->runClient();
}
}

View File

@@ -28,6 +28,7 @@
************************************************************************/
namespace Espo\ORM\Repositories;
use \Espo\ORM\EntityManager;
use \Espo\ORM\EntityFactory;
use \Espo\ORM\EntityCollection;

View File

@@ -63,23 +63,9 @@
},
"scopeLevelTypesDefaults": {
"boolean": true,
"recordAllTeamOwnNo": {
"read": "all",
"edit": "all",
"delete": "no"
},
"recordAllOwnNo": {
"read": "all",
"edit": "all",
"delete": "no"
},
"recordAllTeamNo": {
"read": "all",
"edit": "all",
"delete": "no"
},
"recordAllNo": {
"record": {
"read": "all",
"stream": "all",
"edit": "all",
"delete": "no"
}

View File

@@ -7,11 +7,7 @@
"delete": "no",
"stream": "no"
},
"Team": {
"read": "no",
"edit": "no",
"delete": "no"
},
"Team": false,
"Note": {
"read": "own",
"edit": "own",
@@ -25,11 +21,7 @@
"delete": "own"
},
"PhoneNumber": false,
"EmailAccount": {
"read": "own",
"edit": "own",
"delete": "own"
},
"EmailAccount": false,
"Role": false,
"PortalRole": false,
"EmailFilter": false,
@@ -57,23 +49,9 @@
},
"scopeLevelTypesDefaults": {
"boolean": false,
"recordAllAccountOwnNo": {
"read": "no",
"edit": "no",
"delete": "no"
},
"recordAllOwnNo": {
"read": "no",
"edit": "no",
"delete": "no"
},
"recordAllAccountNo": {
"read": "no",
"edit": "no",
"delete": "no"
},
"recordAllNo": {
"record": {
"read": "no",
"stream": "no",
"edit": "no",
"delete": "no"
}

View File

@@ -17,6 +17,9 @@
"user": {
"type": "link"
},
"portal": {
"type": "link"
},
"ipAddress": {
"type": "varchar",
"maxLength": "36"
@@ -37,6 +40,10 @@
"user": {
"type": "belongsTo",
"entity": "User"
},
"portal": {
"type": "belongsTo",
"entity": "Portal"
}
},
"collection": {

View File

@@ -121,6 +121,11 @@ class Email extends \Espo\Core\SelectManagers\Base
$this->boolFilterOnlyMy($result);
}
protected function accessPortalOnlyOwn(&$result)
{
$this->boolFilterOnlyMy($result);
}
protected function accessOnlyTeam(&$result)
{
$this->setDistinct(true, $result);
@@ -135,6 +140,55 @@ class Email extends \Espo\Core\SelectManagers\Base
);
}
protected function accessPortalOnlyAccount(&$result)
{
$this->setDistinct(true, $result);
$this->addLeftJoin(['users', 'usersAccess'], $result);
$d = array(
'usersAccess.id' => $this->getUser()->id
);
$accountIdList = $this->getUser()->getLinkMultipleIdList('accounts');
if (count($accountIdList)) {
$d['accountId'] = $accountIdList;
}
$contactId = $this->getUser()->get('contactId');
if ($contactId) {
$d[] = array(
'parentId' => $contactId,
'parentType' => 'Contact'
);
}
$result['whereClause'][] = array(
'OR' => $d
);
}
protected function accessPortalOnlyContact(&$result)
{
$this->setDistinct(true, $result);
$this->addLeftJoin(['users', 'usersAccess'], $result);
$d = array(
'usersAccess.id' => $this->getUser()->id
);
$contactId = $this->getUser()->get('contactId');
if ($contactId) {
$d[] = array(
'parentId' => $contactId,
'parentType' => 'Contact'
);
}
$result['whereClause'][] = array(
'OR' => $d
);
}
protected function textFilter($textFilter, &$result)
{
$d = array();

View File

@@ -0,0 +1,65 @@
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2015 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
Espo.define('acl-portal/email', 'acl-portal', function (Dep) {
return Dep.extend({
checkModelRead: function (model, data, precise) {
var result = this.checkModel(model, data, 'read', precise);
if (result) {
return true;
}
if (data === false) {
return false;
}
var d = data || {};
if (d.read === 'no') {
return false;
}
if (model.has('usersIds')) {
if (~(model.get('usersIds') || []).indexOf(this.getUser().id)) {
return true;
}
} else {
if (precise) {
return null;
}
}
return result;
}
});
});

View File

@@ -0,0 +1,36 @@
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2015 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
Espo.define('app-portal', ['app'], function (Dep) {
return Dep.extend({
});
});

View File

@@ -543,6 +543,8 @@ Espo.define(
}, Backbone.Events);
App.extend = Backbone.Router.extend;
return App;
});

View File

@@ -36,6 +36,7 @@ Espo.define('views/portal-role/record/table', 'views/role/record/table', functio
'recordAllContactOwnNo': ['all', 'contact', 'own', 'no'],
'recordAllAccountNo': ['all', 'account', 'no'],
'recordAllContactNo': ['all', 'contact', 'no'],
'recordAllAccountContactNo': ['all', 'account', 'contact', 'no'],
'recordAllOwnNo': ['all', 'own', 'no'],
'recordAllNo': ['all', 'no'],
'record': ['all', 'own', 'no']

54
frontend/html/portal.html Normal file
View File

@@ -0,0 +1,54 @@
<!doctype html>
<html>
<head>
<title>EspoCRM</title>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="description" content="EspoCRM is Open Source CRM application. Increase profitability through customer loyalty!">
<script type="text/javascript" src="client/lib/jquery-2.1.4.min.js"></script>
<script type="text/javascript" src="client/lib/underscore-min.js"></script>
<script type="text/javascript" src="client/lib/es6-promise.min.js"></script>
<script type="text/javascript" src="client/lib/backbone-min.js"></script>
<script type="text/javascript" src="client/lib/handlebars.js"></script>
<script type="text/javascript" src="client/lib/base64.js"></script>
<script type="text/javascript" src="client/lib/jquery-ui.min.js"></script>
<script type="text/javascript" src="client/lib/moment.min.js"></script>
<script type="text/javascript" src="client/lib/moment-timezone-with-data.min.js"></script>
<script type="text/javascript" src="client/lib/jquery.timepicker.min.js"></script>
<script type="text/javascript" src="client/lib/jquery.autocomplete.js"></script>
<script type="text/javascript" src="client/lib/bootstrap.min.js"></script>
<script type="text/javascript" src="client/lib/bootstrap-datepicker.js"></script>
<script type="text/javascript" src="client/lib/bull.min.js"></script>
<script type="text/javascript" src="client/src/loader.js"></script>
<script type="text/javascript" src="client/src/utils.js"></script>
<script type="text/javascript" src="client/src/exceptions.js"></script>
<link href="{{stylesheet}}" rel="stylesheet" id='main-stylesheet'>
<link rel="icon" href="client/img/favicon.ico" type="image/x-icon">
<link rel="shortcut icon" href="client/img/favicon.ico" type="image/x-icon">
<script type="text/javascript">
$(function () {
Espo.require('app-portal', function (App) {
var app = new App({
useCache: false,
url: '../api/v1/portal/{{portalId}}',
}, function (app) {
{{runScript}}
});
});
});
</script>
</head>
<body>
<div class="container content"></div>
<footer>
<p class="credit small">&copy; 2015 <a href="http://www.espocrm.com" title="Powered by EspoCRM" alt="Visit official EspoCRM website">EspoCRM</a></p>
</footer>
</body>
</html>

34
html/portal.html Normal file
View File

@@ -0,0 +1,34 @@
<!doctype html>
<html>
<head>
<title>EspoCRM</title>
<script type="text/javascript" src="client/espo.min.js?r=@@timestamp"></script>
<link href="{{stylesheet}}?r=@@timestamp" rel="stylesheet" id='main-stylesheet'>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="description" content="EspoCRM is Open Source CRM application. Increase profitability through customer loyalty!">
<link rel="icon" href="client/img/favicon.ico" type="image/x-icon">
<link rel="shortcut icon" href="client/img/favicon.ico" type="image/x-icon">
<script type="text/javascript">
$(function () {
Espo.require('app-portal', function (App) {
var app = new App({
useCache: {{useCache}},
cacheTimestamp: {{cacheTimestamp}},
url: '../api/v1/portal/{{portalId}}',
}, function (app) {
{{runScript}}
});
});
});
</script>
</head>
<body>
<div class="container content"></div>
<footer>
<p class="credit small">&copy; 2015 <a href="http://www.espocrm.com" title="Powered by EspoCRM" alt="Visit official EspoCRM website">EspoCRM</a></p>
</footer>
</body>
</html>