Compare commits

..

13 Commits
7.0.2 ... 7.0.4

Author SHA1 Message Date
Yuri Kuznetsov
056191db82 fix pdf filename 2021-10-11 13:01:59 +03:00
Yuri Kuznetsov
9ace150efa v 2021-10-11 11:31:48 +03:00
Yuri Kuznetsov
79ae89d172 fix duration 2021-10-10 11:38:15 +03:00
Yuri Kuznetsov
bb703e2060 fix export not existing fields 2021-10-10 11:22:58 +03:00
Yuri Kuznetsov
972d9019e1 fix log 2021-10-10 11:19:38 +03:00
Yuri Kuznetsov
c99566410a note acl refactoring and period change 2021-10-08 15:35:05 +03:00
Yuri Kuznetsov
9c56a14fb0 file manager allow create file w/ wrong ownership 2021-10-08 11:45:56 +03:00
Yuri Kuznetsov
b95e58317b fix msg 2021-10-08 11:27:09 +03:00
Yuri Kuznetsov
6fd9d6e15c upgrade fix 2021-10-07 17:42:31 +03:00
Yuri Kuznetsov
518b9fa2ba unlink file in checkCreateFile 2021-10-07 17:17:22 +03:00
Yuri Kuznetsov
c113b7bd88 throw exception in auth 2021-10-07 15:00:11 +03:00
Yuri Kuznetsov
fb0a302f62 v 2021-10-06 18:27:50 +03:00
Yuri Kuznetsov
43127379cd fix settings 2021-10-06 18:27:07 +03:00
12 changed files with 94 additions and 41 deletions

View File

@@ -218,9 +218,7 @@ class Auth
return;
}
$response->setStatus(500);
$this->log->error("Auth: " . $e->getMessage());
throw $e;
}
protected function handleUnauthorized(Response $response, bool $showDialog): void

View File

