Skip to content

Commit

Permalink
Merge branch 'develop' of github.com:RocketChat/Rocket.Chat into admi…
Browse files Browse the repository at this point in the history
…n-refactor

* 'develop' of github.com:RocketChat/Rocket.Chat:
  Allow to filter omnichannel analytics dashboards per departments. (#17463)
  [FIX] Uncessary updates on Settings, Roles and Permissions on startup (#17160)
  [NEW] Add the ability to send Livechat offline messages to a channel (#17442)
  [FIX] Federation attachment URL for audio and video files (#16430)
  [NEW] Add Livechat website URL to the offline message e-mail (#17429)
  • Loading branch information
ggazzo committed May 5, 2020
2 parents 9896f31 + aaf9083 commit 48c43c6
Show file tree
Hide file tree
Showing 62 changed files with 1,532 additions and 762 deletions.
2 changes: 1 addition & 1 deletion app/api/server/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ export class APIClass extends Restivus {
'error-unauthorized': 'unauthorized',
}[e.error] || 'failure';

result = API.v1[apiMethod](typeof e === 'string' ? e : e.message, e.error, undefined, e);
result = API.v1[apiMethod](typeof e === 'string' ? e : e.message, e.error, process.env.TEST_MODE ? e.stack : undefined, e);
} finally {
delete Accounts._accountData[connection.id];
}
Expand Down
2 changes: 1 addition & 1 deletion app/api/server/v1/chat.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Match, check } from 'meteor/check';
import { Messages } from '../../../models';
import { canAccessRoom, hasPermission } from '../../../authorization';
import { normalizeMessagesForUser } from '../../../utils/server/lib/normalizeMessagesForUser';
import { processWebhookMessage } from '../../../lib';
import { processWebhookMessage } from '../../../lib/server';
import { API } from '../api';
import Rooms from '../../../models/server/models/Rooms';
import Users from '../../../models/server/models/Users';
Expand Down
2 changes: 1 addition & 1 deletion app/api/server/v1/permissions.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Meteor } from 'meteor/meteor';
import { Match, check } from 'meteor/check';

import { hasPermission } from '../../../authorization';
import { Permissions, Roles } from '../../../models';
import { Permissions, Roles } from '../../../models/server';
import { API } from '../api';

/**
Expand Down
2 changes: 1 addition & 1 deletion app/api/server/v1/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Match, check } from 'meteor/check';
import { ServiceConfiguration } from 'meteor/service-configuration';
import _ from 'underscore';

import { Settings } from '../../../models';
import { Settings } from '../../../models/server';
import { hasPermission } from '../../../authorization';
import { API } from '../api';

Expand Down
2 changes: 1 addition & 1 deletion app/apps/server/orchestrator.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class AppServerOrchestrator {

initialize() {
this._rocketchatLogger = new Logger('Rocket.Chat Apps');
Permissions.createOrUpdate('manage-apps', ['admin']);
Permissions.create('manage-apps', ['admin']);

this._marketplaceUrl = 'https://marketplace.rocket.chat';

Expand Down
23 changes: 14 additions & 9 deletions app/authorization/server/startup.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint no-multi-spaces: 0 */
import { Meteor } from 'meteor/meteor';

import { Roles, Permissions, Settings } from '../../models';
import { Roles, Permissions, Settings } from '../../models/server';
import { settings } from '../../settings/server';
import { getSettingPermissionId, CONSTANTS } from '../lib';
import { clearCache } from './functions/hasPermission';
Expand Down Expand Up @@ -114,9 +114,7 @@ Meteor.startup(function() {
];

for (const permission of permissions) {
if (!Permissions.findOneById(permission._id)) {
Permissions.upsert(permission._id, { $set: permission });
}
Permissions.create(permission._id, permission.roles);
}

const defaultRoles = [
Expand All @@ -134,7 +132,7 @@ Meteor.startup(function() {
];

for (const role of defaultRoles) {
Roles.upsert({ _id: role.name }, { $setOnInsert: { scope: role.scope, description: role.description || '', protected: true, mandatory2fa: false } });
Roles.createOrUpdate(role.name, role.scope, role.description, true, false);
}

const getPreviousPermissions = function(settingId) {
Expand All @@ -155,27 +153,34 @@ Meteor.startup(function() {
const createSettingPermission = function(setting, previousSettingPermissions) {
const permissionId = getSettingPermissionId(setting._id);
const permission = {
_id: permissionId,
level: CONSTANTS.SETTINGS_LEVEL,
// copy those setting-properties which are needed to properly publish the setting-based permissions
settingId: setting._id,
group: setting.group,
section: setting.section,
sorter: setting.sorter,
roles: [],
};
// copy previously assigned roles if available
if (previousSettingPermissions[permissionId] && previousSettingPermissions[permissionId].roles) {
permission.roles = previousSettingPermissions[permissionId].roles;
} else {
permission.roles = [];
}
if (setting.group) {
permission.groupPermissionId = getSettingPermissionId(setting.group);
}
if (setting.section) {
permission.sectionPermissionId = getSettingPermissionId(setting.section);
}
Permissions.upsert(permission._id, { $set: permission });

const existent = Permissions.findOne({
_id: permissionId,
...permission,
}, { fields: { _id: 1 } });

if (!existent) {
Permissions.upsert({ _id: permissionId }, { $set: permission });
}

delete previousSettingPermissions[permissionId];
};

Expand Down
4 changes: 1 addition & 3 deletions app/channel-settings-mail-messages/server/lib/startup.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,5 @@ Meteor.startup(function() {
_id: 'mail-messages',
roles: ['admin'],
};
return Permissions.upsert(permission._id, {
$setOnInsert: permission,
});
return Permissions.create(permission._id, permission.roles);
});
6 changes: 3 additions & 3 deletions app/channel-settings/server/startup.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Meteor } from 'meteor/meteor';
import { Permissions } from '../../models';

Meteor.startup(function() {
Permissions.upsert('post-readonly', { $setOnInsert: { roles: ['admin', 'owner', 'moderator'] } });
Permissions.upsert('set-readonly', { $setOnInsert: { roles: ['admin', 'owner'] } });
Permissions.upsert('set-react-when-readonly', { $setOnInsert: { roles: ['admin', 'owner'] } });
Permissions.create('post-readonly', ['admin', 'owner', 'moderator']);
Permissions.create('set-readonly', ['admin', 'owner']);
Permissions.create('set-react-when-readonly', ['admin', 'owner']);
});
2 changes: 1 addition & 1 deletion app/cloud/server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { Permissions } from '../../models';
import { settings } from '../../settings/server';

if (Permissions) {
Permissions.createOrUpdate('manage-cloud', ['admin']);
Permissions.create('manage-cloud', ['admin']);
}

const licenseCronName = 'Cloud Workspace Sync';
Expand Down
2 changes: 1 addition & 1 deletion app/custom-sounds/server/startup/permissions.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ import { Permissions } from '../../../models';

Meteor.startup(() => {
if (Permissions) {
Permissions.createOrUpdate('manage-sounds', ['admin']);
Permissions.create('manage-sounds', ['admin']);
}
});
4 changes: 1 addition & 3 deletions app/discussion/server/permissions.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ Meteor.startup(() => {
];

for (const permission of permissions) {
if (!Permissions.findOneById(permission._id)) {
Permissions.upsert(permission._id, { $set: permission });
}
Permissions.create(permission._id, permission.roles);
}
});
10 changes: 8 additions & 2 deletions app/federation/server/endpoints/dispatch.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,10 +225,16 @@ const eventHandlers = {
// Update the message's file
denormalizedMessage.file._id = upload._id;

// Update the message's attachments
// Update the message's attachments dependent on type
for (const attachment of denormalizedMessage.attachments) {
attachment.title_link = attachment.title_link.replace(oldUploadId, upload._id);
attachment.image_url = attachment.image_url.replace(oldUploadId, upload._id);
if (/^image\/.+/.test(denormalizedMessage.file.type)) {
attachment.image_url = attachment.image_url.replace(oldUploadId, upload._id);
} else if (/^audio\/.+/.test(denormalizedMessage.file.type)) {
attachment.audio_url = attachment.audio_url.replace(oldUploadId, upload._id);
} else if (/^video\/.+/.test(denormalizedMessage.file.type)) {
attachment.video_url = attachment.video_url.replace(oldUploadId, upload._id);
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion app/lib/server/functions/createDirectRoom.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Rooms, Subscriptions } from '../../../models/server';
import { settings } from '../../../settings/lib/settings';
import { settings } from '../../../settings/server';
import { getDefaultSubscriptionPref } from '../../../utils/server';
import { callbacks } from '../../../callbacks/server';

Expand Down
2 changes: 1 addition & 1 deletion app/lib/server/startup/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -2756,7 +2756,7 @@ settings.addGroup('Setup_Wizard', function() {
secret: true,
});

this.add('Cloud_Workspace_Access_Token_Expires_At', new Date(), {
this.add('Cloud_Workspace_Access_Token_Expires_At', new Date(0), {
type: 'date',
hidden: true,
readonly: true,
Expand Down
3 changes: 1 addition & 2 deletions app/livechat/client/stylesheets/livechat.css
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,7 @@
.lc-analytics-table {
display: flex;

height: ~"calc(100% - 280px)";
height: ~"-webkit-calc-height(100% - 280px)";
height: 100%;

min-height: 300px;
flex-flow: column;
Expand Down
22 changes: 22 additions & 0 deletions app/livechat/client/views/app/analytics/livechatAnalytics.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,28 @@
<i class="icon-angle-down"></i>
</div>

{{#if hasDepartments }}
<div class="form-group ">
{{> livechatAutocompleteUser
onClickTag=onClickTagDepartment
list=selectedDepartments
onSelect=onSelectDepartments
collection='CachedDepartmentList'
endpoint='livechat/department.autocomplete'
field='name'
sort='name'
placeholder="Select_a_department"
name="department"
icon="queue"
noMatchTemplate="userSearchEmpty"
templateItem="popupList_item_channel"
template="roomSearch"
noMatchTemplate="roomSearchEmpty"
modifier=departmentModifier
}}
</div>
{{/if}}

<div class="form-group lc-analytics-header">
{{#if showLeftNavButton}}
<button class="lc-daterange-prev">
Expand Down
49 changes: 47 additions & 2 deletions app/livechat/client/views/app/analytics/livechatAnalytics.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { handleError } from '../../../../../utils';
import { popover } from '../../../../../ui-utils';
import { drawLineChart } from '../../../lib/chartHandler';
import { setDateRange, updateDateRange } from '../../../lib/dateHandler';
import { APIClient } from '../../../../../utils/client';
import './livechatAnalytics.html';

let templateInstance; // current template instance/context
Expand Down Expand Up @@ -62,13 +63,19 @@ const chunkArray = (arr, chunkCount) => { // split array into n almost equal arr
return chunks;
};

const getChartDepartment = (department) => department?._id;

const updateAnalyticsChart = () => {
const [department] = templateInstance.selectedDepartments.get();
const departmentId = getChartDepartment(department);

const options = {
daterange: {
from: moment(templateInstance.daterange.get().from, 'MMM D YYYY').toISOString(),
to: moment(templateInstance.daterange.get().to, 'MMM D YYYY').toISOString(),
},
chartOptions: templateInstance.chartOptions.get(),
...departmentId && { departmentId },
};

Meteor.call('livechat:getAnalyticsChartData', options, async function(error, result) {
Expand Down Expand Up @@ -97,12 +104,16 @@ const updateAnalyticsChart = () => {
};

const updateAnalyticsOverview = () => {
const [department] = templateInstance.selectedDepartments.get();
const departmentId = getChartDepartment(department);

const options = {
daterange: {
from: moment(templateInstance.daterange.get().from, 'MMM D YYYY').toISOString(),
to: moment(templateInstance.daterange.get().to, 'MMM D YYYY').toISOString(),
},
analyticsOptions: templateInstance.analyticsOptions.get(),
...departmentId && { departmentId },
};

Meteor.call('livechat:getAnalyticsOverviewData', options, (error, result) => {
Expand Down Expand Up @@ -150,17 +161,49 @@ Template.livechatAnalytics.helpers({
}
return true;
},
departmentModifier() {
return (filter, text = '') => {
const f = filter.get();
return `${ f.length === 0 ? text : text.replace(new RegExp(filter.get(), 'i'), (part) => `<strong>${ part }</strong>`) }`;
};
},
onClickTagDepartment() {
return Template.instance().onClickTagDepartment;
},
selectedDepartments() {
return Template.instance().selectedDepartments.get();
},
onSelectDepartments() {
return Template.instance().onSelectDepartments;
},
hasDepartments() {
return Template.instance().hasDepartments.get();
},
});


Template.livechatAnalytics.onCreated(function() {
Template.livechatAnalytics.onCreated(async function() {
templateInstance = Template.instance();

this.analyticsOverviewData = new ReactiveVar();
this.agentOverviewData = new ReactiveVar();
this.daterange = new ReactiveVar({});
this.analyticsOptions = new ReactiveVar(analyticsAllOptions()[0]); // default selected first
this.chartOptions = new ReactiveVar(analyticsAllOptions()[0].chartOptions[0]); // default selected first
this.selectedDepartments = new ReactiveVar([]);
this.hasDepartments = new ReactiveVar(false);

this.onSelectDepartments = ({ item: department }) => {
department.text = department.name;
this.selectedDepartments.set([department]);
};

this.onClickTagDepartment = () => {
this.selectedDepartments.set([]);
};

const { departments } = await APIClient.v1.get('livechat/department?count=1');
this.hasDepartments.set(departments?.length > 0);

this.autorun(() => {
templateInstance.daterange.set(setDateRange());
Expand All @@ -169,7 +212,9 @@ Template.livechatAnalytics.onCreated(function() {

Template.livechatAnalytics.onRendered(() => {
Tracker.autorun(() => {
if (templateInstance.daterange.get() && templateInstance.analyticsOptions.get() && templateInstance.chartOptions.get()) {
if (templateInstance.daterange.get()
&& templateInstance.analyticsOptions.get()
&& templateInstance.chartOptions.get()) {
updateAnalyticsOverview();
updateAnalyticsChart();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,27 @@
</select>
<i class="icon-angle-down"></i>
</div>
{{#if hasDepartments }}
<div class="form-group ">
{{> livechatAutocompleteUser
onClickTag=onClickTagDepartment
list=selectedDepartments
onSelect=onSelectDepartments
collection='CachedDepartmentList'
endpoint='livechat/department.autocomplete'
field='name'
sort='name'
placeholder="Select_a_department"
name="department"
icon="queue"
noMatchTemplate="userSearchEmpty"
templateItem="popupList_item_channel"
template="roomSearch"
noMatchTemplate="roomSearchEmpty"
modifier=departmentModifier
}}
</div>
{{/if}}
</form>
{{#if isLoading}}
{{> loading }}
Expand Down
Loading

0 comments on commit 48c43c6

Please sign in to comment.