mirror of
https://github.com/espocrm/espocrm.git
synced 2026-03-11 06:27:01 +00:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
056191db82 | ||
|
|
9ace150efa | ||
|
|
79ae89d172 | ||
|
|
bb703e2060 | ||
|
|
972d9019e1 | ||
|
|
c99566410a | ||
|
|
9c56a14fb0 | ||
|
|
b95e58317b | ||
|
|
6fd9d6e15c | ||
|
|
518b9fa2ba | ||
|
|
c113b7bd88 | ||
|
|
fb0a302f62 | ||
|
|
43127379cd |
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -455,6 +455,10 @@ class Export
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$entityDefs->hasField($field)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($entityDefs->getField($field)->getParam('exportDisabled')) {
|
||||
unset($fieldList[$i]);
|
||||
}
|
||||
|
||||
@@ -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
2
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "espocrm",
|
||||
"version": "7.0.2",
|
||||
"version": "7.0.4",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "espocrm",
|
||||
"version": "7.0.2",
|
||||
"version": "7.0.4",
|
||||
"description": "Open-source CRM.",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user