Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 632ee66155 | |||
| 4446bc3167 | |||
| 785934c7cc | |||
| ac36096d55 | |||
| 8ec8cb3c56 | |||
| 1f7cb2402d | |||
| 3825893ec1 | |||
| a4ed78b953 | |||
| eed9059913 | |||
| 20a1053413 | |||
| e814ea9ec6 | |||
| de16e9a9ce | |||
| 62fba991e2 | |||
| 832c63e014 | |||
| 0194d364b8 | |||
| 1c7785f6ba |
@@ -28,10 +28,10 @@ use \Espo\Core\Exceptions\Forbidden;
|
||||
class ExternalAccount extends \Espo\Core\Controllers\Record
|
||||
{
|
||||
public static $defaultAction = 'list';
|
||||
|
||||
|
||||
public function actionList($params, $data, $request)
|
||||
{
|
||||
$integrations = $this->getEntityManager()->getRepository('Integration')->find();
|
||||
$integrations = $this->getEntityManager()->getRepository('Integration')->find();
|
||||
$arr = array();
|
||||
foreach ($integrations as $entity) {
|
||||
if ($entity->get('enabled') && $this->getMetadata()->get('integrations.' . $entity->id .'.allowUserAccounts')) {
|
||||
@@ -44,22 +44,22 @@ class ExternalAccount extends \Espo\Core\Controllers\Record
|
||||
'list' => $arr
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function actionGetOAuth2Info($params, $data, $request)
|
||||
{
|
||||
$id = $request->get('id');
|
||||
list($integration, $userId) = explode('__', $id);
|
||||
|
||||
|
||||
|
||||
if ($this->getUser()->id != $userId) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$entity = $this->getEntityManager()->getEntity('Integration', $integration);
|
||||
if ($entity) {
|
||||
return array(
|
||||
'clientId' => $entity->get('clientId'),
|
||||
'redirectUri' => $this->getConfig()->get('siteUrl') . '/oauthcallback',
|
||||
'redirectUri' => $this->getConfig()->get('siteUrl') . '?entryPoint=oauthCallback',
|
||||
'isConnected' => $this->getRecordService()->ping($integration, $userId)
|
||||
);
|
||||
}
|
||||
@@ -67,57 +67,57 @@ class ExternalAccount extends \Espo\Core\Controllers\Record
|
||||
|
||||
public function actionRead($params, $data, $request)
|
||||
{
|
||||
list($integration, $userId) = explode('__', $params['id']);
|
||||
list($integration, $userId) = explode('__', $params['id']);
|
||||
|
||||
if ($this->getUser()->id != $userId) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
$entity = $this->getEntityManager()->getEntity('ExternalAccount', $params['id']);
|
||||
}
|
||||
|
||||
$entity = $this->getEntityManager()->getEntity('ExternalAccount', $params['id']);
|
||||
return $entity->toArray();
|
||||
}
|
||||
|
||||
|
||||
public function actionUpdate($params, $data)
|
||||
{
|
||||
return $this->actionPatch($params, $data);
|
||||
}
|
||||
|
||||
|
||||
public function actionPatch($params, $data)
|
||||
{
|
||||
list($integration, $userId) = explode('__', $params['id']);
|
||||
|
||||
|
||||
|
||||
if ($this->getUser()->id != $userId) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
|
||||
if (isset($data['enabled']) && !$data['enabled']) {
|
||||
$data['data'] = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$entity = $this->getEntityManager()->getEntity('ExternalAccount', $params['id']);
|
||||
$entity->set($data);
|
||||
$this->getEntityManager()->saveEntity($entity);
|
||||
|
||||
return $entity->toArray();
|
||||
|
||||
return $entity->toArray();
|
||||
}
|
||||
|
||||
|
||||
public function actionAuthorizationCode($params, $data, $request)
|
||||
{
|
||||
if (!$request->isPost()) {
|
||||
throw new Error('Bad HTTP method type.');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$id = $data['id'];
|
||||
$code = $data['code'];
|
||||
|
||||
list($integration, $userId) = explode('__', $id);
|
||||
|
||||
list($integration, $userId) = explode('__', $id);
|
||||
|
||||
if ($this->getUser()->id != $userId) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
$service = $this->getRecordService();
|
||||
|
||||
$service = $this->getRecordService();
|
||||
return $service->authorizationCode($integration, $userId, $code);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ class Layout extends \Espo\Core\Controllers\Base
|
||||
{
|
||||
$data = $this->getContainer()->get('layout')->get($params['scope'], $params['name']);
|
||||
if (empty($data)) {
|
||||
throw new NotFound("Layout " . $params['scope'] . ":" . $params['name'] . ' is not found');
|
||||
throw new NotFound("Layout " . $params['scope'] . ":" . $params['name'] . ' is not found.');
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
@@ -43,16 +43,18 @@ class Layout extends \Espo\Core\Controllers\Base
|
||||
if (!$this->getUser()->isAdmin()) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
$result = $this->getContainer()->get('layout')->set($data, $params['scope'], $params['name']);
|
||||
|
||||
$layoutManager = $this->getContainer()->get('layout');
|
||||
$layoutManager->set($data, $params['scope'], $params['name']);
|
||||
$result = $layoutManager->save();
|
||||
|
||||
if ($result === false) {
|
||||
throw new Error("Error while saving layout");
|
||||
throw new Error("Error while saving layout.");
|
||||
}
|
||||
|
||||
$this->getContainer()->get('dataManager')->updateCacheTimestamp();
|
||||
|
||||
return $this->getContainer()->get('layout')->get($params['scope'], $params['name']);
|
||||
return $layoutManager->get($params['scope'], $params['name']);
|
||||
}
|
||||
|
||||
public function actionPatch($params, $data)
|
||||
|
||||
@@ -94,7 +94,7 @@ class CronManager
|
||||
|
||||
protected function getLastRunTime()
|
||||
{
|
||||
$lastRunTime = $this->getFileManager()->getContents($this->lastRunTime);
|
||||
$lastRunTime = $this->getFileManager()->getPhpContents($this->lastRunTime);
|
||||
if (!is_int($lastRunTime)) {
|
||||
$lastRunTime = time() - (intval($this->getConfig()->get('cron.minExecutionTime')) + 60);
|
||||
}
|
||||
@@ -104,7 +104,7 @@ class CronManager
|
||||
|
||||
protected function setLastRunTime($time)
|
||||
{
|
||||
return $this->getFileManager()->putContentsPHP($this->lastRunTime, $time);
|
||||
return $this->getFileManager()->putPhpContents($this->lastRunTime, $time);
|
||||
}
|
||||
|
||||
protected function checkLastRunTime()
|
||||
|
||||
@@ -29,33 +29,33 @@ use \Espo\Core\Exceptions\NotFound;
|
||||
class ClientManager
|
||||
{
|
||||
protected $entityManager;
|
||||
|
||||
|
||||
protected $metadata;
|
||||
|
||||
|
||||
protected $clientMap = array();
|
||||
|
||||
|
||||
public function __construct($entityManager, $metadata, $config)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
$this->metadata = $metadata;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
|
||||
protected function getMetadata()
|
||||
{
|
||||
return $this->metadata;
|
||||
}
|
||||
|
||||
|
||||
protected function getEntityManager()
|
||||
{
|
||||
return $this->entityManager;
|
||||
}
|
||||
|
||||
|
||||
protected function getConfig()
|
||||
{
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
|
||||
public function storeAccessToken($hash, $data)
|
||||
{
|
||||
if (!empty($this->clientMap[$hash]) && !empty($this->clientMap[$hash]['externalAccountEntity'])) {
|
||||
@@ -64,37 +64,37 @@ class ClientManager
|
||||
$externalAccountEntity->set('tokenType', $data['tokenType']);
|
||||
$this->getEntityManager()->saveEntity($externalAccountEntity);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function create($integration, $userId)
|
||||
{
|
||||
$authMethod = $this->getMetadata()->get("integrations.{$integration}.authMethod");
|
||||
$methodName = 'create' . ucfirst($authMethod);
|
||||
return $this->$methodName($integration, $userId);
|
||||
$authMethod = $this->getMetadata()->get("integrations.{$integration}.authMethod");
|
||||
$methodName = 'create' . ucfirst($authMethod);
|
||||
return $this->$methodName($integration, $userId);
|
||||
}
|
||||
|
||||
|
||||
protected function createOAuth2($integration, $userId)
|
||||
{
|
||||
{
|
||||
$integrationEntity = $this->getEntityManager()->getEntity('Integration', $integration);
|
||||
$externalAccountEntity = $this->getEntityManager()->getEntity('ExternalAccount', $integration . '__' . $userId);
|
||||
|
||||
|
||||
$className = $this->getMetadata()->get("integrations.{$integration}.clientClassName");
|
||||
|
||||
$redirectUri = $this->getConfig()->get('siteUrl') . '/oauthcallback'; // TODO move to client class
|
||||
|
||||
|
||||
$redirectUri = $this->getConfig()->get('siteUrl') . '?entryPoint=oauthCallback'; // TODO move to client class
|
||||
|
||||
if (!$externalAccountEntity) {
|
||||
throw new Error("External Account {$integration} not found for {$userId}");
|
||||
}
|
||||
|
||||
|
||||
if (!$integrationEntity->get('enabled')) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (!$externalAccountEntity->get('enabled')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$oauth2Client = new \Espo\Core\ExternalAccount\OAuth2\Client();
|
||||
|
||||
}
|
||||
|
||||
$oauth2Client = new \Espo\Core\ExternalAccount\OAuth2\Client();
|
||||
|
||||
$client = new $className($oauth2Client, array(
|
||||
'endpoint' => $this->getMetadata()->get("integrations.{$integration}.params.endpoint"),
|
||||
'tokenEndpoint' => $this->getMetadata()->get("integrations.{$integration}.params.tokenEndpoint"),
|
||||
@@ -105,12 +105,12 @@ class ClientManager
|
||||
'refreshToken' => $externalAccountEntity->get('refreshToken'),
|
||||
'tokenType' => $externalAccountEntity->get('tokenType'),
|
||||
), $this);
|
||||
|
||||
|
||||
$this->addToClientMap($client, $integrationEntity, $externalAccountEntity, $userId);
|
||||
|
||||
return $client;
|
||||
|
||||
return $client;
|
||||
}
|
||||
|
||||
|
||||
protected function addToClientMap($client, $integrationEntity, $externalAccountEntity, $userId)
|
||||
{
|
||||
$this->clientMap[spl_object_hash($client)] = array(
|
||||
|
||||
@@ -29,9 +29,9 @@ use \Espo\Core\ExternalAccount\OAuth2\Client;
|
||||
abstract class OAuth2Abstract implements IClient
|
||||
{
|
||||
protected $client = null;
|
||||
|
||||
|
||||
protected $manager = null;
|
||||
|
||||
|
||||
protected $paramList = array(
|
||||
'endpoint',
|
||||
'tokenEndpoint',
|
||||
@@ -42,33 +42,33 @@ abstract class OAuth2Abstract implements IClient
|
||||
'refreshToken',
|
||||
'redirectUri',
|
||||
);
|
||||
|
||||
|
||||
protected $clientId = null;
|
||||
|
||||
|
||||
protected $clientSecret = null;
|
||||
|
||||
|
||||
protected $accessToken = null;
|
||||
|
||||
|
||||
protected $refreshToken = null;
|
||||
|
||||
|
||||
protected $redirectUri = null;
|
||||
|
||||
|
||||
public function __construct($client, array $params = array(), $manager = null)
|
||||
{
|
||||
$this->client = $client;
|
||||
|
||||
$this->setParams($params);
|
||||
|
||||
|
||||
$this->manager = $manager;
|
||||
}
|
||||
|
||||
|
||||
public function getParam($name)
|
||||
{
|
||||
if (in_array($name, $this->paramList)) {
|
||||
return $this->$name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function setParam($name, $value)
|
||||
{
|
||||
if (in_array($name, $this->paramList)) {
|
||||
@@ -79,7 +79,7 @@ abstract class OAuth2Abstract implements IClient
|
||||
$this->$name = $value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function setParams(array $params)
|
||||
{
|
||||
foreach ($this->paramList as $name) {
|
||||
@@ -88,42 +88,41 @@ abstract class OAuth2Abstract implements IClient
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected function afterTokenRefreshed($data)
|
||||
{
|
||||
if ($this->manager) {
|
||||
$this->manager->storeAccessToken(spl_object_hash($this), $data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function getAccessTokenFromAuthorizationCode($code)
|
||||
{
|
||||
$r = $this->client->getAccessToken($this->getParam('tokenEndpoint'), Client::GRANT_TYPE_AUTHORIZATION_CODE, array(
|
||||
'code' => $code,
|
||||
'redirect_uri' => $this->getParam('redirectUri')
|
||||
));
|
||||
|
||||
|
||||
|
||||
if ($r['code'] == 200) {
|
||||
$data = array();
|
||||
if (!empty($r['result'])) {
|
||||
$data['accessToken'] = $r['result']['access_token'];
|
||||
$data['tokenType'] = $r['result']['token_type'];
|
||||
$data['refreshToken'] = $r['result']['refresh_token'];
|
||||
$data['refreshToken'] = $r['result']['refresh_token'];
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
abstract protected function getPingUrl();
|
||||
|
||||
|
||||
public function ping()
|
||||
{
|
||||
if (empty($this->accessToken) || empty($this->clientId) || empty($this->clientSecret)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
$url = $this->getPingUrl();
|
||||
|
||||
try {
|
||||
@@ -133,35 +132,48 @@ abstract class OAuth2Abstract implements IClient
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function request($url, $params = array(), $httpMethod = Client::HTTP_METHOD_GET, $allowRenew = true)
|
||||
|
||||
public function request($url, $params = null, $httpMethod = Client::HTTP_METHOD_GET, $contentType = null, $allowRenew = true)
|
||||
{
|
||||
$r = $this->client->request($url, $params, $httpMethod);
|
||||
|
||||
$httpHeaders = array();
|
||||
if (!empty($contentType)) {
|
||||
$httpHeaders['Content-Type'] = $contentType;
|
||||
switch ($contentType) {
|
||||
case Client::CONTENT_TYPE_MULTIPART_FORM_DATA:
|
||||
$httpHeaders['Content-Length'] = strlen($params);
|
||||
break;
|
||||
case Client::CONTENT_TYPE_APPLICATION_JSON:
|
||||
$httpHeaders['Content-Length'] = strlen($params);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$r = $this->client->request($url, $params, $httpMethod, $httpHeaders);
|
||||
|
||||
$code = null;
|
||||
if (!empty($r['code'])) {
|
||||
$code = $r['code'];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ($code == 200) {
|
||||
return $r['result'];
|
||||
} else {
|
||||
$handledData = $this->handleErrorResponse($r);
|
||||
|
||||
|
||||
if ($allowRenew && is_array($handledData)) {
|
||||
if ($handledData['action'] == 'refreshToken') {
|
||||
if ($this->refreshToken()) {
|
||||
return $this->request($url, $params, $httpMethod, false);
|
||||
if ($this->refreshToken()) {
|
||||
return $this->request($url, $params, $httpMethod, $contentType, false);
|
||||
}
|
||||
} else if ($handledData['action'] == 'renew') {
|
||||
return $this->request($url, $params, $httpMethod, false);
|
||||
return $this->request($url, $params, $httpMethod, $contentType, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
throw new Error("Error after requesting {$httpMethod} {$url}.", $code);
|
||||
}
|
||||
|
||||
|
||||
protected function refreshToken()
|
||||
{
|
||||
if (!empty($this->refreshToken)) {
|
||||
@@ -183,11 +195,11 @@ abstract class OAuth2Abstract implements IClient
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected function handleErrorResponse($r)
|
||||
{
|
||||
if ($r['code'] == 401 && !empty($r['result'])) {
|
||||
$result = $r['result'];
|
||||
$result = $r['result'];
|
||||
if (strpos($r['header'], 'error=invalid_token') !== false) {
|
||||
return array(
|
||||
'action' => 'refreshToken'
|
||||
@@ -198,7 +210,7 @@ abstract class OAuth2Abstract implements IClient
|
||||
);
|
||||
}
|
||||
} else if ($r['code'] == 400 && !empty($r['result'])) {
|
||||
if ($r['result']['error'] == 'invalid_token') {
|
||||
if ($r['result']['error'] == 'invalid_token') {
|
||||
return array(
|
||||
'action' => 'refreshToken'
|
||||
);
|
||||
|
||||
@@ -32,8 +32,9 @@ class Client
|
||||
const TOKEN_TYPE_BEARER = 'Bearer';
|
||||
const TOKEN_TYPE_OAUTH = 'OAuth';
|
||||
|
||||
const CONTENT_TYPE_APPLICATION = 0;
|
||||
const CONTENT_TYPE_MULTIPART = 1;
|
||||
const CONTENT_TYPE_APPLICATION_X_WWW_FORM_URLENENCODED = 'application/x-www-form-urlencoded';
|
||||
const CONTENT_TYPE_MULTIPART_FORM_DATA = 'multipart/form-data';
|
||||
const CONTENT_TYPE_APPLICATION_JSON = 'application/json';
|
||||
|
||||
const HTTP_METHOD_GET = 'GET';
|
||||
const HTTP_METHOD_POST = 'POST';
|
||||
@@ -118,7 +119,7 @@ class Client
|
||||
$this->accessTokenSecret = $accessTokenSecret;
|
||||
}
|
||||
|
||||
public function request($url, $params = array(), $httpMethod = self::HTTP_METHOD_GET, array $httpHeaders = array(), $contentType = self::CONTENT_TYPE_MULTIPART)
|
||||
public function request($url, $params = null, $httpMethod = self::HTTP_METHOD_GET, array $httpHeaders = array())
|
||||
{
|
||||
if ($this->accessToken) {
|
||||
switch ($this->tokenType) {
|
||||
@@ -137,10 +138,10 @@ class Client
|
||||
}
|
||||
}
|
||||
|
||||
return $this->execute($url, $params, $httpMethod, $httpHeaders, $contentType);
|
||||
return $this->execute($url, $params, $httpMethod, $httpHeaders);
|
||||
}
|
||||
|
||||
private function execute($url, $params = array(), $httpMethod, array $httpHeaders = array(), $contentType = self::CONTENT_TYPE_MULTIPART)
|
||||
private function execute($url, $params = null, $httpMethod, array $httpHeaders = array())
|
||||
{
|
||||
$curlOptions = array(
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
@@ -153,8 +154,10 @@ class Client
|
||||
$curlOptions[CURLOPT_POST] = true;
|
||||
case self::HTTP_METHOD_PUT:
|
||||
case self::HTTP_METHOD_PATCH:
|
||||
if (self::CONTENT_TYPE_APPLICATION === $contentType) {
|
||||
if (is_array($params)) {
|
||||
$postFields = http_build_query($params, null, '&');
|
||||
} else {
|
||||
$postFields = $params;
|
||||
}
|
||||
$curlOptions[CURLOPT_POSTFIELDS] = $postFields;
|
||||
break;
|
||||
@@ -165,7 +168,9 @@ class Client
|
||||
if (strpos($url, '?') === false) {
|
||||
$url .= '?';
|
||||
}
|
||||
$url .= http_build_query($params, null, '&');
|
||||
if (is_array($params)) {
|
||||
$url .= http_build_query($params, null, '&');
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -242,7 +247,7 @@ class Client
|
||||
throw new \Exception();
|
||||
}
|
||||
|
||||
return $this->execute($url, $params, self::HTTP_METHOD_POST, $httpHeaders, self::CONTENT_TYPE_APPLICATION);
|
||||
return $this->execute($url, $params, self::HTTP_METHOD_POST, $httpHeaders);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ class HookManager
|
||||
protected function loadHooks()
|
||||
{
|
||||
if ($this->getConfig()->get('useCache') && file_exists($this->cacheFile)) {
|
||||
$this->data = $this->getFileManager()->getContents($this->cacheFile);
|
||||
$this->data = $this->getFileManager()->getPhpContents($this->cacheFile);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ class HookManager
|
||||
$this->data = array_merge_recursive($this->data, $this->getHookData($this->paths['customPath']));
|
||||
|
||||
if ($this->getConfig()->get('useCache')) {
|
||||
$this->getFileManager()->putContentsPHP($this->cacheFile, $this->data);
|
||||
$this->getFileManager()->putPhpContents($this->cacheFile, $this->data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -132,14 +132,16 @@ class Base
|
||||
$d[$field . '*'] = $item['value'] . '%';
|
||||
}
|
||||
}
|
||||
$where['OR'] = $d;
|
||||
$where[] = array(
|
||||
'OR' => $d
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$linkedWith = array();
|
||||
$ignoreList = array('linkedWith', 'boolFilters');
|
||||
foreach ($params['where'] as $item) {
|
||||
foreach ($params['where'] as $item) {
|
||||
if (!in_array($item['type'], $ignoreList)) {
|
||||
$part = $this->getWherePart($item);
|
||||
if (!empty($part)) {
|
||||
@@ -160,7 +162,6 @@ class Base
|
||||
if (is_array($idsValue) && count($idsValue) == 1) {
|
||||
$idsValue = $idsValue[0];
|
||||
}
|
||||
|
||||
|
||||
$relDefs = $this->getSeed()->getRelations();
|
||||
|
||||
@@ -180,8 +181,6 @@ class Base
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (!empty($part)) {
|
||||
@@ -221,7 +220,9 @@ class Base
|
||||
}
|
||||
}
|
||||
|
||||
$result['whereClause']['OR'] = $d;
|
||||
$result['whereClause'][] = array(
|
||||
'OR' => $d
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,9 +247,11 @@ class Base
|
||||
$result['leftJoins'][] = 'teams';
|
||||
}
|
||||
|
||||
$result['whereClause']['OR'] = array(
|
||||
'Team.id' => $this->user->get('teamsIds'),
|
||||
'assignedUserId' => $this->user->id
|
||||
$result['whereClause'][] = array(
|
||||
'OR' => array(
|
||||
'Team.id' => $this->user->get('teamsIds'),
|
||||
'assignedUserId' => $this->user->id
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ class ServiceFactory
|
||||
$config = $this->getContainer()->get('config');
|
||||
|
||||
if (file_exists($this->cacheFile) && $config->get('useCache')) {
|
||||
$this->data = $this->getFileManager()->getContents($this->cacheFile);
|
||||
$this->data = $this->getFileManager()->getPhpContents($this->cacheFile);
|
||||
} else {
|
||||
$this->data = $this->getClassNameHash($this->paths['corePath']);
|
||||
|
||||
@@ -65,7 +65,7 @@ class ServiceFactory
|
||||
$this->data = array_merge($this->data, $this->getClassNameHash($this->paths['customPath']));
|
||||
|
||||
if ($config->get('useCache')) {
|
||||
$result = $this->getFileManager()->putContentsPHP($this->cacheFile, $this->data);
|
||||
$result = $this->getFileManager()->putPhpContents($this->cacheFile, $this->data);
|
||||
if ($result == false) {
|
||||
throw new \Espo\Core\Exceptions\Error();
|
||||
}
|
||||
|
||||
@@ -82,14 +82,14 @@ class Autoload
|
||||
protected function init()
|
||||
{
|
||||
if (file_exists($this->cacheFile) && $this->getConfig()->get('useCache')) {
|
||||
$this->data = $this->getFileManager()->getContents($this->cacheFile);
|
||||
$this->data = $this->getFileManager()->getPhpContents($this->cacheFile);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->data = $this->unify();
|
||||
|
||||
if ($this->getConfig()->get('useCache')) {
|
||||
$result = $this->getFileManager()->putContentsPHP($this->cacheFile, $this->data);
|
||||
$result = $this->getFileManager()->putPhpContents($this->cacheFile, $this->data);
|
||||
if ($result == false) {
|
||||
throw new \Espo\Core\Exceptions\Error('Autoload: Cannot save unified autoload.');
|
||||
}
|
||||
|
||||
@@ -150,7 +150,8 @@ class Config
|
||||
|
||||
$removeData = empty($this->removeData) ? null : $this->removeData;
|
||||
|
||||
$result = $this->getFileManager()->mergeContentsPHP($this->configPath, $values, $removeData);
|
||||
$result = $this->getFileManager()->mergePhpContents($this->configPath, $values, $removeData);
|
||||
|
||||
if ($result) {
|
||||
$this->changedData = array();
|
||||
$this->removeData = array();
|
||||
@@ -162,7 +163,7 @@ class Config
|
||||
|
||||
public function getDefaults()
|
||||
{
|
||||
return $this->getFileManager()->getContents($this->defaultConfigPath);
|
||||
return $this->getFileManager()->getPhpContents($this->defaultConfigPath);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -178,9 +179,9 @@ class Config
|
||||
|
||||
$configPath = file_exists($this->configPath) ? $this->configPath : $this->defaultConfigPath;
|
||||
|
||||
$this->data = $this->getFileManager()->getContents($configPath);
|
||||
$this->data = $this->getFileManager()->getPhpContents($configPath);
|
||||
|
||||
$systemConfig = $this->getFileManager()->getContents($this->systemConfigPath);
|
||||
$systemConfig = $this->getFileManager()->getPhpContents($this->systemConfigPath);
|
||||
$this->data = Util::merge($systemConfig, $this->data);
|
||||
|
||||
return $this->data;
|
||||
|
||||
@@ -333,7 +333,7 @@ class Converter
|
||||
$fileList = $this->getFileManager()->getFileList($this->customTablePath, false, '\.php$', true);
|
||||
|
||||
foreach($fileList as $fileName) {
|
||||
$fileData = $this->getFileManager()->getContents( array($this->customTablePath, $fileName) );
|
||||
$fileData = $this->getFileManager()->getPhpContents( array($this->customTablePath, $fileName) );
|
||||
if (is_array($fileData)) {
|
||||
$customTables = Util::merge($customTables, $fileData);
|
||||
}
|
||||
|
||||
@@ -39,7 +39,6 @@ class FieldManager
|
||||
|
||||
protected $customOptionName = 'isCustom';
|
||||
|
||||
|
||||
public function __construct(Metadata $metadata, Language $language)
|
||||
{
|
||||
$this->metadata = $metadata;
|
||||
@@ -122,7 +121,8 @@ class FieldManager
|
||||
'links.'.$name,
|
||||
);
|
||||
|
||||
$res = $this->getMetadata()->delete($unsets, $this->metadataType, $scope);
|
||||
$this->getMetadata()->delete($this->metadataType, $scope, $unsets);
|
||||
$res = $this->getMetadata()->save();
|
||||
$res &= $this->deleteLabel($name, $scope);
|
||||
|
||||
return (bool) $res;
|
||||
@@ -132,25 +132,25 @@ class FieldManager
|
||||
{
|
||||
$fieldDef = $this->normalizeDefs($name, $fieldDef, $scope);
|
||||
|
||||
$data = Json::encode($fieldDef);
|
||||
$res = $this->getMetadata()->set($data, $this->metadataType, $scope);
|
||||
$this->getMetadata()->set($this->metadataType, $scope, $fieldDef);
|
||||
$res = $this->getMetadata()->save();
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
protected function setTranslatedOptions($name, $value, $scope)
|
||||
{
|
||||
return $this->getLanguage()->set($name, $value, 'options', $scope);
|
||||
return $this->getLanguage()->set($scope, 'options', $name, $value);
|
||||
}
|
||||
|
||||
protected function setLabel($name, $value, $scope)
|
||||
{
|
||||
return $this->getLanguage()->set($name, $value, 'fields', $scope);
|
||||
return $this->getLanguage()->set($scope, 'fields', $name, $value);
|
||||
}
|
||||
|
||||
protected function deleteLabel($name, $scope)
|
||||
{
|
||||
$this->getLanguage()->delete($name, 'fields', $scope);
|
||||
$this->getLanguage()->delete($scope, 'fields', $name);
|
||||
return $this->getLanguage()->save();
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ class ClassParser
|
||||
}
|
||||
|
||||
if ($cacheFile && file_exists($cacheFile) && $this->getConfig()->get('useCache')) {
|
||||
$data = $this->getFileManager()->getContents($cacheFile);
|
||||
$data = $this->getFileManager()->getPhpContents($cacheFile);
|
||||
} else {
|
||||
$data = $this->getClassNameHash($paths['corePath']);
|
||||
|
||||
@@ -104,7 +104,7 @@ class ClassParser
|
||||
}
|
||||
|
||||
if ($cacheFile && $this->getConfig()->get('useCache')) {
|
||||
$result = $this->getFileManager()->putContentsPHP($cacheFile, $data);
|
||||
$result = $this->getFileManager()->putPhpContents($cacheFile, $data);
|
||||
if ($result == false) {
|
||||
throw new \Espo\Core\Exceptions\Error();
|
||||
}
|
||||
|
||||
@@ -156,17 +156,31 @@ class Manager
|
||||
$fullPath = $this->concatPaths($path);
|
||||
|
||||
if (file_exists($fullPath)) {
|
||||
|
||||
if (strtolower(substr($fullPath, -4))=='.php') {
|
||||
return include($fullPath);
|
||||
if (isset($maxlen)) {
|
||||
return file_get_contents($fullPath, $useIncludePath, $context, $offset, $maxlen);
|
||||
} else {
|
||||
if (isset($maxlen)) {
|
||||
return file_get_contents($fullPath, $useIncludePath, $context, $offset, $maxlen);
|
||||
} else {
|
||||
return file_get_contents($fullPath, $useIncludePath, $context, $offset);
|
||||
}
|
||||
return file_get_contents($fullPath, $useIncludePath, $context, $offset);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get PHP array from PHP file
|
||||
*
|
||||
* @param string | array $path
|
||||
* @return array | bool
|
||||
*/
|
||||
public function getPhpContents($path)
|
||||
{
|
||||
$fullPath = $this->concatPaths($path);
|
||||
|
||||
if (file_exists($fullPath) && strtolower(substr($fullPath, -4)) == '.php') {
|
||||
$phpContents = include($fullPath);
|
||||
if (is_array($phpContents)) {
|
||||
return $phpContents;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -206,7 +220,7 @@ class Manager
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function putContentsPHP($path, $data)
|
||||
public function putPhpContents($path, $data)
|
||||
{
|
||||
return $this->putContents($path, $this->getPHPFormat($data), LOCK_EX);
|
||||
}
|
||||
@@ -235,19 +249,23 @@ class Manager
|
||||
*
|
||||
* @param string | array $path
|
||||
* @param string $content JSON string
|
||||
* @param bool $isJSON
|
||||
* @param bool $isReturnJson
|
||||
* @param string | array $removeOptions - List of unset keys from content
|
||||
* @param bool $isReturn - Is result to be returned or stored
|
||||
* @param bool $isPhp - Is merge php files
|
||||
*
|
||||
* @return bool | array
|
||||
*/
|
||||
public function mergeContents($path, $content, $isJSON = false, $removeOptions = null, $isReturn = false)
|
||||
public function mergeContents($path, $content, $isReturnJson = false, $removeOptions = null, $isPhp = false)
|
||||
{
|
||||
$fileContent = $this->getContents($path);
|
||||
if ($isPhp) {
|
||||
$fileContent = $this->getPhpContents($path);
|
||||
} else {
|
||||
$fileContent = $this->getContents($path);
|
||||
}
|
||||
|
||||
$fullPath = $this->concatPaths($path);
|
||||
if (file_exists($fullPath) && ($fileContent === false || empty($fileContent))) {
|
||||
throw new Error('Failed to read file [' . $fullPath .'].');
|
||||
throw new Error('FileManager: Failed to read file [' . $fullPath .'].');
|
||||
}
|
||||
|
||||
$savedDataArray = Utils\Json::getArrayData($fileContent);
|
||||
@@ -259,12 +277,13 @@ class Manager
|
||||
}
|
||||
|
||||
$data = Utils\Util::merge($savedDataArray, $newDataArray);
|
||||
if ($isJSON) {
|
||||
|
||||
if ($isReturnJson) {
|
||||
$data = Utils\Json::encode($data, JSON_PRETTY_PRINT);
|
||||
}
|
||||
|
||||
if ($isReturn) {
|
||||
return $data;
|
||||
if ($isPhp) {
|
||||
return $this->putPhpContents($path, $data);
|
||||
}
|
||||
|
||||
return $this->putContents($path, $data);
|
||||
@@ -278,11 +297,9 @@ class Manager
|
||||
* @param string | array $removeOptions - List of unset keys from content
|
||||
* @return bool
|
||||
*/
|
||||
public function mergeContentsPHP($path, $content, $removeOptions = null)
|
||||
public function mergePhpContents($path, $content, $removeOptions = null)
|
||||
{
|
||||
$data = $this->mergeContents($path, $content, false, $removeOptions, true);
|
||||
|
||||
return $this->putContentsPHP($path, $data);
|
||||
return $this->mergeContents($path, $content, false, $removeOptions, true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -220,7 +220,6 @@ class Language
|
||||
}
|
||||
|
||||
$this->clearChanges();
|
||||
$this->init(true);
|
||||
|
||||
return (bool) $result;
|
||||
}
|
||||
@@ -234,6 +233,7 @@ class Language
|
||||
{
|
||||
$this->changedData = array();
|
||||
$this->deletedData = array();
|
||||
$this->init(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -253,53 +253,76 @@ class Language
|
||||
|
||||
/**
|
||||
* Set/change a label
|
||||
* @param string | array $label
|
||||
* @param mixed $value
|
||||
* @param string $category
|
||||
*
|
||||
* @param string $scope
|
||||
* @param string $category
|
||||
* @param string | array $name
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set($label, $value, $category = 'labels', $scope = 'Global')
|
||||
public function set($scope, $category, $name, $value)
|
||||
{
|
||||
if (is_array($label)) {
|
||||
foreach ($label as $rowLabel => $rowValue) {
|
||||
$this->set($rowLabel, $rowValue, $category, $scope);
|
||||
if (is_array($name)) {
|
||||
foreach ($name as $rowLabel => $rowValue) {
|
||||
$this->set($scope, $category, $rowLabel, $rowValue);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$this->changedData[$scope][$category][$label] = $value;
|
||||
$this->changedData[$scope][$category][$name] = $value;
|
||||
|
||||
$currentLanguage = $this->getLanguage();
|
||||
$this->data[$currentLanguage][$scope][$category][$label] = $value;
|
||||
if (!isset($this->data[$currentLanguage])) {
|
||||
$this->init();
|
||||
}
|
||||
$this->data[$currentLanguage][$scope][$category][$name] = $value;
|
||||
|
||||
$this->undelete($scope, $category, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a label
|
||||
*
|
||||
* @param string $label
|
||||
* @param string $name
|
||||
* @param string $category
|
||||
* @param string $scope
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete($label, $category = 'labels', $scope = 'Global')
|
||||
public function delete($scope, $category, $name)
|
||||
{
|
||||
if (is_array($label)) {
|
||||
foreach ($label as $rowLabel) {
|
||||
$this->delete($rowLabel, $category, $scope);
|
||||
if (is_array($name)) {
|
||||
foreach ($name as $rowLabel) {
|
||||
$this->delete($scope, $category, $rowLabel);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$this->deletedData[$scope][$category][] = $label;
|
||||
$this->deletedData[$scope][$category][] = $name;
|
||||
|
||||
$currentLanguage = $this->getLanguage();
|
||||
if (isset($this->data[$currentLanguage][$scope][$category][$label])) {
|
||||
unset($this->data[$currentLanguage][$scope][$category][$label]);
|
||||
if (!isset($this->data[$currentLanguage])) {
|
||||
$this->init();
|
||||
}
|
||||
|
||||
if (isset($this->changedData[$scope][$category][$label])) {
|
||||
unset($this->changedData[$scope][$category][$label]);
|
||||
if (isset($this->data[$currentLanguage][$scope][$category][$name])) {
|
||||
unset($this->data[$currentLanguage][$scope][$category][$name]);
|
||||
}
|
||||
|
||||
if (isset($this->changedData[$scope][$category][$name])) {
|
||||
unset($this->changedData[$scope][$category][$name]);
|
||||
}
|
||||
}
|
||||
|
||||
protected function undelete($scope, $category, $name)
|
||||
{
|
||||
if (isset($this->deletedData[$scope][$category])) {
|
||||
foreach ($this->deletedData[$scope][$category] as $key => $labelName) {
|
||||
if ($name === $labelName) {
|
||||
unset($this->deletedData[$scope][$category][$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,7 +342,7 @@ class Language
|
||||
|
||||
if ($this->getConfig()->get('useCache')) {
|
||||
$i18nCacheFile = str_replace('{*}', $i18nName, $this->cacheFile);
|
||||
$result &= $this->getFileManager()->putContentsPHP($i18nCacheFile, $i18nData);
|
||||
$result &= $this->getFileManager()->putPhpContents($i18nCacheFile, $i18nData);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,7 +353,7 @@ class Language
|
||||
|
||||
$currentLanguage = $this->getLanguage();
|
||||
if (empty($this->data[$currentLanguage])) {
|
||||
$this->data[$currentLanguage] = $this->getFileManager()->getContents($this->getLangCacheFile());
|
||||
$this->data[$currentLanguage] = $this->getFileManager()->getPhpContents($this->getLangCacheFile());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,23 +18,26 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Utils;
|
||||
|
||||
class Layout
|
||||
{
|
||||
private $fileManager;
|
||||
private $metadata;
|
||||
|
||||
|
||||
private $metadata;
|
||||
|
||||
private $changedData = array();
|
||||
|
||||
/**
|
||||
* @var string - uses for loading default values
|
||||
*/
|
||||
private $name = 'layout';
|
||||
private $name = 'layout';
|
||||
|
||||
protected $params = array(
|
||||
protected $params = array(
|
||||
'defaultsPath' => 'application/Espo/Core/defaults',
|
||||
);
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
@@ -42,10 +45,10 @@ class Layout
|
||||
*/
|
||||
private $paths = array(
|
||||
'corePath' => 'application/Espo/Resources/layouts',
|
||||
'modulePath' => 'application/Espo/Modules/{*}/Resources/layouts',
|
||||
'customPath' => 'custom/Espo/Custom/Resources/layouts',
|
||||
);
|
||||
|
||||
'modulePath' => 'application/Espo/Modules/{*}/Resources/layouts',
|
||||
'customPath' => 'custom/Espo/Custom/Resources/layouts',
|
||||
);
|
||||
|
||||
|
||||
public function __construct(\Espo\Core\Utils\File\Manager $fileManager, \Espo\Core\Utils\Metadata $metadata)
|
||||
{
|
||||
@@ -63,7 +66,6 @@ class Layout
|
||||
return $this->metadata;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get Layout context
|
||||
*
|
||||
@@ -73,13 +75,17 @@ class Layout
|
||||
* @return json
|
||||
*/
|
||||
public function get($controller, $name)
|
||||
{
|
||||
$fileFullPath = Util::concatPath($this->getLayoutPath($controller, true), $name.'.json');
|
||||
if (!file_exists($fileFullPath)) {
|
||||
$fileFullPath = Util::concatPath($this->getLayoutPath($controller), $name.'.json');
|
||||
}
|
||||
{
|
||||
if (isset($this->changedData[$controller][$name])) {
|
||||
return Json::encode($this->changedData[$controller][$name]);
|
||||
}
|
||||
|
||||
if (!file_exists($fileFullPath)) {
|
||||
$fileFullPath = Util::concatPath($this->getLayoutPath($controller, true), $name.'.json');
|
||||
if (!file_exists($fileFullPath)) {
|
||||
$fileFullPath = Util::concatPath($this->getLayoutPath($controller), $name.'.json');
|
||||
}
|
||||
|
||||
if (!file_exists($fileFullPath)) {
|
||||
//load defaults
|
||||
$defaultPath = $this->params['defaultsPath'];
|
||||
$fileFullPath = Util::concatPath( Util::concatPath($defaultPath, $this->name), $name.'.json' );
|
||||
@@ -91,34 +97,68 @@ class Layout
|
||||
}
|
||||
|
||||
return $this->getFileManager()->getContents($fileFullPath);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Layout data
|
||||
* Ex. $controller= Account, $name= detail then will be created a file layoutFolder/Account/detail.json
|
||||
* Ex. $controller = Account, $name = detail then will be created a file layoutFolder/Account/detail.json
|
||||
*
|
||||
* @param JSON string $data
|
||||
* @param array $data
|
||||
* @param string $controller - ex. Account
|
||||
* @param string $name - detail
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set($data, $controller, $name)
|
||||
{
|
||||
if (empty($controller) || empty($name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$layoutPath = $this->getLayoutPath($controller, true);
|
||||
|
||||
if (!Json::isJSON($data)) {
|
||||
$data = Json::encode($data);
|
||||
}
|
||||
|
||||
return $this->getFileManager()->putContents(array($layoutPath, $name.'.json'), $data);
|
||||
$this->changedData[$controller][$name] = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save changes
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
$result = true;
|
||||
|
||||
if (!empty($this->changedData)) {
|
||||
foreach ($this->changedData as $controllerName => $rowData) {
|
||||
foreach ($rowData as $layoutName => $layoutData) {
|
||||
|
||||
if (empty($controllerName) || empty($layoutName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$layoutPath = $this->getLayoutPath($controllerName, true);
|
||||
$data = Json::encode($layoutData);
|
||||
|
||||
$result &= $this->getFileManager()->putContents(array($layoutPath, $layoutName.'.json'), $data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($result == true) {
|
||||
$this->clearChanges();
|
||||
}
|
||||
|
||||
return (bool) $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear unsaved changes
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function clearChanges()
|
||||
{
|
||||
$this->changedData = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge layout data
|
||||
@@ -133,15 +173,15 @@ class Layout
|
||||
public function merge($data, $controller, $name)
|
||||
{
|
||||
$prevData = $this->get($controller, $name);
|
||||
|
||||
$prevDataArray= Json::getArrayData($prevData);
|
||||
$dataArray= Json::getArrayData($data);
|
||||
|
||||
$data= Util::merge($prevDataArray, $dataArray);
|
||||
$data= Json::encode($data);
|
||||
$prevDataArray = Json::getArrayData($prevData);
|
||||
$dataArray = Json::getArrayData($data);
|
||||
|
||||
$data = Util::merge($prevDataArray, $dataArray);
|
||||
$data = Json::encode($data);
|
||||
|
||||
return $this->set($data, $controller, $name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Layout path, ex. application/Modules/Crm/Layouts/Account
|
||||
@@ -152,23 +192,23 @@ class Layout
|
||||
* @return string
|
||||
*/
|
||||
protected function getLayoutPath($entityName, $isCustom = false)
|
||||
{
|
||||
$path = $this->paths['customPath'];
|
||||
{
|
||||
$path = $this->paths['customPath'];
|
||||
|
||||
if (!$isCustom) {
|
||||
$moduleName = $this->getMetadata()->getScopeModuleName($entityName);
|
||||
|
||||
|
||||
$path = $this->paths['corePath'];
|
||||
if ($moduleName !== false) {
|
||||
$path = str_replace('{*}', $moduleName, $this->paths['modulePath']);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
$path = Util::concatPath($path, $entityName);
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,10 @@ class Metadata
|
||||
*/
|
||||
protected $defaultModuleOrder = 10;
|
||||
|
||||
private $deletedData = array();
|
||||
|
||||
private $changedData = array();
|
||||
|
||||
public function __construct(\Espo\Core\Utils\Config $config, \Espo\Core\Utils\File\Manager $fileManager)
|
||||
{
|
||||
$this->config = $config;
|
||||
@@ -124,13 +128,13 @@ class Metadata
|
||||
}
|
||||
|
||||
if (file_exists($this->cacheFile) && !$reload) {
|
||||
$this->meta = $this->getFileManager()->getContents($this->cacheFile);
|
||||
$this->meta = $this->getFileManager()->getPhpContents($this->cacheFile);
|
||||
} else {
|
||||
$this->meta = $this->getUnifier()->unify($this->name, $this->paths, true);
|
||||
$this->meta = $this->setLanguageFromConfig($this->meta);
|
||||
|
||||
if ($this->getConfig()->get('useCache')) {
|
||||
$isSaved = $this->getFileManager()->putContentsPHP($this->cacheFile, $this->meta);
|
||||
$isSaved = $this->getFileManager()->putPhpContents($this->cacheFile, $this->meta);
|
||||
if ($isSaved === false) {
|
||||
$GLOBALS['log']->emergency('Metadata:init() - metadata has not been saved to a cache file');
|
||||
}
|
||||
@@ -213,52 +217,139 @@ class Metadata
|
||||
|
||||
/**
|
||||
* Set Metadata data
|
||||
* Ex. $type= menu, $scope= Account then will be created a file metadataFolder/menu/Account.json
|
||||
* Ex. $key1 = menu, $key2 = Account then will be created a file metadataFolder/menu/Account.json
|
||||
*
|
||||
* @param string $key1
|
||||
* @param string $key2
|
||||
* @param JSON string $data
|
||||
* @param string $type - ex. menu
|
||||
* @param string $scope - Account
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function set($data, $type, $scope)
|
||||
public function set($key1, $key2, $data)
|
||||
{
|
||||
$path = $this->paths['customPath'];
|
||||
$newData = array(
|
||||
$key1 => array(
|
||||
$key2 => $data,
|
||||
),
|
||||
);
|
||||
|
||||
$result = $this->getFileManager()->mergeContents(array($path, $type, $scope.'.json'), $data, true);
|
||||
if ($result === false) {
|
||||
throw new Error("Error saving metadata. See log file for details.");
|
||||
}
|
||||
$this->changedData = Util::merge($this->changedData, $newData);
|
||||
$this->meta = Util::merge($this->getData(), $newData);
|
||||
|
||||
$this->init(true);
|
||||
|
||||
return $result;
|
||||
$this->undelete($key1, $key2, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unset some fields and other stuff in metadat
|
||||
*
|
||||
* @param string $key1
|
||||
* @param string $key2
|
||||
* @param array | string $unsets Ex. 'fields.name'
|
||||
* @param string $type Ex. 'entityDefs'
|
||||
* @param string $scope
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function delete($unsets, $type, $scope)
|
||||
public function delete($key1, $key2, $unsets)
|
||||
{
|
||||
if (!is_array($unsets)) {
|
||||
$unsets = (array) $unsets;
|
||||
}
|
||||
|
||||
$normalizedData = array(
|
||||
'__APPEND__',
|
||||
);
|
||||
$metaUnsetData = array();
|
||||
foreach ($unsets as $unsetItem) {
|
||||
$normalizedData[] = $unsetItem;
|
||||
$metaUnsetData[] = implode('.', array($key1, $key2, $unsetItem));
|
||||
}
|
||||
|
||||
$unsetData = array(
|
||||
$key1 => array(
|
||||
$key2 => $normalizedData,
|
||||
),
|
||||
);
|
||||
|
||||
$this->deletedData = Util::merge($this->deletedData, $unsetData);
|
||||
$this->deletedData = Util::unsetInArrayByValue('__APPEND__', $this->deletedData);
|
||||
|
||||
$this->meta = Util::unsetInArray($this->getData(), $metaUnsetData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Undelete the deleted items
|
||||
*
|
||||
* @param string $key1
|
||||
* @param string $key2
|
||||
* @param array $data
|
||||
* @return void
|
||||
*/
|
||||
protected function undelete($key1, $key2, $data)
|
||||
{
|
||||
if (isset($this->deletedData[$key1][$key2])) {
|
||||
foreach ($this->deletedData[$key1][$key2] as $unsetIndex => $unsetItem) {
|
||||
$value = Util::getValueByKey($data, $unsetItem);
|
||||
if (isset($value)) {
|
||||
unset($this->deletedData[$key1][$key2][$unsetIndex]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear unsaved changes
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function clearChanges()
|
||||
{
|
||||
$this->changedData = array();
|
||||
$this->deletedData = array();
|
||||
$this->init(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save changes
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
$path = $this->paths['customPath'];
|
||||
|
||||
$result = $this->getFileManager()->unsetContents(array($path, $type, $scope.'.json'), $unsets, true);
|
||||
|
||||
if ($result == false) {
|
||||
$GLOBALS['log']->warning('Delete metadata items available only for custom code.');
|
||||
$result = true;
|
||||
if (!empty($this->changedData)) {
|
||||
foreach ($this->changedData as $key1 => $keyData) {
|
||||
foreach ($keyData as $key2 => $data) {
|
||||
if (!empty($data)) {
|
||||
$result &= $this->getFileManager()->mergeContents(array($path, $key1, $key2.'.json'), $data, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->init(true);
|
||||
if (!empty($this->deletedData)) {
|
||||
foreach ($this->deletedData as $key1 => $keyData) {
|
||||
foreach ($keyData as $key2 => $unsetData) {
|
||||
if (!empty($unsetData)) {
|
||||
$rowResult = $this->getFileManager()->unsetContents(array($path, $key1, $key2.'.json'), $unsetData, true);
|
||||
if ($rowResult == false) {
|
||||
$GLOBALS['log']->warning('Metadata items ['.$key1.'.'.$key2.'] can be deleted for custom code only.');
|
||||
}
|
||||
$result &= $rowResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
if ($result == false) {
|
||||
throw new Error("Error saving metadata. See log file for details.");
|
||||
}
|
||||
|
||||
$this->clearChanges();
|
||||
|
||||
return (bool) $result;
|
||||
}
|
||||
|
||||
|
||||
public function getOrmMetadata($reload = false)
|
||||
{
|
||||
if (!empty($this->ormMeta) && is_array($this->ormMeta) && !$reload) {
|
||||
@@ -270,7 +361,7 @@ class Metadata
|
||||
}
|
||||
|
||||
if (empty($this->ormMeta)) {
|
||||
$this->ormMeta = $this->getFileManager()->getContents($this->ormCacheFile);
|
||||
$this->ormMeta = $this->getFileManager()->getPhpContents($this->ormCacheFile);
|
||||
}
|
||||
|
||||
return $this->ormMeta;
|
||||
@@ -279,7 +370,7 @@ class Metadata
|
||||
public function setOrmMetadata(array $ormMeta)
|
||||
{
|
||||
if ($this->getConfig()->get('useCache')) {
|
||||
$result = $this->getFileManager()->putContentsPHP($this->ormCacheFile, $ormMeta);
|
||||
$result = $this->getFileManager()->putPhpContents($this->ormCacheFile, $ormMeta);
|
||||
if ($result == false) {
|
||||
throw new \Espo\Core\Exceptions\Error('Metadata::setOrmMetadata() - Cannot save ormMetadata to a file');
|
||||
}
|
||||
|
||||
@@ -84,12 +84,12 @@ class Module
|
||||
protected function init()
|
||||
{
|
||||
if (file_exists($this->cacheFile) && $this->getConfig()->get('useCache')) {
|
||||
$this->data = $this->getFileManager()->getContents($this->cacheFile);
|
||||
$this->data = $this->getFileManager()->getPhpContents($this->cacheFile);
|
||||
} else {
|
||||
$this->data = $this->getUnifier()->unify($this->paths, true);
|
||||
|
||||
if ($this->getConfig()->get('useCache')) {
|
||||
$result = $this->getFileManager()->putContentsPHP($this->cacheFile, $this->data);
|
||||
$result = $this->getFileManager()->putPhpContents($this->cacheFile, $this->data);
|
||||
if ($result == false) {
|
||||
throw new \Espo\Core\Exceptions\Error('Module - Cannot save unified modules.');
|
||||
}
|
||||
|
||||
@@ -95,12 +95,12 @@ class Route
|
||||
protected function init()
|
||||
{
|
||||
if (file_exists($this->cacheFile) && $this->getConfig()->get('useCache')) {
|
||||
$this->data = $this->getFileManager()->getContents($this->cacheFile);
|
||||
$this->data = $this->getFileManager()->getPhpContents($this->cacheFile);
|
||||
} else {
|
||||
$this->data = $this->unify();
|
||||
|
||||
if ($this->getConfig()->get('useCache')) {
|
||||
$result = $this->getFileManager()->putContentsPHP($this->cacheFile, $this->data);
|
||||
$result = $this->getFileManager()->putPhpContents($this->cacheFile, $this->data);
|
||||
if ($result == false) {
|
||||
throw new \Espo\Core\Exceptions\Error('Route - Cannot save unified routes');
|
||||
}
|
||||
@@ -127,7 +127,7 @@ class Route
|
||||
protected function getAddData($currData, $routeFile)
|
||||
{
|
||||
if (file_exists($routeFile)) {
|
||||
$content= $this->getFileManager()->getContents($routeFile);
|
||||
$content = $this->getFileManager()->getContents($routeFile);
|
||||
$arrayContent = Json::getArrayData($content);
|
||||
if (empty($arrayContent)) {
|
||||
$GLOBALS['log']->error('Route::unify() - Empty file or syntax error - ['.$routeFile.']');
|
||||
|
||||
@@ -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/.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\EntryPoints;
|
||||
|
||||
use \Espo\Core\Exceptions\NotFound;
|
||||
use \Espo\Core\Exceptions\Forbidden;
|
||||
use \Espo\Core\Exceptions\BadRequest;
|
||||
|
||||
class OauthCallback extends \Espo\Core\EntryPoints\Base
|
||||
{
|
||||
public static $authRequired = false;
|
||||
|
||||
public function run()
|
||||
{
|
||||
echo "EspoCRM rocks !!!";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[
|
||||
{"name":"name", "width": 32, "link": true},
|
||||
{"name":"account"},
|
||||
{"name":"stage"},
|
||||
{"name":"amount"},
|
||||
{"name":"createdAt"}
|
||||
]
|
||||
@@ -5,7 +5,7 @@
|
||||
},
|
||||
"salutationName": {
|
||||
"type": "enum",
|
||||
"options": ["", "Mr.", "Mrs.", "Dr.", "Drs."]
|
||||
"options": ["", "Mr.", "Mrs.", "Dr."]
|
||||
},
|
||||
"firstName": {
|
||||
"type": "varchar",
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
},
|
||||
"salutationName": {
|
||||
"type": "enum",
|
||||
"options": ["", "Mr.", "Mrs.", "Dr.", "Drs."]
|
||||
"options": ["", "Mr.", "Mrs.", "Dr."]
|
||||
},
|
||||
"firstName": {
|
||||
"type": "varchar",
|
||||
|
||||
@@ -132,7 +132,8 @@
|
||||
"authTokens": "Active auth sessions. IP address and last access date.",
|
||||
"authentication": "Authentication settings.",
|
||||
"currency": "Currency settings and rates.",
|
||||
"extensions": "Install or uninstall extensions."
|
||||
"extensions": "Install or uninstall extensions.",
|
||||
"integrations": "Integration with third-party services."
|
||||
},
|
||||
"options": {
|
||||
"previewSize": {
|
||||
|
||||
@@ -235,8 +235,7 @@
|
||||
"salutationName": {
|
||||
"Mr.": "Mr.",
|
||||
"Mrs.": "Mrs.",
|
||||
"Dr.": "Dr.",
|
||||
"Drs.": "Drs."
|
||||
"Dr.": "Dr."
|
||||
},
|
||||
"language": {
|
||||
"af_ZA":"Afrikaans",
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
"redirectUri": "Redirect URI"
|
||||
},
|
||||
"messages": {
|
||||
"selectIntegration": "Select an integration in menu."
|
||||
"selectIntegration": "Select an integration from menu.",
|
||||
"noIntegrations": "No Integrations is available."
|
||||
},
|
||||
"help": {
|
||||
"Google": "<p><b>Obtain OAuth 2.0 credentials from the Google Developers Console.</b></p><p>Visit <a href=\"https://console.developers.google.com/project\">Google Developers Console</a> to obtain OAuth 2.0 credentials such as a Client ID and Client Secret that are known to both Google and EspoCRM application.</p>"
|
||||
|
||||
@@ -28,7 +28,8 @@
|
||||
"Teams and Access Control": "Teams and Access Control",
|
||||
"Forgot Password?": "Forgot Password?",
|
||||
"Password Change Request": "Password Change Request",
|
||||
"Email Address": "Email Address"
|
||||
"Email Address": "Email Address",
|
||||
"External Accounts": "External Accounts"
|
||||
},
|
||||
"tooltips": {
|
||||
"defaultTeam": "All records created by this user will be related to this team by default.",
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"users": "Usuários"
|
||||
},
|
||||
"tooltips": {
|
||||
"roles": "Todos os usuários deste time terão acesso as configurações das regras selecionadas."
|
||||
"roles": "Todos os usuários deste time terão acesso as configurações das regras selecionadas.",
|
||||
"positionList": "Posições disponíveis neste time. E.g. Vendedor, Gerente."
|
||||
},
|
||||
"labels": {
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
"messages": {
|
||||
"passwordWillBeSent": "A senha será enviada para o email do usuário.",
|
||||
"accountInfoEmailSubject": "Informações da Conta",
|
||||
"accountInfoEmailBody": "Informações da sua conta:\n\nUsuário: {userName}\nSenha: {password}\n\n{siteUrl}",,
|
||||
"accountInfoEmailBody": "Informações da sua conta:\n\nUsuário: {userName}\nSenha: {password}\n\n{siteUrl}",
|
||||
"passwordChangeLinkEmailSubject": "Solicitação para troca da senha",
|
||||
"passwordChangeLinkEmailBody": "Você pode atualizar sua senha usando este link {link}. Esta URL é única e expirará em breve.",
|
||||
"passwordChanged": "A senha foi atualizada",
|
||||
|
||||
@@ -22,6 +22,11 @@
|
||||
"label":"Currency",
|
||||
"description":"currency"
|
||||
},
|
||||
{
|
||||
"url":"#Admin/integrations",
|
||||
"label":"Integrations",
|
||||
"description":"integrations"
|
||||
},
|
||||
{
|
||||
"url":"#Admin/upgrade",
|
||||
"label":"Upgrade",
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
},
|
||||
"salutationName": {
|
||||
"type": "enum",
|
||||
"options": ["", "Mr.", "Mrs.", "Dr.", "Drs."]
|
||||
"options": ["", "Mr.", "Mrs.", "Dr."]
|
||||
},
|
||||
"firstName": {
|
||||
"type": "varchar",
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"fields": {
|
||||
"clientId": {
|
||||
"type": "varchar",
|
||||
"maxLength": 255,
|
||||
"required": true
|
||||
},
|
||||
"clientSecret": {
|
||||
"type": "varchar",
|
||||
"maxLength": 255,
|
||||
"required": true
|
||||
}
|
||||
},
|
||||
"params": {
|
||||
"endpoint": "https://accounts.google.com/o/oauth2/auth",
|
||||
"tokenEndpoint": "https://accounts.google.com/o/oauth2/token",
|
||||
"scope": "https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/calendar"
|
||||
},
|
||||
"allowUserAccounts": true,
|
||||
"authMethod": "OAuth2",
|
||||
"clientClassName": "\\Espo\\Core\\ExternalAccount\\Clients\\Google"
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="page-header">
|
||||
<h3>EspoCRM - Open Source CRM application</h3>
|
||||
<h3>EspoCRM - Open Source CRM application</h3>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
@@ -8,19 +8,19 @@
|
||||
<strong>Version {{version}}</strong>
|
||||
</p>
|
||||
<p>
|
||||
Copyright © 2014 EspoCRM: Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko.
|
||||
Copyright © 2014-2015 EspoCRM: Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko.
|
||||
<br>
|
||||
Website: <a href="http://www.espocrm.com">http://www.espocrm.com</a>.
|
||||
</p>
|
||||
</p>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
</p>
|
||||
<p>
|
||||
EspoCRM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||
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.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -78,7 +78,12 @@ Espo.define('Views.Admin.Integrations.Index', 'View', function (Dep) {
|
||||
|
||||
renderDefaultPage: function () {
|
||||
$('#integration-header').html('').hide();
|
||||
$('#integration-content').html(this.translate('selectIntegration', 'messages', 'Integration'));
|
||||
if (this.integrationList.length) {
|
||||
var msg = this.translate('selectIntegration', 'messages', 'Integration');
|
||||
} else {
|
||||
var msg = '<p class="lead">' + this.translate('noIntegrations', 'messages', 'Integration') + '</p>';
|
||||
}
|
||||
$('#integration-content').html(msg);
|
||||
},
|
||||
|
||||
renderHeader: function () {
|
||||
|
||||
@@ -17,22 +17,22 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
************************************************************************/
|
||||
|
||||
Espo.define('Views.Admin.Integrations.OAuth2', 'Views.Admin.Integrations.Edit', function (Dep) {
|
||||
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
|
||||
template: 'admin.integrations.oauth2',
|
||||
|
||||
|
||||
data: function () {
|
||||
|
||||
|
||||
return _.extend({
|
||||
// TODO fetch from server
|
||||
redirectUri: this.getConfig().get('siteUrl') + '/oauthcallback'
|
||||
redirectUri: this.getConfig().get('siteUrl') + '?entryPoint=oauthCallback'
|
||||
}, Dep.prototype.data.call(this));
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -40,38 +40,38 @@ Espo.define('Views.ExternalAccount.Index', 'View', function (Dep) {
|
||||
},
|
||||
},
|
||||
|
||||
setup: function () {
|
||||
setup: function () {
|
||||
this.externalAccountList = this.collection.toJSON();
|
||||
|
||||
|
||||
this.userId = this.getUser().id;
|
||||
this.id = this.options.id || null;
|
||||
this.id = this.options.id || null;
|
||||
if (this.id) {
|
||||
this.userId = this.id.split('__')[1];
|
||||
}
|
||||
|
||||
this.on('after:render', function () {
|
||||
this.renderHeader();
|
||||
|
||||
this.on('after:render', function () {
|
||||
this.renderHeader();
|
||||
if (!this.id) {
|
||||
this.renderDefaultPage();
|
||||
} else {
|
||||
this.openExternalAccount(this.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
openExternalAccount: function (id) {
|
||||
this.id = id;
|
||||
|
||||
|
||||
var integration = this.integration = id.split('__')[0];
|
||||
this.userId = id.split('__')[1];
|
||||
|
||||
this.getRouter().navigate('#ExternalAccount/edit/' + id, {trigger: false});
|
||||
|
||||
var viewName =
|
||||
this.getMetadata().get('integrations.' + integration + '.userView') ||
|
||||
'ExternalAccount.' + this.getMetadata().get('integrations.' + integration + '.authMethod');
|
||||
|
||||
this.notify('Loading...');
|
||||
this.getRouter().navigate('#ExternalAccount/edit/' + id, {trigger: false});
|
||||
|
||||
var viewName =
|
||||
this.getMetadata().get('integrations.' + integration + '.userView') ||
|
||||
'ExternalAccount.' + this.getMetadata().get('integrations.' + integration + '.authMethod');
|
||||
|
||||
this.notify('Loading...');
|
||||
this.createView('content', viewName, {
|
||||
el: '#external-account-content',
|
||||
id: id,
|
||||
@@ -79,10 +79,10 @@ Espo.define('Views.ExternalAccount.Index', 'View', function (Dep) {
|
||||
}, function (view) {
|
||||
this.renderHeader();
|
||||
view.render();
|
||||
this.notify(false);
|
||||
this.notify(false);
|
||||
$(window).scrollTop(0);
|
||||
}.bind(this));
|
||||
},
|
||||
},
|
||||
|
||||
renderDefaultPage: function () {
|
||||
$('#external-account-header').html('').hide();
|
||||
|
||||
@@ -17,18 +17,18 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
************************************************************************/
|
||||
|
||||
Espo.define('Views.ExternalAccount.OAuth2', 'View', function (Dep) {
|
||||
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
|
||||
template: 'external-account.oauth2',
|
||||
|
||||
|
||||
events: {
|
||||
|
||||
},
|
||||
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
integration: this.integration,
|
||||
@@ -36,9 +36,9 @@ Espo.define('Views.ExternalAccount.OAuth2', 'View', function (Dep) {
|
||||
isConnected: this.isConnected
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
isConnected: false,
|
||||
|
||||
|
||||
events: {
|
||||
'click button[data-action="cancel"]': function () {
|
||||
this.getRouter().navigate('#ExternalAccount', {trigger: true});
|
||||
@@ -50,26 +50,25 @@ Espo.define('Views.ExternalAccount.OAuth2', 'View', function (Dep) {
|
||||
this.connect();
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
setup: function () {
|
||||
this.integration = this.options.integration;
|
||||
this.id = this.options.id;
|
||||
|
||||
|
||||
|
||||
this.helpText = false;
|
||||
if (this.getLanguage().has(this.integration, 'help', 'ExternalAccount')) {
|
||||
this.helpText = this.translate(this.integration, 'help', 'ExternalAccount');
|
||||
}
|
||||
|
||||
|
||||
this.fieldList = [];
|
||||
|
||||
this.dataFieldList = [];
|
||||
|
||||
|
||||
this.dataFieldList = [];
|
||||
|
||||
this.model = new Espo.Model();
|
||||
this.model.id = this.id;
|
||||
this.model.name = 'ExternalAccount';
|
||||
this.model.urlRoot = 'ExternalAccount';
|
||||
|
||||
|
||||
this.model.defs = {
|
||||
fields: {
|
||||
enabled: {
|
||||
@@ -77,32 +76,32 @@ Espo.define('Views.ExternalAccount.OAuth2', 'View', function (Dep) {
|
||||
type: 'bool'
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
this.wait(true);
|
||||
|
||||
};
|
||||
|
||||
this.wait(true);
|
||||
|
||||
this.model.populateDefaults();
|
||||
|
||||
|
||||
this.listenToOnce(this.model, 'sync', function () {
|
||||
this.createFieldView('bool', 'enabled');
|
||||
|
||||
|
||||
$.ajax({
|
||||
url: 'ExternalAccount/action/getOAuth2Info?id=' + this.id,
|
||||
dataType: 'json'
|
||||
}).done(function (respose) {
|
||||
this.clientId = respose.clientId;
|
||||
this.redirectUri = respose.redirectUri;
|
||||
if (respose.isConnected) {
|
||||
this.redirectUri = respose.redirectUri;
|
||||
if (respose.isConnected) {
|
||||
this.isConnected = true;
|
||||
}
|
||||
this.wait(false);
|
||||
}
|
||||
this.wait(false);
|
||||
}.bind(this));
|
||||
|
||||
|
||||
}, this);
|
||||
|
||||
this.model.fetch();
|
||||
|
||||
this.model.fetch();
|
||||
},
|
||||
|
||||
|
||||
hideField: function (name) {
|
||||
this.$el.find('label.field-label-' + name).addClass('hide');
|
||||
this.$el.find('div.field-' + name).addClass('hide');
|
||||
@@ -111,7 +110,7 @@ Espo.define('Views.ExternalAccount.OAuth2', 'View', function (Dep) {
|
||||
view.enabled = false;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
showField: function (name) {
|
||||
this.$el.find('label.field-label-' + name).removeClass('hide');
|
||||
this.$el.find('div.field-' + name).removeClass('hide');
|
||||
@@ -120,12 +119,12 @@ Espo.define('Views.ExternalAccount.OAuth2', 'View', function (Dep) {
|
||||
view.enabled = true;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
afterRender: function () {
|
||||
if (!this.model.get('enabled')) {
|
||||
this.$el.find('.data-panel').addClass('hidden');
|
||||
}
|
||||
|
||||
|
||||
this.listenTo(this.model, 'change:enabled', function () {
|
||||
if (this.model.get('enabled')) {
|
||||
this.$el.find('.data-panel').removeClass('hidden');
|
||||
@@ -134,7 +133,7 @@ Espo.define('Views.ExternalAccount.OAuth2', 'View', function (Dep) {
|
||||
}
|
||||
}, this);
|
||||
},
|
||||
|
||||
|
||||
createFieldView: function (type, name, readOnly, params) {
|
||||
this.createView(name, this.getFieldManager().getViewName(type), {
|
||||
model: this.model,
|
||||
@@ -148,45 +147,45 @@ Espo.define('Views.ExternalAccount.OAuth2', 'View', function (Dep) {
|
||||
});
|
||||
this.fieldList.push(name);
|
||||
},
|
||||
|
||||
|
||||
save: function () {
|
||||
this.fieldList.forEach(function (field) {
|
||||
var view = this.getView(field);
|
||||
if (!view.readOnly) {
|
||||
view.fetchToModel();
|
||||
}
|
||||
}, this);
|
||||
|
||||
}, this);
|
||||
|
||||
var notValid = false;
|
||||
this.fieldList.forEach(function (field) {
|
||||
notValid = this.getView(field).validate() || notValid;
|
||||
}, this);
|
||||
|
||||
|
||||
if (notValid) {
|
||||
this.notify('Not valid', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
this.listenToOnce(this.model, 'sync', function () {
|
||||
}
|
||||
|
||||
this.listenToOnce(this.model, 'sync', function () {
|
||||
this.notify('Saved', 'success');
|
||||
if (!this.model.get('enabled')) {
|
||||
if (!this.model.get('enabled')) {
|
||||
this.setNotConnected();
|
||||
}
|
||||
}, this);
|
||||
|
||||
|
||||
this.notify('Saving...');
|
||||
this.model.save();
|
||||
},
|
||||
|
||||
|
||||
popup: function (options, callback) {
|
||||
options.windowName = options.windowName || 'ConnectWithOAuth';
|
||||
options.windowOptions = options.windowOptions || 'location=0,status=0,width=800,height=400';
|
||||
options.callback = options.callback || function(){ window.location.reload(); };
|
||||
|
||||
|
||||
var self = this;
|
||||
|
||||
|
||||
var path = options.path;
|
||||
|
||||
|
||||
var arr = [];
|
||||
var params = (options.params || {});
|
||||
for (var name in params) {
|
||||
@@ -195,17 +194,17 @@ Espo.define('Views.ExternalAccount.OAuth2', 'View', function (Dep) {
|
||||
}
|
||||
}
|
||||
path += '?' + arr.join('&');
|
||||
|
||||
|
||||
var parseUrl = function (str) {
|
||||
var code = null;
|
||||
var error = null;
|
||||
|
||||
|
||||
str = str.substr(str.indexOf('?') + 1, str.length);
|
||||
str.split('&').forEach(function (part) {
|
||||
var arr = part.split('=');
|
||||
var name = decodeURI(arr[0]);
|
||||
var value = decodeURI(arr[1] || '');
|
||||
|
||||
|
||||
if (name == 'code') {
|
||||
code = value;
|
||||
}
|
||||
@@ -223,14 +222,14 @@ Espo.define('Views.ExternalAccount.OAuth2', 'View', function (Dep) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
popup = window.open(path, options.windowName, options.windowOptions);
|
||||
interval = window.setInterval(function () {
|
||||
if (popup.closed) {
|
||||
window.clearInterval(interval);
|
||||
} else {
|
||||
var res = parseUrl(popup.location.href.toString());
|
||||
if (res) {
|
||||
if (res) {
|
||||
callback.call(self, res);
|
||||
popup.close();
|
||||
window.clearInterval(interval);
|
||||
@@ -238,9 +237,8 @@ Espo.define('Views.ExternalAccount.OAuth2', 'View', function (Dep) {
|
||||
}
|
||||
}, 500);
|
||||
},
|
||||
|
||||
|
||||
connect: function () {
|
||||
this.notify('Please wait...');
|
||||
this.popup({
|
||||
path: this.getMetadata().get('integrations.' + this.integration + '.params.endpoint'),
|
||||
params: {
|
||||
@@ -250,7 +248,7 @@ Espo.define('Views.ExternalAccount.OAuth2', 'View', function (Dep) {
|
||||
response_type: 'code',
|
||||
access_type: 'offline',
|
||||
approval_prompt: 'force'
|
||||
}
|
||||
}
|
||||
}, function (res) {
|
||||
if (res.errror) {
|
||||
this.notify(false);
|
||||
@@ -268,35 +266,35 @@ Espo.define('Views.ExternalAccount.OAuth2', 'View', function (Dep) {
|
||||
dataType: 'json',
|
||||
error: function () {
|
||||
this.$el.find('[data-action="connect"]').removeClass('disabled');
|
||||
}.bind(this)
|
||||
}.bind(this)
|
||||
}).done(function (response) {
|
||||
this.notify(false);
|
||||
if (response === true) {
|
||||
this.setConneted();
|
||||
} else {
|
||||
this.setNotConneted();
|
||||
this.setNotConneted();
|
||||
}
|
||||
this.$el.find('[data-action="connect"]').removeClass('disabled');
|
||||
this.$el.find('[data-action="connect"]').removeClass('disabled');
|
||||
}.bind(this));
|
||||
|
||||
|
||||
} else {
|
||||
this.notify('Error occured', 'error');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
setConneted: function () {
|
||||
this.isConnected = true;
|
||||
this.$el.find('[data-action="connect"]').addClass('hidden');;
|
||||
this.$el.find('.connected-label').removeClass('hidden');
|
||||
},
|
||||
|
||||
|
||||
setNotConnected: function () {
|
||||
this.isConnected = false;
|
||||
this.$el.find('[data-action="connect"]').removeClass('hidden');;
|
||||
this.$el.find('.connected-label').addClass('hidden');
|
||||
},
|
||||
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -18,26 +18,26 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
|
||||
|
||||
Espo.define('Views.User.Record.Detail', 'Views.Record.Detail', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
|
||||
sideView: 'User.Record.DetailSide',
|
||||
|
||||
|
||||
editModeEnabled: false,
|
||||
|
||||
|
||||
setup: function () {
|
||||
Dep.prototype.setup.call(this);
|
||||
this.buttons = _.clone(this.buttons);
|
||||
|
||||
|
||||
if (this.model.id == this.getUser().id || this.getUser().isAdmin()) {
|
||||
this.buttons.push({
|
||||
name: 'preferences',
|
||||
label: 'Preferences',
|
||||
style: 'default'
|
||||
});
|
||||
|
||||
|
||||
if (!this.model.get('isAdmin')) {
|
||||
this.buttons.push({
|
||||
name: 'access',
|
||||
@@ -45,7 +45,7 @@ Espo.define('Views.User.Record.Detail', 'Views.Record.Detail', function (Dep) {
|
||||
style: 'default'
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
if (this.model.id == this.getUser().id) {
|
||||
this.buttons.push({
|
||||
name: 'changePassword',
|
||||
@@ -53,40 +53,52 @@ Espo.define('Views.User.Record.Detail', 'Views.Record.Detail', function (Dep) {
|
||||
style: 'default'
|
||||
});
|
||||
}
|
||||
|
||||
if (this.model.id == this.getUser().id) {
|
||||
this.buttons.push({
|
||||
name: 'externalAccounts',
|
||||
label: 'External Accounts',
|
||||
style: 'default'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (this.model.id == this.getUser().id) {
|
||||
this.listenTo(this.model, 'after:save', function () {
|
||||
this.getUser().set(this.model.toJSON());
|
||||
}.bind(this));
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
actionChangePassword: function () {
|
||||
this.notify('Loading...');
|
||||
|
||||
|
||||
this.createView('changePassword', 'Modals.ChangePassword', {
|
||||
userId: this.model.id
|
||||
}, function (view) {
|
||||
view.render();
|
||||
this.notify(false);
|
||||
|
||||
|
||||
this.listenToOnce(view, 'changed', function () {
|
||||
setTimeout(function () {
|
||||
this.getBaseController().logout();
|
||||
}.bind(this), 2000);
|
||||
}, this);
|
||||
|
||||
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
|
||||
actionPreferences: function () {
|
||||
this.getRouter().navigate('#Preferences/edit/' + this.model.id, {trigger: true});
|
||||
},
|
||||
|
||||
|
||||
actionExternalAccounts: function () {
|
||||
this.getRouter().navigate('#ExternalAccount', {trigger: true});
|
||||
},
|
||||
|
||||
actionAccess: function () {
|
||||
this.notify('Loading...');
|
||||
|
||||
|
||||
$.ajax({
|
||||
url: 'User/action/acl',
|
||||
type: 'GET',
|
||||
@@ -102,11 +114,11 @@ Espo.define('Views.User.Record.Detail', 'Views.Record.Detail', function (Dep) {
|
||||
view.render();
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
|
||||
|
||||
|
||||
},
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "espocrm",
|
||||
"version": "2.9.0",
|
||||
"version": "2.9.1",
|
||||
"description": "",
|
||||
"main": "index.php",
|
||||
"repository": {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?php
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
@@ -28,24 +28,24 @@ use tests\ReflectionHelper;
|
||||
class CronManagerTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
protected $object;
|
||||
|
||||
|
||||
protected $objects;
|
||||
|
||||
protected $filesPath= 'tests/testData/EntryPoints';
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
{
|
||||
$this->objects['container'] = $this->getMockBuilder('\Espo\Core\Container')->disableOriginalConstructor()->getMock();
|
||||
|
||||
$this->objects['serviceFactory'] = $this->getMockBuilder('\Espo\Core\ServiceFactory')->disableOriginalConstructor()->getMock();
|
||||
$this->objects['config'] = $this->getMockBuilder('\Espo\Core\Utils\Config')->disableOriginalConstructor()->getMock();
|
||||
$this->objects['fileManager'] = $this->getMockBuilder('\Espo\Core\Utils\File\Manager')->disableOriginalConstructor()->getMock();
|
||||
|
||||
|
||||
$this->objects['fileManager'] = $this->getMockBuilder('\Espo\Core\Utils\File\Manager')->disableOriginalConstructor()->getMock();
|
||||
|
||||
|
||||
$map = array(
|
||||
array('config', $this->objects['config']),
|
||||
array('fileManager', $this->objects['fileManager']),
|
||||
array('serviceFactory', $this->objects['serviceFactory']),
|
||||
array('serviceFactory', $this->objects['serviceFactory']),
|
||||
);
|
||||
|
||||
$this->objects['container']
|
||||
@@ -55,7 +55,7 @@ class CronManagerTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$this->object = new \Espo\Core\CronManager( $this->objects['container'] );
|
||||
|
||||
$this->reflection = new ReflectionHelper($this->object);
|
||||
$this->reflection = new ReflectionHelper($this->object);
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
@@ -68,50 +68,50 @@ class CronManagerTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$this->objects['fileManager']
|
||||
->expects($this->once())
|
||||
->method('getContents')
|
||||
->method('getPhpContents')
|
||||
->will($this->returnValue(false));
|
||||
|
||||
$this->objects['config']
|
||||
->expects($this->exactly(2))
|
||||
->method('get')
|
||||
->will($this->returnValue(50));
|
||||
|
||||
$this->assertTrue( $this->reflection->invokeMethod('checkLastRunTime', array()) );
|
||||
}
|
||||
|
||||
$this->assertTrue( $this->reflection->invokeMethod('checkLastRunTime', array()) );
|
||||
}
|
||||
|
||||
|
||||
function testCheckLastRunTime()
|
||||
{
|
||||
$this->objects['fileManager']
|
||||
->expects($this->once())
|
||||
->method('getContents')
|
||||
->method('getPhpContents')
|
||||
->will($this->returnValue(time()-60));
|
||||
|
||||
$this->objects['config']
|
||||
->expects($this->once())
|
||||
->method('get')
|
||||
->will($this->returnValue(50));
|
||||
|
||||
$this->assertTrue( $this->reflection->invokeMethod('checkLastRunTime', array()) );
|
||||
}
|
||||
|
||||
$this->assertTrue( $this->reflection->invokeMethod('checkLastRunTime', array()) );
|
||||
}
|
||||
|
||||
|
||||
function testCheckLastRunTimeTooFrequency()
|
||||
{
|
||||
$this->objects['fileManager']
|
||||
->expects($this->once())
|
||||
->method('getContents')
|
||||
->method('getPhpContents')
|
||||
->will($this->returnValue(time()-49));
|
||||
|
||||
$this->objects['config']
|
||||
->expects($this->once())
|
||||
->method('get')
|
||||
->will($this->returnValue(50));
|
||||
|
||||
$this->assertFalse( $this->reflection->invokeMethod('checkLastRunTime', array()) );
|
||||
}
|
||||
|
||||
|
||||
$this->assertFalse( $this->reflection->invokeMethod('checkLastRunTime', array()) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?php
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
@@ -150,7 +150,7 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
public function testSystemConfigMerge()
|
||||
{
|
||||
$configDataWithoutSystem = $this->objects['fileManager']->getContents($this->configPath);
|
||||
$configDataWithoutSystem = $this->objects['fileManager']->getPhpContents($this->configPath);
|
||||
$this->assertArrayNotHasKey('systemItems', $configDataWithoutSystem);
|
||||
$this->assertArrayNotHasKey('adminItems', $configDataWithoutSystem);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?php
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
@@ -89,7 +89,7 @@ class FieldManagerTest extends \PHPUnit_Framework_TestCase
|
||||
->method('get')
|
||||
->will($this->returnValue($data));
|
||||
|
||||
$this->assertTrue($this->object->update('name', $data, 'Account'));
|
||||
$this->object->update('name', $data, 'Account');
|
||||
}
|
||||
|
||||
public function testUpdateCustomFieldIsNotChanged()
|
||||
@@ -138,10 +138,9 @@ class FieldManagerTest extends \PHPUnit_Framework_TestCase
|
||||
"isCustom" => true,
|
||||
);
|
||||
|
||||
$this->assertTrue($this->object->update('varName', $data, 'CustomEntity'));
|
||||
$this->object->update('varName', $data, 'CustomEntity');
|
||||
}
|
||||
|
||||
|
||||
public function testRead()
|
||||
{
|
||||
$data = array(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?php
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
@@ -80,7 +80,6 @@ class LanguageTest extends \PHPUnit_Framework_TestCase
|
||||
$this->object->setLanguage($originalLang);
|
||||
}
|
||||
|
||||
|
||||
public function testGetLangCacheFile()
|
||||
{
|
||||
$cacheFile = $this->cacheFile;
|
||||
@@ -96,7 +95,6 @@ class LanguageTest extends \PHPUnit_Framework_TestCase
|
||||
$this->object->setLanguage($originalLang);
|
||||
}
|
||||
|
||||
|
||||
public function testGetData()
|
||||
{
|
||||
$result = array (
|
||||
@@ -142,7 +140,6 @@ class LanguageTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertEquals($result, $this->reflection->invokeMethod('getData', array()));
|
||||
}
|
||||
|
||||
|
||||
public function testGet()
|
||||
{
|
||||
$result = array (
|
||||
@@ -204,7 +201,6 @@ class LanguageTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertEquals($result, $this->object->translate('language', 'options', 'Global', $requiredOptions));
|
||||
}
|
||||
|
||||
|
||||
public function testTranslateArray()
|
||||
{
|
||||
$input = array(
|
||||
@@ -227,20 +223,124 @@ class LanguageTest extends \PHPUnit_Framework_TestCase
|
||||
public function testSet()
|
||||
{
|
||||
$label = 'TEST';
|
||||
$this->object->set('label', $label, 'fields', 'User');
|
||||
$this->object->set('User', 'fields', 'label', $label);
|
||||
$this->assertEquals($label, $this->object->translate('label', 'fields', 'User'));
|
||||
|
||||
$result = array(
|
||||
'User' => array(
|
||||
'fields' => array(
|
||||
'label' => 'TEST',
|
||||
),
|
||||
),
|
||||
);
|
||||
$this->assertEquals($result, $this->reflection->getProperty('changedData'));
|
||||
|
||||
$label2 = 'TEST2';
|
||||
$this->object->set('name', $label2, 'fields', 'User');
|
||||
$this->object->set('User', 'fields', 'name', $label2);
|
||||
$this->assertEquals($label2, $this->object->translate('name', 'fields', 'User'));
|
||||
|
||||
$result = array(
|
||||
'User' => array(
|
||||
'fields' => array(
|
||||
'label' => 'TEST',
|
||||
'name' => 'TEST2',
|
||||
),
|
||||
),
|
||||
);
|
||||
$this->assertEquals($result, $this->reflection->getProperty('changedData'));
|
||||
|
||||
$label3 = 'TEST3';
|
||||
$this->object->set('name', $label3, 'fields', 'Account');
|
||||
$this->object->set('Account', 'fields', 'name', $label3);
|
||||
$this->assertEquals($label3, $this->object->translate('name', 'fields', 'Account'));
|
||||
|
||||
$this->reflection->invokeMethod('init', array(true));
|
||||
$result = array(
|
||||
'User' => array(
|
||||
'fields' => array(
|
||||
'label' => 'TEST',
|
||||
'name' => 'TEST2',
|
||||
),
|
||||
),
|
||||
'Account' => array(
|
||||
'fields' => array(
|
||||
'name' => 'TEST3',
|
||||
),
|
||||
),
|
||||
);
|
||||
$this->assertEquals($result, $this->reflection->getProperty('changedData'));
|
||||
|
||||
$this->object->clearChanges();
|
||||
|
||||
$this->assertEquals(array(), $this->reflection->getProperty('changedData'));
|
||||
$this->assertNotEquals('TEST', $this->object->get('User', 'fields', 'label'));
|
||||
}
|
||||
|
||||
public function testDelete()
|
||||
{
|
||||
$this->object->delete('User', 'fields', 'label');
|
||||
$this->assertNull($this->object->get('User.fields.label'));
|
||||
|
||||
$result = array(
|
||||
'User' => array(
|
||||
'fields' => array(
|
||||
'label',
|
||||
),
|
||||
),
|
||||
);
|
||||
$this->assertEquals($result, $this->reflection->getProperty('deletedData'));
|
||||
|
||||
$this->object->delete('User', 'fields', 'name');
|
||||
$this->assertNull($this->object->get('User.fields.name'));
|
||||
|
||||
$result = array(
|
||||
'User' => array(
|
||||
'fields' => array(
|
||||
'label',
|
||||
'name',
|
||||
),
|
||||
),
|
||||
);
|
||||
$this->assertEquals($result, $this->reflection->getProperty('deletedData'));
|
||||
|
||||
$this->object->clearChanges();
|
||||
|
||||
$this->assertNotNull($this->object->get('User.fields.label'));
|
||||
$this->assertNotNull($this->object->get('User.fields.name'));
|
||||
|
||||
$this->assertEquals(array(), $this->reflection->getProperty('deletedData'));
|
||||
}
|
||||
|
||||
public function testUndelete()
|
||||
{
|
||||
$this->object->delete('User', 'fields', 'label');
|
||||
$this->assertNull($this->object->get('User.fields.label'));
|
||||
|
||||
$this->object->delete('User', 'fields', 'name');
|
||||
$this->assertNull($this->object->get('User.fields.name'));
|
||||
|
||||
$label = 'TEST';
|
||||
$this->object->set('User', 'fields', 'label', $label);
|
||||
$this->assertEquals($label, $this->object->translate('label', 'fields', 'User'));
|
||||
|
||||
$result = array(
|
||||
'User' => array(
|
||||
'fields' => array(
|
||||
1 => 'name',
|
||||
),
|
||||
),
|
||||
);
|
||||
$this->assertEquals($result, $this->reflection->getProperty('deletedData'));
|
||||
|
||||
$label2 = 'TEST2';
|
||||
$this->object->set('User', 'fields', 'name', $label2);
|
||||
$this->assertEquals($label2, $this->object->translate('name', 'fields', 'User'));
|
||||
|
||||
$result = array(
|
||||
'User' => array(
|
||||
'fields' => array(
|
||||
),
|
||||
),
|
||||
);
|
||||
$this->assertEquals($result, $this->reflection->getProperty('deletedData'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?php
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
@@ -24,52 +24,209 @@ namespace tests\Espo\Core\Utils;
|
||||
|
||||
use tests\ReflectionHelper;
|
||||
|
||||
|
||||
class MetadataTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
protected $object;
|
||||
|
||||
|
||||
protected $objects;
|
||||
|
||||
protected $reflection;
|
||||
|
||||
protected $defaultCacheFile = 'tests/testData/Utils/Metadata/metadata.php';
|
||||
|
||||
protected $cacheFile = 'tests/testData/cache/metadata.php';
|
||||
protected $ormCacheFile = 'tests/testData/Utils/Metadata/ormMetadata.php';
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
{
|
||||
/*copy defaultCacheFile file to cache*/
|
||||
if (!file_exists($this->cacheFile)) {
|
||||
copy($this->defaultCacheFile, $this->cacheFile);
|
||||
}
|
||||
|
||||
$this->objects['config'] = $this->getMockBuilder('\Espo\Core\Utils\Config')->disableOriginalConstructor()->getMock();
|
||||
$this->objects['fileManager'] = new \Espo\Core\Utils\File\Manager();
|
||||
$this->objects['fileManager'] = new \Espo\Core\Utils\File\Manager();
|
||||
$this->objects['Unifier'] = $this->getMockBuilder('\Espo\Core\Utils\File\Unifier')->disableOriginalConstructor()->getMock();
|
||||
|
||||
//set to use cache
|
||||
$this->objects['config']
|
||||
->expects($this->any())
|
||||
->method('get')
|
||||
->will($this->returnValue(true));
|
||||
|
||||
->will($this->returnValue(true));
|
||||
|
||||
|
||||
$this->object = new \Espo\Core\Utils\Metadata($this->objects['config'], $this->objects['fileManager']);
|
||||
|
||||
$this->reflection = new ReflectionHelper($this->object);
|
||||
$this->reflection->setProperty('cacheFile', 'tests/testData/Utils/Metadata/metadata.php');
|
||||
$this->reflection->setProperty('ormCacheFile', 'tests/testData/Utils/Metadata/ormMetadata.php');
|
||||
$this->reflection = new ReflectionHelper($this->object);
|
||||
$this->reflection->setProperty('cacheFile', $this->cacheFile);
|
||||
$this->reflection->setProperty('ormCacheFile', $this->ormCacheFile);
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
{
|
||||
$this->object = NULL;
|
||||
}
|
||||
|
||||
|
||||
function testGet()
|
||||
{
|
||||
|
||||
public function testGet()
|
||||
{
|
||||
$result = 'System';
|
||||
$this->assertEquals($result, $this->object->get('app.adminPanel.system.label'));
|
||||
$this->assertEquals($result, $this->object->get('app.adminPanel.system.label'));
|
||||
|
||||
$result = 'fields';
|
||||
$this->assertArrayHasKey($result, $this->object->get('entityDefs.User'));
|
||||
}
|
||||
$this->assertArrayHasKey($result, $this->object->get('entityDefs.User'));
|
||||
}
|
||||
|
||||
public function testSet()
|
||||
{
|
||||
$data = array (
|
||||
'fields' =>
|
||||
array (
|
||||
'name' =>
|
||||
array (
|
||||
'required' => false,
|
||||
'maxLength' => 150,
|
||||
'view' => 'Views.Test.Custom',
|
||||
),
|
||||
),
|
||||
);
|
||||
$this->object->set('entityDefs', 'Attachment', $data);
|
||||
$this->assertEquals('Views.Test.Custom', $this->object->get('entityDefs.Attachment.fields.name.view'));
|
||||
$this->assertEquals(150, $this->object->get('entityDefs.Attachment.fields.name.maxLength'));
|
||||
|
||||
$result = array(
|
||||
'entityDefs' => array(
|
||||
'Attachment' => $data
|
||||
),
|
||||
);
|
||||
$this->assertEquals($result, $this->reflection->getProperty('changedData'));
|
||||
|
||||
}
|
||||
$data = array (
|
||||
'fields' =>
|
||||
array (
|
||||
'name' =>
|
||||
array (
|
||||
'maxLength' => 200,
|
||||
),
|
||||
),
|
||||
);
|
||||
$this->object->set('entityDefs', 'Attachment', $data);
|
||||
$this->assertEquals(200, $this->object->get('entityDefs.Attachment.fields.name.maxLength'));
|
||||
$this->assertEquals('Views.Test.Custom', $this->object->get('entityDefs.Attachment.fields.name.view'));
|
||||
|
||||
?>
|
||||
$result = array(
|
||||
'entityDefs' => array(
|
||||
'Attachment' => array (
|
||||
'fields' =>
|
||||
array (
|
||||
'name' =>
|
||||
array (
|
||||
'required' => false,
|
||||
'maxLength' => 200,
|
||||
'view' => 'Views.Test.Custom',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
$this->assertEquals($result, $this->reflection->getProperty('changedData'));
|
||||
|
||||
$this->object->clearChanges();
|
||||
|
||||
$this->assertEquals(array(), $this->reflection->getProperty('changedData'));
|
||||
$this->assertNull($this->object->get('entityDefs.Attachment.fields.name.view'));
|
||||
}
|
||||
|
||||
public function testDelete()
|
||||
{
|
||||
$data = array (
|
||||
'fields.name.type',
|
||||
);
|
||||
$this->object->delete('entityDefs', 'Attachment', $data);
|
||||
$this->assertNull($this->object->get('entityDefs.Attachment.fields.name.type'));
|
||||
|
||||
$result = array(
|
||||
'entityDefs' => array(
|
||||
'Attachment' => array(
|
||||
'fields.name.type',
|
||||
),
|
||||
),
|
||||
);
|
||||
$this->assertEquals($result, $this->reflection->getProperty('deletedData'));
|
||||
|
||||
$data = array (
|
||||
'fields.name.required',
|
||||
);
|
||||
$this->object->delete('entityDefs', 'Attachment', $data);
|
||||
$this->assertNull($this->object->get('entityDefs.Attachment.fields.name.required'));
|
||||
|
||||
$result = array(
|
||||
'entityDefs' => array(
|
||||
'Attachment' => array(
|
||||
'fields.name.type',
|
||||
'fields.name.required',
|
||||
),
|
||||
),
|
||||
);
|
||||
$this->assertEquals($result, $this->reflection->getProperty('deletedData'));
|
||||
|
||||
$this->object->init(false);
|
||||
|
||||
$this->assertNotNull($this->object->get('entityDefs.Attachment.fields.name.type'));
|
||||
$this->assertNotNull($this->object->get('entityDefs.Attachment.fields.name.required'));
|
||||
|
||||
$this->object->clearChanges();
|
||||
$this->assertEquals(array(), $this->reflection->getProperty('deletedData'));
|
||||
}
|
||||
|
||||
public function testUndelete()
|
||||
{
|
||||
$data = array (
|
||||
'fields.name.type',
|
||||
'fields.name.required',
|
||||
);
|
||||
$this->object->delete('entityDefs', 'Attachment', $data);
|
||||
$this->assertNull($this->object->get('entityDefs.Attachment.fields.name.type'));
|
||||
|
||||
$data = array (
|
||||
'fields' =>
|
||||
array (
|
||||
'name' =>
|
||||
array (
|
||||
'type' => 'enum',
|
||||
),
|
||||
),
|
||||
);
|
||||
$this->object->set('entityDefs', 'Attachment', $data);
|
||||
$this->assertEquals('enum', $this->object->get('entityDefs.Attachment.fields.name.type'));
|
||||
|
||||
$result = array(
|
||||
'entityDefs' => array(
|
||||
'Attachment' => array(
|
||||
1 => 'fields.name.required',
|
||||
),
|
||||
),
|
||||
);
|
||||
$this->assertEquals($result, $this->reflection->getProperty('deletedData'));
|
||||
|
||||
$data = array (
|
||||
'fields' =>
|
||||
array (
|
||||
'name' =>
|
||||
array (
|
||||
'required' => true,
|
||||
),
|
||||
),
|
||||
);
|
||||
$this->object->set('entityDefs', 'Attachment', $data);
|
||||
$this->assertEquals(true, $this->object->get('entityDefs.Attachment.fields.name.required'));
|
||||
|
||||
$result = array(
|
||||
'entityDefs' => array(
|
||||
'Attachment' => array(
|
||||
),
|
||||
),
|
||||
);
|
||||
$this->assertEquals($result, $this->reflection->getProperty('deletedData'));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user