Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/gorgeous-cougars-visit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@rocket.chat/apps-engine': patch
'@rocket.chat/meteor': patch
---

Change app update strategies to prevent unwanted data changes in database
53 changes: 43 additions & 10 deletions apps/meteor/ee/server/apps/storage/AppRealStorage.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import type { AppStatus } from '@rocket.chat/apps-engine/definition/AppStatus';
import type { IAppInfo } from '@rocket.chat/apps-engine/definition/metadata';
import type { ISetting } from '@rocket.chat/apps-engine/definition/settings';
import type { IMarketplaceInfo } from '@rocket.chat/apps-engine/server/marketplace';
import type { IAppStorageItem } from '@rocket.chat/apps-engine/server/storage';
import { AppMetadataStorage } from '@rocket.chat/apps-engine/server/storage';
import type { Apps } from '@rocket.chat/models';
Expand Down Expand Up @@ -48,20 +52,49 @@ export class AppRealStorage extends AppMetadataStorage {
return items;
}

public async update({ permissionsGranted, ...item }: IAppStorageItem): Promise<IAppStorageItem> {
public async remove(id: string): Promise<{ success: boolean }> {
await this.db.deleteOne({ id });
return { success: true };
}

public async updatePartialAndReturnDocument(
{ _id, ...item }: IAppStorageItem,
{ unsetPermissionsGranted = false } = {},
): Promise<IAppStorageItem> {
if (!_id) {
throw new Error('Property _id is required to update an app storage item');
}

const updateQuery: UpdateFilter<IAppStorageItem> = {
$set: { ...item, ...(permissionsGranted && { permissionsGranted }) },
// Note: This is really important, since we currently store the permissionsGranted as null if none are present
// in the App's manifest. So, if there was a permissionGranted and it was removed, we must see the app as having
// no permissionsGranted at all (which means default permissions). So we must actively unset the field.
...(!permissionsGranted && { $unset: { permissionsGranted: 1 } }),
$set: item,
};

return this.db.findOneAndUpdate({ id: item.id, _id: item._id }, updateQuery, { returnDocument: 'after' });
if (unsetPermissionsGranted) {
delete item.permissionsGranted;
updateQuery.$unset = { permissionsGranted: 1 };
}

return this.db.findOneAndUpdate({ _id }, updateQuery, { returnDocument: 'after' });
}

public async remove(id: string): Promise<{ success: boolean }> {
await this.db.deleteOne({ id });
return { success: true };
public async updateStatus(_id: string, status: AppStatus): Promise<boolean> {
const result = await this.db.updateOne({ _id }, { $set: { status } });
return result.modifiedCount > 0;
}

public async updateSetting(_id: string, setting: ISetting): Promise<boolean> {
const result = await this.db.updateOne({ _id }, { $set: { [`settings.${setting.id}`]: setting } });

return result.modifiedCount > 0;
}

public async updateAppInfo(_id: string, info: IAppInfo): Promise<boolean> {
const result = await this.db.updateOne({ _id }, { $set: { info } });
return result.modifiedCount > 0;
}

public async updateMarketplaceInfo(_id: string, marketplaceInfo: IMarketplaceInfo[]): Promise<boolean> {
const result = await this.db.updateOne({ _id }, { $set: { marketplaceInfo } });
return result.modifiedCount > 0;
}
}
Loading
Loading