Merge branch 'fix'

This commit is contained in:
Yuri Kuznetsov
2023-01-11 13:22:06 +02:00
15 changed files with 140 additions and 47 deletions
+1
View File
@@ -3,3 +3,4 @@
!/codeStyles
!/fileTemplates
!/inspectionProfiles
!misc.xml
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PhpEntryPointsManager">
<pattern value="\Espo\Controllers\*" member="*Action*" />
<pattern value="\Espo\Modules\*\Controllers\*" member="*Action*" />
</component>
</project>
+14 -1
View File
@@ -55,7 +55,20 @@ class ApplicationUser
*/
public function setupSystemUser(): void
{
$user = $this->entityManagerProxy->getEntityById(User::ENTITY_TYPE, self::SYSTEM_USER_ID);
$user = $this->entityManagerProxy
->getRDBRepository(User::ENTITY_TYPE)
->select([
'id',
'name',
'userName',
'type',
'isActive',
'firstName',
'lastName',
'deleted',
])
->where(['id' => self::SYSTEM_USER_ID])
->findOne();
if (!$user) {
throw new RuntimeException("System user is not found.");
@@ -4,7 +4,6 @@
"providerClassName": "Espo\\Modules\\Crm\\Tools\\Activities\\PopupNotificationsProvider",
"serviceName": "Activities",
"methodName": "getPopupNotifications",
"interval": 15,
"useWebSocket": true,
"portalDisabled": true,
"view": "crm:views/meeting/popup-notification"
@@ -29,6 +29,19 @@
/** @todo Remove in v8.0. */
class_alias('Laminas\\Mail\\Protocol\\Smtp', 'Zend\\Mail\\Protocol\\Smtp');
class_alias('Laminas\\Mail\\Protocol\\Imap', 'Zend\\Mail\\Protocol\\Imap');
class_alias('Laminas\\Mail\\Message', 'Zend\\Mail\\Message');
$map = [
['Laminas\\Mail\\Protocol\\Smtp', 'Zend\\Mail\\Protocol\\Smtp'],
['Laminas\\Mail\\Protocol\\Imap', 'Zend\\Mail\\Protocol\\Imap'],
['Laminas\\Mail\\Message', 'Zend\\Mail\\Message'],
];
foreach ($map as $item) {
$className = $item[0];
$alias = $item[1];
if (!class_exists($className)) {
continue;
}
class_alias($className, $alias);
}
@@ -133,6 +133,7 @@ return [
'emailNotificationsDelay' => 30,
'emailMessageMaxSize' => 10,
'notificationsCheckInterval' => 10,
'popupNotificationsCheckInterval' => 15,
'maxEmailAccountCount' => 2,
'followCreatedEntities' => false,
'b2cMode' => false,
@@ -85,7 +85,10 @@
},
"User": {
"dashboardTemplate": false,
"workingTimeCalendar": false,
"workingTimeCalendar": {
"read": "yes",
"edit": "no"
},
"password": false,
"passwordConfirm": false,
"auth2FA": false,
@@ -48,7 +48,7 @@
"nonAdminReadOnly": true
},
"workingTimeCalendar": {
"onlyAdmin": true
"nonAdminReadOnly": true
},
"accounts": {
"nonAdminReadOnly": true
@@ -441,7 +441,8 @@
},
"workingTimeCalendar": {
"type": "belongsTo",
"entity": "WorkingTimeCalendar"
"entity": "WorkingTimeCalendar",
"noJoin": true
},
"workingTimeRanges": {
"type": "hasMany",
+1
View File
@@ -156,6 +156,7 @@ define('views/email/list', ['views/list'], function (Dep) {
let $row = $container.find(`.list-row[data-id="${m.id}"]`).first();
$row.draggable({
cancel: 'input,textarea,button,select,option,.dropdown-menu',
helper: () => {
let text = this.translate('Moving to Folder', 'labels', 'Email');
+60 -36
View File
@@ -33,8 +33,10 @@ define('views/notification/badge', ['view'], function (Dep) {
template: 'notification/badge',
notificationsCheckInterval: 10,
groupedCheckInterval: 15,
timeout: null,
groupedTimeout: null,
popupNotificationsData: null,
@@ -58,6 +60,10 @@ define('views/notification/badge', ['view'], function (Dep) {
clearTimeout(this.timeout);
}
if (this.groupedTimeout) {
clearTimeout(this.groupedTimeout);
}
for (let name in this.popupTimeouts) {
clearTimeout(this.popupTimeouts[name]);
}
@@ -69,6 +75,9 @@ define('views/notification/badge', ['view'], function (Dep) {
this.notificationsCheckInterval = this.getConfig().get('notificationsCheckInterval') ||
this.notificationsCheckInterval;
this.groupedCheckInterval = this.getConfig().get('popupNotificationsCheckInterval') ||
this.groupedCheckInterval;
this.lastId = 0;
this.shownNotificationIds = [];
this.closedNotificationIds = [];
@@ -80,10 +89,10 @@ define('views/notification/badge', ['view'], function (Dep) {
window.addEventListener('storage', e => {
if (e.key === 'messageClosePopupNotificationId') {
var id = localStorage.getItem('messageClosePopupNotificationId');
let id = localStorage.getItem('messageClosePopupNotificationId');
if (id) {
var key = 'popup-' + id;
let key = 'popup-' + id;
if (this.hasView(key)) {
this.markPopupRemoved(id);
@@ -105,7 +114,6 @@ define('views/notification/badge', ['view'], function (Dep) {
afterRender: function () {
this.$badge = this.$el.find('.notifications-button');
this.$icon = this.$el.find('.notifications-button .icon');
this.$number = this.$el.find('.number-badge');
this.runCheckUpdates(true);
@@ -119,14 +127,16 @@ define('views/notification/badge', ['view'], function (Dep) {
.appendTo('body');
}
var popupNotificationsData = this.popupNotificationsData =
let popupNotificationsData = this.popupNotificationsData =
this.getMetadata().get('app.popupNotifications') || {};
for (var name in popupNotificationsData) {
for (let name in popupNotificationsData) {
this.checkPopupNotifications(name);
}
this.checkGroupedPopupNotifications();
if (this.hasGroupedPopupNotifications()) {
this.checkGroupedPopupNotifications();
}
},
playSound: function () {
@@ -186,6 +196,8 @@ define('views/notification/badge', ['view'], function (Dep) {
) {
return true;
}
return false;
},
checkUpdates: function (isFirstCheck) {
@@ -197,7 +209,7 @@ define('views/notification/badge', ['view'], function (Dep) {
.getRequest('Notification/action/notReadCount')
.then(count => {
if (!isFirstCheck && count > this.unreadCount) {
var messageBlockPlayNotificationSound =
let messageBlockPlayNotificationSound =
localStorage.getItem('messageBlockPlayNotificationSound');
if (!messageBlockPlayNotificationSound) {
@@ -240,45 +252,57 @@ define('views/notification/badge', ['view'], function (Dep) {
);
},
checkGroupedPopupNotifications: function () {
var toCheck = false;
for (var name in this.popupNotificationsData) {
var data = this.popupNotificationsData[name] || {};
/**
* @private
* @return {boolean}
*/
hasGroupedPopupNotifications: function () {
for (let name in this.popupNotificationsData) {
let data = this.popupNotificationsData[name] || {};
if (!data.grouped) {
continue;
}
if (data.portalDisabled && this.getUser().isPortal()) {
return;
continue;
}
toCheck = true;
return true;
}
if (!toCheck) {
return;
return false;
},
/**
* @private
*/
checkGroupedPopupNotifications: function () {
if (!this.checkBypass()) {
Espo.Ajax.getRequest('PopupNotification/action/grouped')
.then(result => {
for (let type in result) {
let list = result[type];
list.forEach(item => this.showPopupNotification(type, item));
}
});
}
Espo.Ajax.getRequest('PopupNotification/action/grouped')
.then(result => {
for (const type in result) {
const list = result[type];
list.forEach(item => this.showPopupNotification(type, item));
}
});
this.groupedTimeout = setTimeout(
() => this.checkGroupedPopupNotifications(),
this.groupedCheckInterval * 1000
);
},
checkPopupNotifications: function (name, isNotFirstCheck) {
var data = this.popupNotificationsData[name] || {};
let data = this.popupNotificationsData[name] || {};
var url = data.url;
var interval = data.interval;
var disabled = data.disabled || false;
let url = data.url;
let interval = data.interval;
let disabled = data.disabled || false;
var isFirstCheck = !isNotFirstCheck;
let isFirstCheck = !isNotFirstCheck;
if (disabled) {
return;
@@ -288,10 +312,10 @@ define('views/notification/badge', ['view'], function (Dep) {
return;
}
var useWebSocket = this.useWebSocket && data.useWebSocket;
let useWebSocket = this.useWebSocket && data.useWebSocket;
if (useWebSocket) {
var category = 'popupNotifications.' + (data.webSocketCategory || name);
let category = 'popupNotifications.' + (data.webSocketCategory || name);
this.getHelper().webSocketManager.subscribe(category, (c, response) => {
if (!response.list) {
@@ -356,19 +380,19 @@ define('views/notification/badge', ['view'], function (Dep) {
},
showPopupNotification: function (name, data, isNotFirstCheck) {
var view = this.popupNotificationsData[name].view;
let view = this.popupNotificationsData[name].view;
if (!view) {
return;
}
var id = data.id || null;
let id = data.id || null;
if (id) {
id = name + '_' + id;
if (~this.shownNotificationIds.indexOf(id)) {
var notificationView = this.getView('popup-' + id);
let notificationView = this.getView('popup-' + id);
if (notificationView) {
notificationView.trigger('update-data', data.data);
@@ -406,7 +430,7 @@ define('views/notification/badge', ['view'], function (Dep) {
},
markPopupRemoved: function (id) {
var index = this.shownNotificationIds.indexOf(id);
let index = this.shownNotificationIds.indexOf(id);
if (index > -1) {
this.shownNotificationIds.splice(index, 1);
@@ -437,7 +461,7 @@ define('views/notification/badge', ['view'], function (Dep) {
showNotifications: function () {
this.closeNotifications();
var $container = $('<div>').attr('id', 'notifications-panel');
let $container = $('<div>').attr('id', 'notifications-panel');
$container.appendTo(this.$el.find('.notifications-panel-container'));
+10
View File
@@ -192,6 +192,16 @@ define('views/user/record/edit', ['views/record/edit', 'views/user/record/detail
});
}
if (this.model.isAdmin() || this.model.isRegular()) {
layout.push({
"label": "Misc",
"name": "misc",
"rows": [
[{"name": "workingTimeCalendar"}, false]
]
});
}
if (this.type == 'edit' && this.getUser().isAdmin() && !this.model.isApi()) {
layout.push({
label: 'Password',
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "espocrm",
"version": "7.3.0",
"version": "7.3.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "espocrm",
"version": "7.3.0",
"version": "7.3.1",
"description": "Open-source CRM.",
"repository": {
"type": "git",
+21 -1
View File
@@ -3,7 +3,7 @@
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2021 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
@@ -32,11 +32,14 @@ use Espo\Entities\EmailAccount;
use Espo\Entities\User;
use Espo\Entities\Preferences;
use Espo\ORM\EntityManager;
use Espo\Core\Utils\Config;
use Espo\Core\Utils\Database\Helper as DatabaseHelper;
class BeforeUpgrade
{
public function run(Container $container): void
{
$this->addUserColumn($container->get('config'));
$this->migrateSmtp($container->get('entityManager'));
}
@@ -121,4 +124,21 @@ class BeforeUpgrade
$entityManager->saveEntity($preferences);
}
private function addUserColumn(Config $config)
{
$databaseHelper = new DatabaseHelper($config);
$pdo = $databaseHelper->createPdoConnection();
$query = "
ALTER TABLE `user` ADD `working_time_calendar_id` VARCHAR(24)
DEFAULT NULL COLLATE `utf8mb4_unicode_ci`
";
try {
$sth = $pdo->prepare($query);
$sth->execute();
} catch (\Exception $e) {}
}
}