Browse Source

fix: add upgrader to merge and recover broken plugins

pull/9894/head
Pranav C 18 hours ago
parent
commit
77be7f9226
  1. 8
      packages/nocodb/src/controllers/plugins.controller.ts
  2. 22
      packages/nocodb/src/helpers/NcPluginMgrv2.ts
  3. 29
      packages/nocodb/src/models/Plugin.ts
  4. 2
      packages/nocodb/src/plugins/backblaze/index.ts
  5. 2
      packages/nocodb/src/plugins/linode/index.ts
  6. 2
      packages/nocodb/src/plugins/ovhCloud/index.ts
  7. 2
      packages/nocodb/src/plugins/r2/index.ts
  8. 2
      packages/nocodb/src/plugins/scaleway/index.ts
  9. 2
      packages/nocodb/src/plugins/twilioWhatsapp/index.ts
  10. 2
      packages/nocodb/src/plugins/upcloud/index.ts
  11. 2
      packages/nocodb/src/plugins/vultr/index.ts
  12. 2
      packages/nocodb/src/providers/init-meta-service.provider.ts
  13. 4
      packages/nocodb/src/services/plugins.service.ts
  14. 2
      packages/nocodb/src/types/nc-plugin/lib/XcPluginConfig.ts
  15. 2
      packages/nocodb/src/version-upgrader/NcUpgrader.ts
  16. 99
      packages/nocodb/src/version-upgrader/upgraders/0258003_ncDuplicatePluginMerge.ts

8
packages/nocodb/src/controllers/plugins.controller.ts

@ -82,15 +82,15 @@ export class PluginsController {
}
@Get([
'/api/v1/db/meta/plugins/:pluginTitle/status',
'/api/v2/meta/plugins/:pluginTitle/status',
'/api/v1/db/meta/plugins/:pluginId/status',
'/api/v2/meta/plugins/:pluginId/status',
])
@Acl('isPluginActive', {
scope: 'org',
})
async isPluginActive(@Param('pluginTitle') pluginTitle: string) {
async isPluginActive(@Param('pluginId') pluginId: string) {
return await this.pluginsService.isPluginActive({
pluginTitle: pluginTitle,
pluginId,
});
}
}

22
packages/nocodb/src/helpers/NcPluginMgrv2.ts