@@ -61,17 +61,17 @@ class EspoFileHandler extends MonologStreamHandler
{
if (!$this->url) {
throw new RuntimeException(
"Missing a logger file path. Check logger params in `data/config.php`."
"Missing a logger file path. Check logger params in config."
);
}
try {
if (!is_writable($this->url)) {
$this->fileManager->checkCreateFile($this->url);
}
$checkFileResult = $this->fileManager->checkCreateFile($this->url);
if (!is_writable($this->url)) {
return;
if (!$checkFileResult) {
return;
}
}
$this->fileManager->appendContents(

View File

@@ -607,7 +607,7 @@ class Manager
}
/**
* Create a new file if not exists with all folders in the path.
* Checks whether a new file can be created. It will also create all needed directories.
*/
public function checkCreateFile(string $filePath): bool
{
@@ -630,8 +630,11 @@ class Manager
$pathParts = pathinfo($filePath);
if (!file_exists($pathParts['dirname'])) {
$dirPermission = $defaultPermissions['dir'];
$dirPermission = is_string($dirPermission) ? base_convert($dirPermission,8,10) : $dirPermission;
$dirPermissionOriginal = $defaultPermissions['dir'];
$dirPermission = is_string($dirPermissionOriginal) ?
base_convert($dirPermissionOriginal, 8, 10) :
$dirPermissionOriginal;
if (!$this->mkdir($pathParts['dirname'], $dirPermission, true)) {
throw new Error(
@@ -640,11 +643,27 @@ class Manager
}
}
if (touch($filePath)) {
return $this->getPermissionUtils()->setDefaultPermissions($filePath);
$touchResult = touch($filePath);
if (!$touchResult) {
return false;
}
return false;
$setPrermissionsResult = $this->getPermissionUtils()->setDefaultPermissions($filePath);
if (!$setPrermissionsResult) {
$this->unlink($filePath);
/**
* Returning true will cause situations when files are created with
* a wrong ownership. This is a trade-off for being able to run
* Espo under a user that is neither webserver-user nor root. A file
* will be created owned by a user running the process.
*/
return true;
}
return true;
}
/**

View File

@@ -31,6 +31,8 @@ namespace Espo\Entities;
use Espo\Core\ORM\Entity;
use Espo\Core\Field\DateTime;
use stdClass;
class Note extends Entity
@@ -117,6 +119,11 @@ class Note extends Entity
return $this->get('post');
}
public function getCreatedAt(): ?DateTime
{
return $this->getValueObject('createdAt');
}
public function setAclIsProcessed(): void
{
$this->aclIsProcessed = true;

View File

@@ -84,7 +84,7 @@ class Pdf implements EntryPoint
->setHeader('Pragma', 'public')
->setHeader('Expires', 'Sat, 26 Jul 1997 05:00:00 GMT')
->setHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT')
->setHeader('Content', 'inline; filename="' . basename($fileName) . '"');
->setHeader('Content-Disposition', 'inline; filename="' . basename($fileName) . '"');
if (!$request->getServerParam('HTTP_ACCEPT_ENCODING')) {
$response->setHeader('Content-Length', $contents->getLength());

View File

@@ -196,10 +196,6 @@ class Settings
foreach ($this->access->getAdminParamList() as $item) {
$ignoreItemList[] = $item;
}
foreach ($this->access->getSuperAdminParamList() as $item) {
$ignoreItemList[] = $item;
}
}
if ($this->config->get('restrictedMode') && !$user->isSuperAdmin()) {

View File

@@ -108,7 +108,18 @@ class Stream
private $recordServiceContainer;
private const NOTE_ACL_PERIOD = '1 hour';
/**
* When a record is re-assigned, ACL will be recalculated for related notes
* created within the period.
*/
private const NOTE_ACL_PERIOD = '3 days';
private const NOTE_ACL_LIMIT = 50;
/**
* Not used currently.
*/
private const NOTE_NOTIFICATION_PERIOD = '1 hour';
public function __construct(
EntityManager $entityManager,
@@ -2110,6 +2121,8 @@ class Stream
return;
}
$limit = $this->config->get('noteAclLimit', self::NOTE_ACL_LIMIT);
$noteList = $this->entityManager
->getRDBRepository('Note')
->where([
@@ -2137,6 +2150,8 @@ class Stream
'relatedId',
'createdAt',
])
->order('number', 'DESC')
->limit(0, $limit)
->find();
$noteOptions = [];
@@ -2145,9 +2160,11 @@ class Stream
$noteOptions['forceProcessNotifications'] = true;
}
$period = '-' . $this->config->get('noteNotificationPeriod', self::NOTE_ACL_PERIOD);
$notificationPeriod = '-' . $this->config->get('noteNotificationPeriod', self::NOTE_NOTIFICATION_PERIOD);
$aclPeriod = '-' . $this->config->get('noteAclPeriod', self::NOTE_ACL_PERIOD);
$threshold = (new DateTime())->modify($period);
$notificationThreshold = (new DateTime())->modify($notificationPeriod);
$aclThreshold = (new DateTime())->modify($aclPeriod);
foreach ($noteList as $note) {
$this->processNoteAclItem($entity, $note, [
@@ -2156,7 +2173,8 @@ class Stream
'forceProcessNoteNotifications' => $forceProcessNoteNotifications,
'teamIdList' => $teamIdList,
'userIdList' => $userIdList,
'threshold' => $threshold,
'notificationThreshold' => $notificationThreshold,
'aclThreshold' => $aclThreshold,
]);
}
}
@@ -2170,21 +2188,21 @@ class Stream
$teamIdList = $params['teamIdList'];
$userIdList = $params['userIdList'];
$threshold = $params['threshold'];
$notificationThreshold = $params['notificationThreshold'];
$aclThreshold = $params['aclThreshold'];
$noteOptions = [
'forceProcessNotifications' => $forceProcessNoteNotifications,
];
$createdAt = $note->getCreatedAt();
if (!$entity->isNew() && $note->get('createdAt')) {
try {
$createdAtDt = new DateTime($note->get('createdAt'));
}
catch (Exception $e) {
return;
if (!$createdAt) {
return;
}
if (!$entity->isNew()) {
if ($createdAt->getTimestamp() < $notificationThreshold->getTimestamp()) {
$forceProcessNoteNotifications = false;
}
if ($createdAtDt->getTimestamp() < $threshold->getTimestamp()) {
if ($createdAt->getTimestamp() < $aclThreshold->getTimestamp()) {
return;
}
}
@@ -2197,7 +2215,9 @@ class Stream
$note->set('usersIds', $userIdList);
}
$this->entityManager->saveEntity($note, $noteOptions);
$this->entityManager->saveEntity($note, [
'forceProcessNotifications' => $forceProcessNoteNotifications,
]);
}
public function applyAccessControlToNote(NoteEntity $note, ?User $user = null): void

View File

@@ -455,6 +455,10 @@ class Export
continue;
}
if (!$entityDefs->hasField($field)) {
continue;
}
if ($entityDefs->getField($field)->getParam('exportDisabled')) {
unset($fieldList[$i]);
}

View File

@@ -123,12 +123,16 @@ define('views/fields/duration', 'views/fields/enum', function (Dep) {
return this.stringValue;
},
stringifyDuration: function (seconds) {
if (!seconds) {
stringifyDuration: function (secondsTotal) {
if (!secondsTotal) {
return '0';
}
var d = seconds;
if (secondsTotal < 60) {
return '0';
}
var d = secondsTotal;
var days = Math.floor(d / (86400));

2
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "espocrm",
"version": "7.0.2",
"version": "7.0.4",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "espocrm",
"version": "7.0.2",
"version": "7.0.4",
"description": "Open-source CRM.",
"repository": {
"type": "git",

View File

@@ -41,7 +41,12 @@ class BeforeUpgrade
$this->processCheckCache();
// Load to prevent fail if run in a single process.
$container->get('entityManager')->getQueryBuilder()->update();
$container->get('entityManager')
->getQueryBuilder()
->update()
->in('Test')
->set(['test' => 'test'])
->build();
}
private function processCheckCache()