# Release v1.16.7
## Services
### Update services
* [core] [done] core service
* [core] [done] main worker service
* [core] [done] modules:
* [done] NICE inContact
* [done] rake user app worker
* [core] [done] admin service
* [core] [done] permissions service
* [core] [done] user app worker service
* [core] [done] event trigger service
* [core] [not need] statistic service
* [core] [inprogress] rake chat widget service
* [core] [done] event notifications service
### New services
* [user-app] notifications service
* [user-app] billings service
* [core] [done] api service
* [core] [done] resource defaults service
## DB
### [done] Email aliases
#### [done] systemUsers collection
Script for converting existing data
```
const data = db.systemUsers.find({ email: { $exists: true } }).toArray();
const workspaces = db.workspaces.find().projection({ workspaceId: 1, workspaceStatusId: 1 }).toArray().reduce((acc, cur) => {
acc[cur.workspaceId] = cur.workspaceStatusId;
return acc;
}, {});
data.forEach((systemUser, i) => {
let result = db.workspaceSystemUsers.find({ systemUserId: systemUser.systemUserId })
.toArray().map(e => {
return {
id: e.workspaceId,
email: (e.emails && e.emails[0]) || systemUser.email,
isVerifiedEmail: systemUser.isVerifiedEmail,
updatedEmail: systemUser.updatedEmail,
referenceValues: {
workspaceStatusId: workspaces[e.workspaceId],
workspaceSystemUserStatusId: e.status
}
}
}).reduce((acc, cur) => {
acc.workspaces.push(cur);
return acc;
}, { systemUserId: systemUser.systemUserId, fieldName: 'workspaces', workspaces: [] });
db.systemUsers.updateOne(
{ systemUserId: result.systemUserId },
{ $push: { [`emails.${result.fieldName}`]: { $each: result[result.fieldName] } } }
);
result = db.projectSystemUsers.find({ systemUserId: systemUser.systemUserId })
.toArray().map(e => {
return {
id: e.projectId,
email: (e.emails && e.emails[0]) || systemUser.email,
isVerifiedEmail: systemUser.isVerifiedEmail,
updatedEmail: systemUser.updatedEmail,
}
}).reduce((acc, cur) => {
acc.projects.push(cur);
return acc;
}, { systemUserId: systemUser.systemUserId, fieldName: 'projects', projects: [] });
db.systemUsers.updateOne(
{ systemUserId: result.systemUserId },
{ $push: { [`emails.${result.fieldName}`]: { $each: result[result.fieldName] } } }
);
result = db.organizationSystemUsers.find({ systemUserId: systemUser.systemUserId })
.toArray().map(e => {
return {
id: e.organizationId,
email: (e.emails && e.emails[0]) || systemUser.email,
isVerifiedEmail: systemUser.isVerifiedEmail,
updatedEmail: systemUser.updatedEmail,
}
}).reduce((acc, cur) => {
acc.organizations.push(cur);
return acc;
}, { systemUserId: systemUser.systemUserId, fieldName: 'organizations', organizations: [] });
db.systemUsers.updateOne(
{ systemUserId: result.systemUserId },
{ $push: { [`emails.${result.fieldName}`]: { $each: result[result.fieldName] } } }
);
console.log(`${i} from ${data.length} systemUserId:${result.systemUserId}`)
})
```
### [done] Reference values
#### [not need] sessions collection
Schema:
```=javascript
{ referenceValues: { workspace: { name } } }
```
Script for converting existing data
```=javascript
```
Schema:
```=javascript
{
entities: {
referenceValues: {
entity: {
firstName,
lastName,
profile: { imageUrl, color }
}
}
}
}
```
Script for converting existing data
```=javascript
```
#### [done] systemUsers collection
Schema:
```=javascript
{
emails: {
workspaces: {
referenceValues: { workspaceStatusId, workspaceSystemUserStatusId }
}
}
}
```
#### [done] workspace/project/organizationSystemUser
Schema:
```=javascript
{
referenceValues: {
entity: {
email,
entityId,
firstName,
lastName,
phoneNumber
}
}
}
```
Script for converting existing data
```=javascript
const systemUsers = db.systemUsers.aggregate([
{
$lookup: {
from: 'entities',
localField: 'entityId',
foreignField: 'entityId',
as: 'entity'
}
},
{ $unwind: '$entity' },
]).toArray();
systemUsers.forEach((systemUser,i) => {
const entity = {
entityId: systemUser.entityId,
firstName: systemUser.entity.firstName,
lastName: systemUser.entity.lastName,
phoneNumber: systemUser.entity.phoneNumber,
email: systemUser.entity.email,
};
[
db.workspaceSystemUsers,
db.projectSystemUsers,
db.organizationSystemUsers
].forEach(collection => {
collection.updateOne(
{ systemUserId: systemUser.systemUserId },
{ $set: { 'referenceValues.entity': entity } }
);
console.log(`${i} from ${systemUsers.length}`);
});
})
```
#### [done] workspaces collection
Schema:
```=javascript
{ referenceValues: { modules: { count } } }
```
Script for converting existing data
```=javascript
let res = db.workspaces.aggregate([{
$lookup: {
from: "workspaceModules",
localField: "workspaceId",
foreignField: "workspaceId",
as: "workspaceModules"
}
},
{
$project: {
workspaceId: 1,
count: {$size: "$workspaceModules" }
}
},
]).toArray()
for(let item of res) {
db.workspaces.update({workspaceId: item.workspaceId}, {$set: {
"referenceValues.modules.count": item.count
}})
}
```
### [done] Mongo trigger
| actionId | operation name |
| -------- | ---- |
| 1 | replace |
| 2 | insert |
| 3 | update |
| 4 | delete |
| trigger name | description |
| ------------ | ----------- |
| messages_2 | Updating messageCount field in session collection |
| organizationSystemUsers_2 | Put in organizationSystemUsers doc referenceValue entity: { entityId, firstName, lastName, phoneNumber, email }
| projectSystemUsers_2 | Put in projectSystemUsers doc referenceValue entity: { entityId, firstName, lastName, phoneNumber, email }
| workspaceSystemUsers_2_3 | Put in workspaceSystemUsers doc referenceValue entity: { entityId, firstName, lastName, phoneNumber, email }. Creating system events -142(workspace system user was created), -143(workspace system user was updated)
| entities_2_3 | Creting system evnets -166(create entity), -167(update entity).<br>Updating referenceValues in workspaceSystemUser, projectSystemUser, orgnaizationSystemUser, sessions
| workspaces_3 | Update reference values in session collections
| workspaceModules_1_4_workspaces | Increment or decrement workspace reference value: modules.count
| twilio_workspace_2_3 | Put and update field attachedToScope.count
| rake_live_chat_workspace_2_3 | Put and update field attachedToScope.count
| rake_direct_workspace_2_3 | Put and update field attachedToScope.count
| inContact_workspace_2_3 | Put and update field attachedToScope.count
| facebook_workspace_2_3 | Put and update field attachedToScope.count
| entities_3 | creating system event id: -139 (system user was updated) and update referenceValues
| systemUsers_2_3 | Creating uniqueIndexedEmails set of emails. Creating system event ids: -140(system user was created), -139(system user was updated)
| workspaces_2_3_workspace | Creating system events ids: -137(workspace was created), -141(workspace was deactivated), -138(workspace was updated)
### [done] Roles
* [done] Update field names assignments.typeId => assignments.type, scope.typeId => scope.type,
```=javascript
db.roles.updateMany({}, [{
$set: {
'assignments.type': '$assignments.typeId',
'scope.type': '$scope.typeId'
}
}])
```
* [done] Update general roles. Add assignments.type field
```=javascript
db.roles.updateMany(
{ roleId: { $in: [1,2,3] }},
{ $set: { 'assignments.type': 'organization' } }
)
db.roles.updateMany(
{ roleId: { $in: [4,5,6,12] }},
{ $set: { 'assignments.type': 'project' } }
)
db.roles.updateMany(
{ roleId: { $in: [8,9,10,11] }},
{ $set: { 'assignments.type': 'workspace' } }
)
```
* [done] Add new systemFunction to general roles
```=javascript
const roleIds = [
1, // Org OWner
2, // Org admin
4, // Pro Owner
5, // Pro admin
8, // Work Owner
9, // Work admin
];
db.roles.updateMany(
{ roleId: { $in: roleIds } },
{ $push: {
systemFunctionIds: {
id: 591,
availablePermissionTypeIds: [2, 3]
}
}}
)
```
* sync uat value and prod value
### systemConfig collections
```
db.systemConfigs.updateOne({ nodeEnv: 'prod' }, {
$set: {
'resourceDefaults': {
'roles': {
'zapier': -1,
'agent': 12,
'organization': {
'defaultRoleIds': [
1,
2,
3
],
'creatorRoleId': 1
},
'project': {
'defaultRoleIds': [
4,
5,
6
],
'creatorRoleId': 4
},
'workspace': {
'defaultRoleIds': [
8,
9,
10
],
'creatorRoleId': 8,
'invitationIds': [
10
]
}
},
'channels': {
'workspace': [
{
'isPublic': true,
'name': 'general',
'membershipTypeId': 2
},
{
'isPublic': true,
'name': 'external',
'membershipTypeId': 1
},
{
'isPublic': true,
'name': 'sales',
'membershipTypeId': 0
}
]
},
'platforms': {
'workspace': [
{
'platformId': 2
},
{
'platformId': 5
}
]
},
'modules': {
'workspace': [
36
]
},
'billings': {
'workspace': 18
},
'businessHours': {
'workspace': {
'hours': {
'1': {
'closed': false,
'opening': { 'hour': 0, 'minute': 0 },
'closing': { 'hour': 24, 'minute': 0 }
},
'2': {
'closed': false,
'opening': { 'hour': 0, 'minute': 0 },
'closing': { 'hour': 24, 'minute': 0 }
},
'3': {
'closed': false,
'opening': { 'hour': 0, 'minute': 0 },
'closing': { 'hour': 24, 'minute': 0 }
},
'4': {
'closed': false,
'opening': { 'hour': 0, 'minute': 0 },
'closing': { 'hour': 24, 'minute': 0 }
},
'5': {
'closed': false,
'opening': { 'hour': 0, 'minute': 0 },
'closing': { 'hour': 24, 'minute': 0 }
},
'6': {
'closed': false,
'opening': { 'hour': 0, 'minute': 0 },
'closing': { 'hour': 24, 'minute': 0 }
},
'7': {
'closed': false,
'opening': { 'hour': 0, 'minute': 0 },
'closing': { 'hour': 24, 'minute': 0 }
}
}
}
}
},
'resourceDefaultsUrl': 'https://resources-default-2dfusaeaaa-uc.a.run.app',
'rakeUserApp': {
'default': {
'projectId': 34
}
}
}
})
```
### [done] entityTypes collection
```json=
db.getCollection("entityTypes").insert({
"entityTypeId": 11,
"isMergeEligible": false,
"name": "API user"
})
```
### [done] systemFunctions collection
Put all docs from UAT env
### [done] events collection
```=javascript
db.getCollection("events").insert({
"systemEventId": -166,
"name": "Create entity record",
"systemReference": "entity.created"
})
db.getCollection("events").insert({
"systemEventId": -167,
"name": "Update entity record",
"systemReference": "entity.updated"
})
```
### eventTriggers collection
Must be inserted eventTriggerIds: -239, -240, -238, -236, -237, 64,63,65,-32-31, -116, -115,
```=javascript
db.eventTriggers.insert({
"eventIds": [
NumberInt(-132)
],
"filters": [],
"customFilter": "",
description: "Rake user app. Event about customer was created",
"actions": [
{
"arguments": [
{
"queueName" : "notifications",
"pack" : {
event: 'customer-created',
entityId: "{rawMessage.entityId}",
workspaceId: "{rawMessage.workspaceId}",
customerEntityId: "{rawMessage.customerEntityId}"
}
}
],
"id": NumberInt(3)
}
],
"eventTriggerId": NumberInt(-31),
"__v": NumberInt(0)
});
db.eventTriggers.insertOne({
"eventIds": [
NumberInt(-166), -167
],
"filters": [{
"filterOperatorId": 5,
"filterId": -1,
"arguments": [
0,
'{rawMessage.entityTypeIds}'
]
}],
"customFilter": "",
"description": "Entity record was created",
"actions": [
{
"arguments": [
{
"queueName": "searchCache",
"pack": {
"event": "setCustomer",
"entityId": "{rawMessage.entityId}",
"entityTypeIds": "{rawMessage.entityTypeIds}",
"firstName": "{rawMessage.firstName}",
"lastName": "{rawMessage.lastName}",
"phoneNumber": "{rawMessage.phoneNumber}",
"email": "{rawMessage.email}",
"workspaceIds": "{rawMessage.scope.workspaceIds}",
"projectIds": "{rawMessage.scope.workspaceIds}",
"organizationIds": "{rawMessage.scope.workspaceIds}"
}
}
],
"id": NumberInt(3)
}
],
"eventTriggerId": NumberInt(-32) "__v": NumberInt(0)
})
```
### [done] entities collection
#### [done] Step 1
```=javascript
db.entities.updateMany({},{
$set: {
'scope.workspaceIds': [],
'scope.projectIds': [],
'scope.organizationIds': '$organizationIds'
}
})
```
#### [done] Step 2 workspaceEntities
```
let result = db.workspaceEntities.aggregate([
{ $match: {workspaceId: {$exists: true }}},
{
$group: {
_id: { workspaceId: '$workspaceId' },
entityIds: {$push: '$entityId' }
}
},
{
$lookup: {
from: 'workspaces',
localField: '_id.workspaceId',
foreignField: 'workspaceId',
as: 'workspace'
}},
{
$lookup: {
from: 'projects',
localField: 'workspace.projectId',
foreignField: 'projectId',
as: 'project'
}},
]
).toArray()
for(let item of result) {
db.entities.updateMany({entityId: {$in: item.entityIds}},
{$addToSet: {
'scope.workspaceIds': item._id.workspaceId,
'scope.projectIds': item.project[0].projectId,
'scope.organizationIds': item.project[0].organizationId
}})
}
```
#### [done] Step 3 workspaceSystemUsers
```
let result =
db.workspaceSystemUsers.aggregate([{
$match: {workspaceId: {$exists: true },
}},
{
$group: {
_id: { workspaceId: '$workspaceId' },
systemUserIds: {$push: '$systemUserId' }
}
},
{
$lookup: {
from: 'systemUsers',
localField: 'systemUserIds',
foreignField: 'systemUserId',
as: 'systemUsers'
}},
{
$lookup: {
from: 'workspaces',
localField: '_id.workspaceId',
foreignField: 'workspaceId',
as: 'workspace'
}},
{
$lookup: {
from: 'projects',
localField: 'workspace.projectId',
foreignField: 'projectId',
as: 'project'
}}]
)
.toArray()
for(let item of result) {
let entityIds = item.systemUsers.map(item => item.entityId)
let query = {'scope.workspaceIds': item._id.workspaceId}
if(item.project[0]){
query = {
...query,
'scope.projectIds': item.project[0].projectId,
'scope.organizationIds': item.project[0].organizationId
}
}
db.entities.updateMany({entityId: {$in: entityIds}},
{$addToSet: query})
}
```
#### [done] Step 4 projectSystemUser
```
let result =
db.projectSystemUsers.aggregate([{
$match: {projectId: {$exists: true },
}},
{
$group: {
_id: { projectId: '$projectId' },
systemUserIds: {$push: '$systemUserId' }
}
},
{
$lookup: {
from: 'systemUsers',
localField: 'systemUserIds',
foreignField: 'systemUserId',
as: 'systemUsers'
}},
{
$lookup: {
from: 'projects',
localField: '_id.projectId',
foreignField: 'projectId',
as: 'project'
}},
]
)
.toArray()
for(let item of result) {
let entityIds = item.systemUsers.map(item => item.entityId)
let query = {}
if(item.project[0]){
query = {
...query,
'scope.projectIds': item.project[0].projectId,
'scope.organizationIds': item.project[0].organizationId
}
}
if(Object.keys(query).length === 0) {
continue
}
db.entities.updateMany({entityId: {$in: entityIds}},
{$addToSet: query})
}
```
#### [done] Step 5 organizationSystemUsers
```=javascript
let result =
db.organizationSystemUsers.aggregate([{
$match: {organizationId: {$exists: true },
}},
{
$group: {
_id: { organizationId: '$organizationId' },
systemUserIds: {$push: '$systemUserId' }
}
},
{
$lookup: {
from: 'systemUsers',
localField: 'systemUserIds',
foreignField: 'systemUserId',
as: 'systemUsers'
}}
]
)
.toArray()
for(let item of result) {
let entityIds = item.systemUsers.map(item => item.entityId)
db.entities.updateMany({entityId: {$in: entityIds}},
{$addToSet: { 'scope.organizationIds': item._id.organizationId}})
}
```
### [done] systemApplications collection
Put all docs from UAT env
### [done] facebookWorkspaces collection (Max?)
```
const result = db.facebookMessenger_Workspaces.aggregate([
{
$group: {
_id: { appId : "$appId" },
count: { $sum: 1 }
}
}
]).toArray();
let promises = [];
for(let item of result) {
promises.push(
db.facebook_Applications.updateOne({
appId: item._id.appId
},
{
$set: { "attachedToScope": {
type: 'workspace',
count: item.count }
}
})
)
}
try {
Promise.all(promises)
} catch (err){
console.log(JSON.stringify(err))
}
db.facebookMessenger_Workspaces.dropIndex("appId_1_pageId_1")
let data = db.facebookMessenger_Workspaces.aggregate([
{
$match: {
appId: { $exists: true }
}
},
{
$lookup: {
'from': 'facebook_Applications',
localField: 'appId',
foreignField: 'appId',
as: 'facebookApp'
}
}
]).toArray()
for(let item of data){
let { facebookWorkspaceId, facebookApp } = item;
let { facebookAppId } = facebookApp[0];
db.facebookMessenger_Workspaces.update({facebookWorkspaceId}, {
$set: {
facebookAppId
},
$unset: {
appId: ''
}
}
})
}
```
### [done] facebookApplication collection (Max?)
```
let result =
db.facebook_Applications.aggregate({
$lookup: {
from: 'facebookMessenger_Workspaces',
localField: 'appId',
foreignField: 'appId',
as: 'workspaces'
}},
{
$unwind: {
path: '$workspaces',
preserveNullAndEmptyArrays: true
}
},
{
$group: {
_id: { appId: '$appId' },
workspaces: {$addToSet: '$workspaces.workspaceId'},
projectId: {$first: '$projectId' }
}
}
)
.toArray();
for(let item of result) {
if(item.workspaces.length > 0) {
db.facebook_Applications.update({appId: item._id.appId},
{
$set: {
scope: { type: 'workspace', ids: item.workspaces }
}
}
)
} else {
db.facebook_Applications.update({appId: item._id.appId},
{
$set: {
scope: { type: 'project', ids: [item.projectId] }
}
}
)
}
}
```
### [done] inContactWorkspaces collection (Max?)
```
const result = db.inContact_Workspaces.aggregate([
{
$group: {
_id: { inContactAppConfigId : "$inContactAppConfigId" },
count: { $sum: 1 }
}
}
]).toArray();
let promises = [];
for(let item of result) {
promises.push(
db.inContact_AppConfigurations.updateOne({
inContactAppConfigId: item._id.inContactAppConfigId
},
{
$set: { "attachedToScope": {
type: 'workspace',
count: item.count }
}
})
)
}
try {
Promise.all(promises)
} catch (err){
console.log(JSON.stringify(err))
}
```
### [done] inContactApp collection (Max?)
```
let result =
db.inContact_AppConfigurations.aggregate({
$lookup: {
from: 'inContact_Workspaces',
localField: 'inContactAppConfigId',
foreignField: 'inContactAppConfigId',
as: 'workspaces'
}},
{
$unwind: {
path: '$workspaces',
preserveNullAndEmptyArrays: true
}
},
{
$group: {
_id: { inContactAppConfigId: '$inContactAppConfigId' },
workspaces: {$addToSet: '$workspaces.workspaceId'},
projectId: {$first: '$projectId' }
}
}
)
.toArray();
for(let item of result) {
if(item.workspaces.length > 0) {
db.inContact_AppConfigurations.update({inContactAppConfigId: item._id.inContactAppConfigId},
{
$set: {
scope: { type: 'workspace', ids: item.workspaces }
}
}
)
} else {
db.inContact_AppConfigurations.update({inContactAppConfigId: item._id.inContactAppConfigId},
{
$set: {
scope: { type: 'project', ids: [item.projectId] }
}
}
)
}
}
```
### [done] Rake direct collection(Max?)
```
const result = db.rakeDirect_Workspaces.aggregate([
{
$group: {
_id: { rakeDirectConfigurationId : "$rakeDirectConfigurationId" },
count: { $sum: 1 }
}
}
]).toArray();
let promises = [];
for(let item of result) {
promises.push(
db.rakeDirect_Configurations.updateOne({
rakeDirectConfigurationId: item._id.rakeDirectConfigurationId
},
{
$set: { "attachedToScope": {
type: 'workspace',
count: item.count }
}
})
)
}
try {
Promise.all(promises)
} catch (err){
console.log(JSON.stringify(err))
}
```
### [done] Rake Direct config collection(Max?)
```
let result =
db.rakeDirect_Configurations.aggregate({
$lookup: {
from: 'rakeDirect_Workspaces',
localField: 'rakeDirectConfigurationId',
foreignField: 'rakeDirectConfigurationId',
as: 'workspaces'
}},
{
$unwind: {
path: '$workspaces',
preserveNullAndEmptyArrays: true
}
},
{
$group: {
_id: { rakeDirectConfigurationId: '$rakeDirectConfigurationId' },
workspaces: {$addToSet: '$workspaces.workspaceId'},
projectId: {$first: '$projectId' }
}
}
)
.toArray();
for(let item of result) {
if(item.workspaces.length > 0) {
db.rakeDirect_Configurations.update({rakeDirectConfigurationId: item._id.rakeDirectConfigurationId},
{
$set: {
scope: { type: 'workspace', ids: item.workspaces }
}
}
)
} else {
db.rakeDirect_Configurations.update({rakeDirectConfigurationId: item._id.rakeDirectConfigurationId},
{
$set: {
scope: { type: 'project', ids: [item.projectId] }
}
}
)
}
}
```
### [done] Rake live chat collection(Max?)
```
const result = db.rakeLiveChat_Workspaces.aggregate([
{
$group: {
_id: { rakeLiveChatConfigId : "$rakeLiveChatConfigId" },
count: { $sum: 1 }
}
}
]).toArray();
let promises = [];
for(let item of result) {
promises.push(
db.rakeLiveChat_Configurations.updateOne({
rakeLiveChatConfigId: item._id.rakeLiveChatConfigId
},
{
$set: { "attachedToScope": {
type: 'workspace',
count: item.count }
}
})
)
}
try {
Promise.all(promises)
} catch (err){
console.log(JSON.stringify(err))
}
```
### [done] Rake Live chat config colletion (Max?)
```
let result =
db.rakeLiveChat_Configurations.aggregate({
$lookup: {
from: 'rakeLiveChat_Workspaces',
localField: 'rakeLiveChatConfigId',
foreignField: 'rakeLiveChatConfigId',
as: 'workspaces'
}},
{
$unwind: {
path: '$workspaces',
preserveNullAndEmptyArrays: true
}
},
{
$group: {
_id: { rakeLiveChatConfigId: '$rakeLiveChatConfigId' },
workspaces: {$addToSet: '$workspaces.workspaceId'},
projectId: {$first: '$projectId' }
}
}
)
.toArray();
for(let item of result) {
if(item.workspaces.length > 0) {
db.rakeLiveChat_Configurations.update({rakeLiveChatConfigId: item._id.rakeLiveChatConfigId},
{
$set: {
scope: { type: 'workspace', ids: item.workspaces }
}
}
)
} else {
db.rakeLiveChat_Configurations.update({rakeLiveChatConfigId: item._id.rakeLiveChatConfigId},
{
$set: {
scope: { type: 'project', ids: [item.projectId] }
}
}
)
}
}
```
### [done] Twilio collection(Max?)
```
const result = db.twilioSMS_Workspaces.aggregate([
{
$group: {
_id: { twilioProjectId : "$twilioProjectId" },
count: { $sum: 1 }
}
}
]).toArray();
let promises = [];
for(let item of result) {
promises.push(
db.twilio_Projects.updateOne({
twilioProjectId: item._id.twilioProjectId
},
{
$set: { "attachedToScope": {
type: 'workspace',
count: item.count }
}
})
)
}
try {
Promise.all(promises)
} catch (err){
console.log(JSON.stringify(err))
}
```
### [done] Twilio Projects collection(Max?)
```
let result =
db.twilio_Projects.aggregate({
$lookup: {
from: 'twilioSMS_Workspaces',
localField: 'twilioProjectId',
foreignField: 'twilioProjectId',
as: 'workspaces'
}},
{
$unwind: {
path: '$workspaces',
preserveNullAndEmptyArrays: true
}
},
{
$group: {
_id: { twilioProjectId: '$twilioProjectId' },
workspaces: {$addToSet: '$workspaces.workspaceId'},
projectId: {$first: '$projectId' }
}
}
)
.toArray();
for(let item of result) {
if(item.workspaces.length > 0) {
db.twilio_Projects.update({twilioProjectId: item._id.twilioProjectId},
{
$set: {
scope: { type: 'workspace', ids: item.workspaces }
}
}
)
} else {
db.twilio_Projects.update({twilioProjectId: item._id.twilioProjectId},
{
$set: {
scope: { type: 'project', ids: [item.projectId] }
}
}
)
}
}
```
### [done] projects collection (Max?)
```
const projects = db.projects.find({}).toArray()
projects.forEach(item => {
if(item.settings && item.settings.languageCode) {
db.projects.update(
{projectId: item.projectId},
{$set: {
languageCode: item.settings.languageCode
},
$unset: {
settings: ""
}
})
}
})
projects.forEach(item => {
if(item.settings && item.settings.language) {
db.projects.update(
{projectId: item.projectId},
{$set: {
languageCode: item.settings.language
},
$unset: {
settings: ""
}
})
}
})
```
### [done] organizations collection (Max?)
```
const organizations = db.organizations.find({}).toArray()
organizations.forEach(item => {
if(item.settings && item.settings.languageCode) {
db.organizations.update(
{organizationId: item.organizationId},
{$set: {
languageCode: item.settings.languageCode
},
$unset: {
settings: ""
}
})
}
})
```
### [done] Zapier Workspaces(Max?)
```
db.getCollection("zapier_Workspaces").update({},
{ $set: { "isEnabled": NumberInt(1) } }, {multi: true})
```
## [done] Dynamic links updates
Run it from dynamic-links.js - admin service
```
const createDynamicLinksScript = async () => {
const invitations = await Invitations.find({
shortLink: { $exists: false },
'scope.type': 'workspace',
invitationTypeId: 1,
}).select(['token', 'scope', 'invitationId']).lean();
invitations.forEach(async (invitation) => {
const { shortLink } = await getDynamicLink({
link: module.exports.generateLinks.workspace
.inviteByLink(invitation.scope.id, invitation.token),
});
Invitation.findOneAndUpdate({
invitationId: invitation.invitationId,
}, {
$set: {
shortLink,
},
});
});
};
```
## [in progress] Presence updates
Fields for renaming
> subscribedAt --- > *createdAt*
> unsubscribedAt --- > *deletedAt*
Fields for removing
> systemUserPresenceId
> workspaceId
```=javascript
const systemUserPresences = db.systemUserPresences.find({});
db.systemUserPresences.dropIndex("systemUserPresenceId_1");
db.systemUserPresences.dropIndex("unsubscribedAt_1");
db.systemUserPresences.dropIndex("entityId_1_workspaceId_1_unsubscribedAt_1_pubnubConnectionType_1");
db.systemUserPresences.dropIndex("systemUserId_1_workspaceId_1_unsubscribedAt_1_pubnubConnectionType_1");
db.systemUserPresences.dropIndex("pubnubConnectionType_1");
db.systemUserPresences.dropIndex("entityId_1_workspaceId_1_unsubscribedAt_1_connectionType_1");
db.systemUserPresences.dropIndex("entityId_1_unsubscribedAt_1");
systemUserPresences.forEach((presence) => {
db.systemUserPresences.update({ _id: ObjectId(presence._id) }, {
$unset: { workspaceId: 1, systemUserPresenceId: 1 }
}, false, true);
db.systemUserPresences.update({ _id: ObjectId(presence._id) }, {
$rename: {
subscribedAt: 'createdAt',
unsubscribedAt: 'deletedAt',
}
});
console.log('presence updated: ' + presence._id);
});
db.getCollection("systemUserPresences").createIndex({ "deletedAt": 1 }, {
expireAfterSeconds: 172800,
partialFilterExpression: {
connectionType: { $eq: 'web' },
deletedAt: { $exists: true },
},
});
db.getCollection("systemUserPresences").createIndex({ "entityId": 1, deletedAt: 1, connectionType: 1 });
db.getCollection("systemUserPresences").createIndex({ "entityId": 1, deletedAt: 1 });
```
## [done] Channels updates
### Default channels
```=javascript
const membershipTypes = {
standard: 0,
default: 1,
locked: 2,
};
const sessionsWithDefaultChannels = db.sessions.find({ channel: { $exists: true }, 'channel.isDefault': true });
sessionsWithDefaultChannels.forEach((session) => {
const update = {
"isDirect" : session.channel.isDirect,
"_id" : session.channel._id,
"entityId" : session.channel.entityId,
"isPublic" : session.channel.isPublic,
"channelId" : session.channel.channelId,
"name" : session.channel.name,
membershipTypeId: membershipTypes.locked,
};
db.sessions.updateOne({ sessionId: session.sessionId }, {
$set: {
channel: update,
},
});
console.log('session updated: ' + session.sessionId);
});
```
### Standard channels
```
const membershipTypes = {
standard: 0,
default: 1,
locked: 2,
};
const sessionsChannels = db.sessions.find({ channel: { $exists: true }, 'channel.isDefault': false });
sessionsChannels.forEach((session) => {
const update = {
"isDirect" : session.channel.isDirect,
"_id" : session.channel._id,
"entityId" : session.channel.entityId,
"isPublic" : session.channel.isPublic,
"channelId" : session.channel.channelId,
"name" : session.channel.name,
membershipTypeId: membershipTypes.standard,
};
db.sessions.updateOne({ sessionId: session.sessionId }, {
$set: {
channel: update,
},
});
console.log('session updated: ' + session.sessionId);
});
```
### Assign owner and creator
```
const sessionsChannels = db.sessions.find({ channel: { $exists: true } });
sessionsChannels.forEach((session) => {
const entities = session.entities.filter(one => !one.isInitiator).sort((a, b) => a.entityId - b.entityId);
if (!entities.length) {
console.log('No other but initator found in sessionId: ' + session.sessionId);
}
const [owner] = entities;
db.sessions.updateOne({ sessionId: session.sessionId }, {
$set: {
channel: {
...session.channel,
ownerEntityId: owner.entityId,
creatorEntityId: owner.entityId,
},
},
});
console.log('session updated: ' + session.sessionId);
});
```
## Last steps
### Clean up collections
```
db.appDevices.drop()
db.billingPlanFeatureRates.drop()
db.billingInvoices.drop()
db.billingPaymentQueue.drop()
db.billingPlanFeatureAddOns.drop()
db.billingPlanWorkspaces.drop()
db.billingProcessLogs.drop()
db.billingTransactionsInvoices.drop()
db.billingTypes.drop()
db.billingWorkspaceCredits.drop()
db.conversationStatuses.drop()
db.customers.drop()
db.organizationSettings.drop()
db.phoneTypes.drop()
db.platformPreconfiguredAssets.drop()
db.projectSettings.drop()
db.roleSystemPermissions.drop()
db.services.drop()
db.sessionEntities.drop()
db.systemUserContacts.drop()
db.systemUserRoles.drop()
db.systemUserSettings.drop()
db.systemUserStatuses.drop()
db.teamSystemUsers.drop()
db.tutorialItems.drop()
db.tutorialItemRoles.drop()
db.tutorialItemSystemUsers.drop()
db.workspaceEntities.drop()
db.workspacePaymentTransactions.drop()
db.workspaceSettings.drop()
```
### User profiles
regenarate user profiles by permissions cache route
### other steps
```
db.twilio_Projects.dropIndex("accountSid_1")
db.twilio_Projects.dropIndex("projectId_1_accountSid_1");
db.twilio_Projects.createIndex(
{
projectId: 1,
accountSid: 1
},
{
name: "projectId_1_accountSid_1",
background: true
}
)
db.getCollection("twilio_Projects").createIndex(
{ "accountSid": 1, "scope.ids": 1, "scope.type": 1 },
{ name: 'UniqueConfiguration', unique: true, partialFilterExpression: { "scope": { $exists: true } } }
)
db.rakeLiveChat_Configurations.dropIndex("configurationName_1_projectId_1")
db.facebook_Applications.updateMany({}, { $unset: { projectId: 1 } });
db.inContact_AppConfigurations.updateMany({}, { $unset: { projectId: 1 } });
db.rakeDirect_Configurations.updateMany({}, { $unset: { projectId: 1 } });
db.rakeLiveChat_Configurations.updateMany({}, { $unset: { projectId: 1 } });
db.twilio_Projects.updateMany({}, { $unset: { projectId: 1 } });
```