@ -67,15 +67,26 @@ class NcPluginMgrv2 {
// }
public static async init(ncMeta = Noco.ncMeta): Promise<void> {
// extract duplicate plugin ids from default plugins and throw error
const duplicateIds = defaultPlugins
.map((p) => p.id)
.filter((id, index, self) => self.indexOf(id) !== index);
if (duplicateIds.length) {
throw new Error(
`Duplicate plugin ids found in default plugins: ${duplicateIds.join(
', ',
)}`,
);
}
/* Populate rows into nc_plugins table if not present */
for (const plugin of defaultPlugins) {
const pluginConfig = await ncMeta.metaGet(
RootScopes.ROOT,
RootScopes.ROOT,
MetaTable.PLUGIN,
{
title: plugin.title,
},
plugin.id,
);
if (!pluginConfig) {
@ -84,6 +95,7 @@ class NcPluginMgrv2 {
RootScopes.ROOT,
MetaTable.PLUGIN,
{
id: plugin.id,
title: plugin.title,
version: plugin.version,
logo: plugin.logo,
@ -121,7 +133,7 @@ class NcPluginMgrv2 {
* */
if (process.env.NC_S3_BUCKET_NAME && process.env.NC_S3_REGION) {
const s3Plugin = await Plugin.getPluginByTitle(S3PluginConfig.title);
const s3Plugin = await Plugin.getPlugin(S3PluginConfig.id);
const s3CfgData: Record<string, any> = {
bucket: process.env.NC_S3_BUCKET_NAME,
region: process.env.NC_S3_REGION,
@ -144,7 +156,7 @@ class NcPluginMgrv2 {
process.env.NC_SMTP_HOST &&
process.env.NC_SMTP_PORT
) {
const smtpPlugin = await Plugin.getPluginByTitle(SMTPPluginConfig.title);
const smtpPlugin = await Plugin.getPlugin(SMTPPluginConfig.title);
await Plugin.update(smtpPlugin.id, {
active: true,
input: JSON.stringify({

29
packages/nocodb/src/models/Plugin.ts

@ -89,23 +89,22 @@ export default class Plugin implements PluginType {
);
await NocoCache.update(`${CacheScope.PLUGIN}:${pluginId}`, updateObj);
await NocoCache.update(`${CacheScope.PLUGIN}:${plugin.title}`, updateObj);
return this.get(pluginId);
}
public static async isPluginActive(title: string) {
return !!(await this.getPluginByTitle(title))?.active;
public static async isPluginActive(id: string) {
return !!(await this.getPlugin(id))?.active;
}
/**
* get plugin by title
* get plugin by id
*/
public static async getPluginByTitle(title: string, ncMeta = Noco.ncMeta) {
public static async getPlugin(id: string, ncMeta = Noco.ncMeta) {
let plugin =
title &&
id &&
(await NocoCache.get(
`${CacheScope.PLUGIN}:${title}`,
`${CacheScope.PLUGIN}:${id}`,
CacheGetType.TYPE_OBJECT,
));
if (!plugin) {
@ -113,12 +112,20 @@ export default class Plugin implements PluginType {
RootScopes.ROOT,
RootScopes.ROOT,
MetaTable.PLUGIN,
{
title,
},
id,
);
await NocoCache.set(`${CacheScope.PLUGIN}:${title}`, plugin);
await NocoCache.set(`${CacheScope.PLUGIN}:${id}`, plugin);
}
return plugin;
}
// keeping it for backward compatibility, if someone configured google auth via plugin it still relies on this
static async getPluginByTitle(title: string, ncMeta = Noco.ncMeta) {
return await ncMeta.metaGet2(
RootScopes.ROOT,
RootScopes.ROOT,
MetaTable.PLUGIN,
{ title },
);
}
}

2
packages/nocodb/src/plugins/backblaze/index.ts

@ -6,7 +6,7 @@ const config: XcPluginConfig = {
builder: BackblazePlugin,
id: 'backblaze',
title: 'Backblaze',
fallbackTitles: ['Backblaze B2'],
fallbackTitle: 'Backblaze B2',
version: '0.0.5',
logo: 'plugins/backblaze.jpeg',
tags: 'Storage',

2
packages/nocodb/src/plugins/linode/index.ts

@ -5,7 +5,7 @@ import type { XcPluginConfig } from '~/types/nc-plugin';
const config: XcPluginConfig = {
builder: LinodeObjectStoragePlugin,
id: 'linode',
fallbackTitles: ['Linode Object Storage'],
fallbackTitle: 'Linode Object Storage',
title: 'Linode',
version: '0.0.4',
logo: 'plugins/linode.svg',

2
packages/nocodb/src/plugins/ovhCloud/index.ts

@ -6,7 +6,7 @@ const config: XcPluginConfig = {
builder: OvhCloud,
id: 'ovh',
title: 'Ovh',
fallbackTitles: ['OvhCloud Object Storage'],
fallbackTitle: 'OvhCloud Object Storage',
version: '0.0.4',
logo: 'plugins/ovhCloud.png',
tags: 'Storage',

2
packages/nocodb/src/plugins/r2/index.ts

@ -6,7 +6,7 @@ const config: XcPluginConfig = {
builder: R2Plugin,
id: 'cloudflare-r2',
title: 'Cloudflare R2',
fallbackTitles: ['Cloudflare R2 Storage'],
fallbackTitle: 'Cloudflare R2 Storage',
version: '0.0.3',
logo: 'plugins/r2.png',
description:

2
packages/nocodb/src/plugins/scaleway/index.ts

@ -6,7 +6,7 @@ const config: XcPluginConfig = {
builder: ScalewayObjectStoragePlugin,
id: 'scaleway',
title: 'Scaleway',
fallbackTitles: ['Scaleway Object Storage'],
fallbackTitle: 'Scaleway Object Storage',
version: '0.0.4',
logo: 'plugins/scaleway.png',
tags: 'Storage',

2
packages/nocodb/src/plugins/twilioWhatsapp/index.ts

@ -4,7 +4,7 @@ import type { XcPluginConfig } from '~/types/nc-plugin';
const config: XcPluginConfig = {
builder: TwilioWhatsappPlugin,
id: 'twilio',
id: 'twilio-whatsapp',
title: 'Whatsapp Twilio',
version: '0.0.1',
logo: 'plugins/whatsapp.png',

2
packages/nocodb/src/plugins/upcloud/index.ts

@ -6,7 +6,7 @@ const config: XcPluginConfig = {
builder: UpCloudPlugin,
id: 'upcloud',
title: 'UpCloud',
fallbackTitles: ['UpCloud Object Storage'],
fallbackTitle: 'UpCloud Object Storage',
version: '0.0.4',
logo: 'plugins/upcloud.png',
description:

2
packages/nocodb/src/plugins/vultr/index.ts

@ -6,7 +6,7 @@ const config: XcPluginConfig = {
builder: VultrPlugin,
title: 'Vultr',
id: 'vultr',
fallbackTitles: ['Vultr Object Storage'],
fallbackTitle: 'Vultr Object Storage',
version: '0.0.4',
logo: 'plugins/vultr.png',
description:

2
packages/nocodb/src/providers/init-meta-service.provider.ts

@ -31,7 +31,7 @@ export const InitMetaServiceProvider: FactoryProvider = {
const config = await NcConfig.createByEnv();
// set version
process.env.NC_VERSION = '0225002';
process.env.NC_VERSION = '0258003';
// set migration jobs version
process.env.NC_MIGRATION_JOBS_VERSION = '2';

4
packages/nocodb/src/services/plugins.service.ts

@ -50,8 +50,8 @@ export class PluginsService {
return plugin;
}
async isPluginActive(param: { pluginTitle: string }) {
return await Plugin.isPluginActive(param.pluginTitle);
async isPluginActive(param: { pluginId: string }) {
return await Plugin.isPluginActive(param.pluginId);
}
async webhookPluginList() {

2
packages/nocodb/src/types/nc-plugin/lib/XcPluginConfig.ts

@ -6,7 +6,7 @@ import type XcPluginMigration from './XcPluginMigration';
export default interface XcPluginConfig {
id: string;
title: string;
fallbackTitles?: string[];
fallbackTitle?: string;
logo?: string;
tags?: string;
description?: string;

2
packages/nocodb/src/version-upgrader/NcUpgrader.ts

@ -12,6 +12,7 @@ import ncXcdbLTARUpgrader from './upgraders/0108002_ncXcdbLTARUpgrader';
import ncXcdbLTARIndexUpgrader from './upgraders/0111002_ncXcdbLTARIndexUpgrader';
import ncXcdbCreatedAndUpdatedSystemFieldsUpgrader from './upgraders/0111005_ncXcdbCreatedAndUpdatedSystemFieldsUpgrader';
import ncDatasourceDecrypt from './upgraders/0225002_ncDatasourceDecrypt';
import ncDuplicatePluginMerge from './upgraders/0258003_ncDuplicatePluginMerge';
import type { MetaService } from '~/meta/meta.service';
import type { NcConfig } from '~/interface/config';
import { T } from '~/utils';
@ -150,6 +151,7 @@ export default class NcUpgrader {
{ name: '0111002', handler: ncXcdbLTARIndexUpgrader },
{ name: '0111005', handler: ncXcdbCreatedAndUpdatedSystemFieldsUpgrader },
{ name: '0225002', handler: ncDatasourceDecrypt },
{ name: '0258003', handler: ncDuplicatePluginMerge },
];
}
}

99
packages/nocodb/src/version-upgrader/upgraders/0258003_ncDuplicatePluginMerge.ts

@ -0,0 +1,99 @@
import type { NcUpgraderCtx } from '~/version-upgrader/NcUpgrader';
import SlackPluginConfig from '~/plugins/slack';
import TeamsPluginConfig from '~/plugins/teams';
import DiscordPluginConfig from '~/plugins/discord';
import TwilioWhatsappPluginConfig from '~/plugins/twilioWhatsapp';
import TwilioPluginConfig from '~/plugins/twilio';
import S3PluginConfig from '~/plugins/s3';
import MinioPluginConfig from '~/plugins/mino';
import GcsPluginConfig from '~/plugins/gcs';
import MattermostPluginConfig from '~/plugins/mattermost';
import SpacesPluginConfig from '~/plugins/spaces';
import BackblazePluginConfig from '~/plugins/backblaze';
import VultrPluginConfig from '~/plugins/vultr';
import OvhCloudPluginConfig from '~/plugins/ovhCloud';
import LinodePluginConfig from '~/plugins/linode';
import UpcloudPluginConfig from '~/plugins/upcloud';
import SMTPPluginConfig from '~/plugins/smtp';
import MailerSendConfig from '~/plugins/mailerSend';
import ScalewayPluginConfig from '~/plugins/scaleway';
import SESPluginConfig from '~/plugins/ses';
import R2PluginConfig from '~/plugins/r2';
import { MetaTable } from '~/cli';
const defaultPlugins = [
SlackPluginConfig,
TeamsPluginConfig,
DiscordPluginConfig,
TwilioWhatsappPluginConfig,
TwilioPluginConfig,
S3PluginConfig,
MinioPluginConfig,
GcsPluginConfig,
MattermostPluginConfig,
SpacesPluginConfig,
BackblazePluginConfig,
VultrPluginConfig,
OvhCloudPluginConfig,
LinodePluginConfig,
UpcloudPluginConfig,
SMTPPluginConfig,
MailerSendConfig,
ScalewayPluginConfig,
SESPluginConfig,
R2PluginConfig,
];
// This upgrader helps to merge the duplicate plugins and recover the broken plugins
// and also adds a unique id to the plugin to avoid the duplicate plugins in the future
export default async function ({ ncMeta }: NcUpgraderCtx) {
// get the plugins which are valid and matches the plugin title
// update the plugin with the new id
for (const pluginConfig of defaultPlugins) {
// get the valid plugin
const plugin = await ncMeta
.knex(MetaTable.PLUGIN)
.where('title', pluginConfig.title)
.first();
if (plugin) {
// update the plugin with the new id
await ncMeta
.knex(MetaTable.PLUGIN)
.where('id', plugin.id)
.update({ id: pluginConfig.id });
}
if (pluginConfig.fallbackTitle) {
// get the plugin with old title
const oldPlugin = await ncMeta
.knex(MetaTable.PLUGIN)
.where('title', pluginConfig.fallbackTitle)
.first();
if (plugin) {
// if the old plugin is present then update the new plugin with the old plugin configuration
// and only if new plugin is not configured and active
if (!plugin.active && oldPlugin.active) {
await ncMeta
.knex(MetaTable.PLUGIN)
.update({
input: oldPlugin.input,
active: true,
})
.where('id', plugin.id);
}
// delete the old plugin
await ncMeta.knex(MetaTable.PLUGIN).where('id', oldPlugin.id).delete();
} else {
// if new plugin is not present then update the old plugin with the new id
// we can skip rest of the props since it will get updated from the existing plugin initialization
await ncMeta
.knex(MetaTable.PLUGIN)
.where('id', oldPlugin.id)
.update({ id: pluginConfig.id });
}
}
}
}
Loading…
Cancel
Save