Browse Source

Merge pull request #9894 from nocodb/nc-fix/9890-duplicate-plugin

fix: Merge duplicate plugin and recover broken plugins
pull/9909/head
Pranav C 4 days ago committed by GitHub
parent
commit
4effc44682
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      packages/nc-gui/components/smartsheet/Form.vue
  2. 12
      packages/nc-gui/composables/useNocoAi.ts
  3. 6
      packages/noco-docs/versioned_docs/version-0.109.7/040.developer-resources/020.rest-apis.md
  4. 8
      packages/nocodb/src/controllers/plugins.controller.ts
  5. 24
      packages/nocodb/src/helpers/NcPluginMgrv2.ts
  6. 32
      packages/nocodb/src/models/Plugin.ts
  7. 2
      packages/nocodb/src/plugins/backblaze/index.ts
  8. 1
      packages/nocodb/src/plugins/discord/index.ts
  9. 1
      packages/nocodb/src/plugins/gcs/index.ts
  10. 2
      packages/nocodb/src/plugins/linode/index.ts
  11. 1
      packages/nocodb/src/plugins/mailerSend/index.ts
  12. 1
      packages/nocodb/src/plugins/mattermost/index.ts
  13. 0
      packages/nocodb/src/plugins/minio/Minio.ts
  14. 0
      packages/nocodb/src/plugins/minio/MinioPlugin.ts
  15. 1
      packages/nocodb/src/plugins/minio/index.ts
  16. 2
      packages/nocodb/src/plugins/ovhCloud/index.ts
  17. 2
      packages/nocodb/src/plugins/r2/index.ts
  18. 1
      packages/nocodb/src/plugins/s3/index.ts
  19. 2
      packages/nocodb/src/plugins/scaleway/index.ts
  20. 1
      packages/nocodb/src/plugins/ses/index.ts
  21. 1
      packages/nocodb/src/plugins/slack/index.ts
  22. 1
      packages/nocodb/src/plugins/smtp/index.ts
  23. 1
      packages/nocodb/src/plugins/spaces/index.ts
  24. 1
      packages/nocodb/src/plugins/teams/index.ts
  25. 1
      packages/nocodb/src/plugins/twilio/index.ts
  26. 1
      packages/nocodb/src/plugins/twilioWhatsapp/index.ts
  27. 2
      packages/nocodb/src/plugins/upcloud/index.ts
  28. 2
      packages/nocodb/src/plugins/vultr/index.ts
  29. 12
      packages/nocodb/src/providers/init-meta-service.provider.ts
  30. 4
      packages/nocodb/src/schema/swagger-v2.json
  31. 4
      packages/nocodb/src/schema/swagger.json
  32. 2
      packages/nocodb/src/services/command-palette.service.ts
  33. 4
      packages/nocodb/src/services/plugins.service.ts
  34. 2
      packages/nocodb/src/types/nc-plugin/lib/XcPluginConfig.ts
  35. 2
      packages/nocodb/src/version-upgrader/NcUpgrader.ts
  36. 127
      packages/nocodb/src/version-upgrader/upgraders/0258003_ncDuplicatePluginMerge.ts

2
packages/nc-gui/components/smartsheet/Form.vue

@ -484,7 +484,7 @@ async function handleAddOrRemoveAllColumns<T>(value: T) {
async function checkSMTPStatus() { async function checkSMTPStatus() {
if (emailMe.value && !isEeUI) { if (emailMe.value && !isEeUI) {
const emailPluginActive = await $api.plugin.status('SMTP') const emailPluginActive = await $api.plugin.status('smtp')
if (!emailPluginActive) { if (!emailPluginActive) {
emailMe.value = false emailMe.value = false
// Please activate SMTP plugin in App store for enabling email notification // Please activate SMTP plugin in App store for enabling email notification

12
packages/nc-gui/composables/useNocoAi.ts

@ -348,9 +348,17 @@ export const useNocoAi = createSharedComposable(() => {
} }
} }
onMounted(() => { const { signedIn } = useGlobal()
watch(
signedIn,
(val) => {
if (val) {
loadAiIntegrations() loadAiIntegrations()
}) }
},
{ immediate: true },
)
return { return {
aiIntegrationAvailable, aiIntegrationAvailable,

6
packages/noco-docs/versioned_docs/version-0.109.7/040.developer-resources/020.rest-apis.md vendored

@ -77,7 +77,7 @@ Currently, the default value for `{orgs}` is <b>noco</b>. Users will be able to
### Meta APIs ### Meta APIs
| Category | Method | Tag | Function Name | Path | | Category | Method | Tag | Function Name | Path |
|---|---|---|---|---| |---|---|---|---|-----------------------------------------------------------------------|
| Meta | Get | apiToken | list | /api/v1/db/meta/projects/`{projectId}`/api-tokens | | Meta | Get | apiToken | list | /api/v1/db/meta/projects/`{projectId}`/api-tokens |
| Meta | Post | apiToken | create | /api/v1/db/meta/projects/`{projectId}`/api-tokens | | Meta | Post | apiToken | create | /api/v1/db/meta/projects/`{projectId}`/api-tokens |
| Meta | Delete| apiToken | delete | /api/v1/db/meta/projects/`{projectId}`/api-tokens/`{token}` | | Meta | Delete| apiToken | delete | /api/v1/db/meta/projects/`{projectId}`/api-tokens/`{token}` |
@ -105,7 +105,7 @@ Currently, the default value for `{orgs}` is <b>noco</b>. Users will be able to
| Meta | Post | dbTableSort | create | /api/v1/db/meta/views/`{viewId}`/sorts | | Meta | Post | dbTableSort | create | /api/v1/db/meta/views/`{viewId}`/sorts |
| Meta | Get | dbTableSort | read | /api/v1/db/meta/sorts/`{sortId}` | | Meta | Get | dbTableSort | read | /api/v1/db/meta/sorts/`{sortId}` |
| Meta | Patch | dbTableSort | update | /api/v1/db/meta/sorts/`{sortId}` | | Meta | Patch | dbTableSort | update | /api/v1/db/meta/sorts/`{sortId}` |
| Meta | Delete| dbTableSort | delete | /api/v1/db/meta/sorts/`{sortId}`/api/v1/db | | Meta | Delete| dbTableSort | delete | /api/v1/db/meta/sorts/`{sortId}` |
| Meta | Patch | dbTableWebhook | update | /api/v1/db/meta/hooks/`{hookId}` | | Meta | Patch | dbTableWebhook | update | /api/v1/db/meta/hooks/`{hookId}` |
| Meta | Delete| dbTableWebhook | delete | /api/v1/db/meta/hooks/`{hookId}` | | Meta | Delete| dbTableWebhook | delete | /api/v1/db/meta/hooks/`{hookId}` |
| Meta | Get | dbTableWebhook | list | /api/v1/db/meta/tables/`{tableId}`/hooks | | Meta | Get | dbTableWebhook | list | /api/v1/db/meta/tables/`{tableId}`/hooks |
@ -147,7 +147,7 @@ Currently, the default value for `{orgs}` is <b>noco</b>. Users will be able to
| Meta | Patch | dbViewShare | update | /api/v1/db/meta/views/`{viewId}`/share | | Meta | Patch | dbViewShare | update | /api/v1/db/meta/views/`{viewId}`/share |
| Meta | Delete| dbViewShare | delete | /api/v1/db/meta/views/`{viewId}`/share | | Meta | Delete| dbViewShare | delete | /api/v1/db/meta/views/`{viewId}`/share |
| Meta | Get | plugin | list | /api/v1/db/meta/plugins | | Meta | Get | plugin | list | /api/v1/db/meta/plugins |
| Meta | Get | plugin | status | /api/v1/db/meta/plugins/`{pluginTitle}`/status | | Meta | Get | plugin | status | /api/v1/db/meta/plugins/`{pluginId}`/status |
| Meta | Post | plugin | test | /api/v1/db/meta/plugins/test | | Meta | Post | plugin | test | /api/v1/db/meta/plugins/test |
| Meta | PATCH | plugin | update | /api/v1/db/meta/plugins/`{pluginId}` | | Meta | PATCH | plugin | update | /api/v1/db/meta/plugins/`{pluginId}` |
| Meta | Get | plugin | read | /api/v1/db/meta/plugins/`{pluginId}` | | Meta | Get | plugin | read | /api/v1/db/meta/plugins/`{pluginId}` |

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

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

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

@ -14,7 +14,7 @@ import DiscordPluginConfig from '~/plugins/discord';
import GcsPluginConfig from '~/plugins/gcs'; import GcsPluginConfig from '~/plugins/gcs';
import LinodePluginConfig from '~/plugins/linode'; import LinodePluginConfig from '~/plugins/linode';
import MattermostPluginConfig from '~/plugins/mattermost'; import MattermostPluginConfig from '~/plugins/mattermost';
import MinioPluginConfig from '~/plugins/mino'; import MinioPluginConfig from '~/plugins/minio';
import OvhCloudPluginConfig from '~/plugins/ovhCloud'; import OvhCloudPluginConfig from '~/plugins/ovhCloud';
import S3PluginConfig from '~/plugins/s3'; import S3PluginConfig from '~/plugins/s3';
import ScalewayPluginConfig from '~/plugins/scaleway'; import ScalewayPluginConfig from '~/plugins/scaleway';
@ -67,15 +67,26 @@ class NcPluginMgrv2 {
// } // }
public static async init(ncMeta = Noco.ncMeta): Promise<void> { 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 */ /* Populate rows into nc_plugins table if not present */
for (const plugin of defaultPlugins) { for (const plugin of defaultPlugins) {
const pluginConfig = await ncMeta.metaGet( const pluginConfig = await ncMeta.metaGet(
RootScopes.ROOT, RootScopes.ROOT,
RootScopes.ROOT, RootScopes.ROOT,
MetaTable.PLUGIN, MetaTable.PLUGIN,
{ plugin.id,
title: plugin.title,
},
); );
if (!pluginConfig) { if (!pluginConfig) {
@ -84,6 +95,7 @@ class NcPluginMgrv2 {
RootScopes.ROOT, RootScopes.ROOT,
MetaTable.PLUGIN, MetaTable.PLUGIN,
{ {
id: plugin.id,
title: plugin.title, title: plugin.title,
version: plugin.version, version: plugin.version,
logo: plugin.logo, logo: plugin.logo,
@ -121,7 +133,7 @@ class NcPluginMgrv2 {
* */ * */
if (process.env.NC_S3_BUCKET_NAME && process.env.NC_S3_REGION) { 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> = { const s3CfgData: Record<string, any> = {
bucket: process.env.NC_S3_BUCKET_NAME, bucket: process.env.NC_S3_BUCKET_NAME,
region: process.env.NC_S3_REGION, region: process.env.NC_S3_REGION,
@ -144,7 +156,7 @@ class NcPluginMgrv2 {
process.env.NC_SMTP_HOST && process.env.NC_SMTP_HOST &&
process.env.NC_SMTP_PORT process.env.NC_SMTP_PORT
) { ) {
const smtpPlugin = await Plugin.getPluginByTitle(SMTPPluginConfig.title); const smtpPlugin = await Plugin.getPlugin(SMTPPluginConfig.id);
await Plugin.update(smtpPlugin.id, { await Plugin.update(smtpPlugin.id, {
active: true, active: true,
input: JSON.stringify({ input: JSON.stringify({

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

@ -89,23 +89,25 @@ export default class Plugin implements PluginType {
); );
await NocoCache.update(`${CacheScope.PLUGIN}:${pluginId}`, updateObj); await NocoCache.update(`${CacheScope.PLUGIN}:${pluginId}`, updateObj);
await NocoCache.update(`${CacheScope.PLUGIN}:${plugin.title}`, updateObj);
return this.get(pluginId); return this.get(pluginId);
} }
public static async isPluginActive(title: string) { public static async isPluginActive(id: string, ncMeta = Noco.ncMeta) {
return !!(await this.getPluginByTitle(title))?.active; return !!(
(await this.getPlugin(id, ncMeta)) ||
(await this.getPluginByTitle(id, ncMeta))
)?.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 = let plugin =
title && id &&
(await NocoCache.get( (await NocoCache.get(
`${CacheScope.PLUGIN}:${title}`, `${CacheScope.PLUGIN}:${id}`,
CacheGetType.TYPE_OBJECT, CacheGetType.TYPE_OBJECT,
)); ));
if (!plugin) { if (!plugin) {
@ -113,12 +115,20 @@ export default class Plugin implements PluginType {
RootScopes.ROOT, RootScopes.ROOT,
RootScopes.ROOT, RootScopes.ROOT,
MetaTable.PLUGIN, MetaTable.PLUGIN,
{ id,
title,
},
); );
await NocoCache.set(`${CacheScope.PLUGIN}:${title}`, plugin); await NocoCache.set(`${CacheScope.PLUGIN}:${id}`, plugin);
} }
return 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

@ -4,7 +4,9 @@ import type { XcPluginConfig } from '~/types/nc-plugin';
const config: XcPluginConfig = { const config: XcPluginConfig = {
builder: BackblazePlugin, builder: BackblazePlugin,
id: 'backblaze',
title: 'Backblaze', title: 'Backblaze',
recoveryTitle: 'Backblaze B2',
version: '0.0.5', version: '0.0.5',
logo: 'plugins/backblaze.jpeg', logo: 'plugins/backblaze.jpeg',
tags: 'Storage', tags: 'Storage',

1
packages/nocodb/src/plugins/discord/index.ts

@ -4,6 +4,7 @@ import type { XcPluginConfig } from '~/types/nc-plugin';
const config: XcPluginConfig = { const config: XcPluginConfig = {
builder: DiscordPlugin, builder: DiscordPlugin,
id: 'discord',
title: 'Discord', title: 'Discord',
version: '0.0.1', version: '0.0.1',
logo: 'plugins/discord.png', logo: 'plugins/discord.png',

1
packages/nocodb/src/plugins/gcs/index.ts

@ -4,6 +4,7 @@ import type { XcPluginConfig } from '~/types/nc-plugin';
const config: XcPluginConfig = { const config: XcPluginConfig = {
builder: GcsPlugin, builder: GcsPlugin,
id: 'gcs',
title: 'GCS', title: 'GCS',
version: '0.0.4', version: '0.0.4',
logo: 'plugins/gcs.png', logo: 'plugins/gcs.png',

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

@ -4,6 +4,8 @@ import type { XcPluginConfig } from '~/types/nc-plugin';
const config: XcPluginConfig = { const config: XcPluginConfig = {
builder: LinodeObjectStoragePlugin, builder: LinodeObjectStoragePlugin,
id: 'linode',
recoveryTitle: 'Linode Object Storage',
title: 'Linode', title: 'Linode',
version: '0.0.4', version: '0.0.4',
logo: 'plugins/linode.svg', logo: 'plugins/linode.svg',

1
packages/nocodb/src/plugins/mailerSend/index.ts

@ -4,6 +4,7 @@ import type { XcPluginConfig } from '~/types/nc-plugin';
const config: XcPluginConfig = { const config: XcPluginConfig = {
builder: MailerSendPlugin, builder: MailerSendPlugin,
id: 'mailersend',
title: 'MailerSend', title: 'MailerSend',
version: '0.0.2', version: '0.0.2',
logo: 'plugins/mailersend.svg', logo: 'plugins/mailersend.svg',

1
packages/nocodb/src/plugins/mattermost/index.ts

@ -4,6 +4,7 @@ import type { XcPluginConfig } from '~/types/nc-plugin';
const config: XcPluginConfig = { const config: XcPluginConfig = {
builder: MattermostPlugin, builder: MattermostPlugin,
id: 'mattermost',
title: 'Mattermost', title: 'Mattermost',
version: '0.0.1', version: '0.0.1',
logo: 'plugins/mattermost.png', logo: 'plugins/mattermost.png',

0
packages/nocodb/src/plugins/mino/Minio.ts → packages/nocodb/src/plugins/minio/Minio.ts

0
packages/nocodb/src/plugins/mino/MinioPlugin.ts → packages/nocodb/src/plugins/minio/MinioPlugin.ts

1
packages/nocodb/src/plugins/mino/index.ts → packages/nocodb/src/plugins/minio/index.ts

@ -4,6 +4,7 @@ import type { XcPluginConfig } from '~/types/nc-plugin';
const config: XcPluginConfig = { const config: XcPluginConfig = {
builder: S3Plugin, builder: S3Plugin,
id: 'minio',
title: 'Minio', title: 'Minio',
version: '0.0.4', version: '0.0.4',
logo: 'plugins/minio.png', logo: 'plugins/minio.png',

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

@ -4,7 +4,9 @@ import type { XcPluginConfig } from '~/types/nc-plugin';
const config: XcPluginConfig = { const config: XcPluginConfig = {
builder: OvhCloud, builder: OvhCloud,
id: 'ovh',
title: 'Ovh', title: 'Ovh',
recoveryTitle: 'OvhCloud Object Storage',
version: '0.0.4', version: '0.0.4',
logo: 'plugins/ovhCloud.png', logo: 'plugins/ovhCloud.png',
tags: 'Storage', tags: 'Storage',

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

@ -4,7 +4,9 @@ import type { XcPluginConfig } from '~/types/nc-plugin';
const config: XcPluginConfig = { const config: XcPluginConfig = {
builder: R2Plugin, builder: R2Plugin,
id: 'cloudflare-r2',
title: 'Cloudflare R2', title: 'Cloudflare R2',
recoveryTitle: 'Cloudflare R2 Storage',
version: '0.0.3', version: '0.0.3',
logo: 'plugins/r2.png', logo: 'plugins/r2.png',
description: description:

1
packages/nocodb/src/plugins/s3/index.ts

@ -4,6 +4,7 @@ import type { XcPluginConfig } from '~/types/nc-plugin';
const config: XcPluginConfig = { const config: XcPluginConfig = {
builder: S3Plugin, builder: S3Plugin,
id: 'aws-s3',
title: 'S3', title: 'S3',
version: '0.0.6', version: '0.0.6',
logo: 'plugins/s3.png', logo: 'plugins/s3.png',

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

@ -4,7 +4,9 @@ import type { XcPluginConfig } from '~/types/nc-plugin';
const config: XcPluginConfig = { const config: XcPluginConfig = {
builder: ScalewayObjectStoragePlugin, builder: ScalewayObjectStoragePlugin,
id: 'scaleway',
title: 'Scaleway', title: 'Scaleway',
recoveryTitle: 'Scaleway Object Storage',
version: '0.0.4', version: '0.0.4',
logo: 'plugins/scaleway.png', logo: 'plugins/scaleway.png',
tags: 'Storage', tags: 'Storage',

1
packages/nocodb/src/plugins/ses/index.ts

@ -4,6 +4,7 @@ import type { XcPluginConfig } from '~/types/nc-plugin';
const config: XcPluginConfig = { const config: XcPluginConfig = {
builder: SESPlugin, builder: SESPlugin,
id: 'ses',
title: 'SES', title: 'SES',
version: '0.0.2', version: '0.0.2',
logo: 'plugins/aws.png', logo: 'plugins/aws.png',

1
packages/nocodb/src/plugins/slack/index.ts

@ -4,6 +4,7 @@ import type { XcPluginConfig } from '~/types/nc-plugin';
const config: XcPluginConfig = { const config: XcPluginConfig = {
builder: SlackPlugin, builder: SlackPlugin,
id: 'slack',
title: 'Slack', title: 'Slack',
version: '0.0.1', version: '0.0.1',
logo: 'plugins/slack.webp', logo: 'plugins/slack.webp',

1
packages/nocodb/src/plugins/smtp/index.ts

@ -6,6 +6,7 @@ import type { XcPluginConfig } from '~/types/nc-plugin';
const config: XcPluginConfig = { const config: XcPluginConfig = {
builder: SMTPPlugin, builder: SMTPPlugin,
id: 'smtp',
title: 'SMTP', title: 'SMTP',
version: '0.0.4', version: '0.0.4',
// icon: 'mdi-email-outline', // icon: 'mdi-email-outline',

1
packages/nocodb/src/plugins/spaces/index.ts

@ -4,6 +4,7 @@ import type { XcPluginConfig } from '~/types/nc-plugin';
const config: XcPluginConfig = { const config: XcPluginConfig = {
builder: SpacesPlugin, builder: SpacesPlugin,
id: 'spaces',
title: 'Spaces', title: 'Spaces',
version: '0.0.2', version: '0.0.2',
logo: 'plugins/spaces.png', logo: 'plugins/spaces.png',

1
packages/nocodb/src/plugins/teams/index.ts

@ -4,6 +4,7 @@ import type { XcPluginConfig } from '~/types/nc-plugin';
const config: XcPluginConfig = { const config: XcPluginConfig = {
builder: TeamsPlugin, builder: TeamsPlugin,
id: 'ms-teams',
title: 'Microsoft Teams', title: 'Microsoft Teams',
version: '0.0.1', version: '0.0.1',
logo: 'plugins/teams.ico', logo: 'plugins/teams.ico',

1
packages/nocodb/src/plugins/twilio/index.ts

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

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

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

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

@ -4,7 +4,9 @@ import type { XcPluginConfig } from '~/types/nc-plugin';
const config: XcPluginConfig = { const config: XcPluginConfig = {
builder: UpCloudPlugin, builder: UpCloudPlugin,
id: 'upcloud',
title: 'UpCloud', title: 'UpCloud',
recoveryTitle: 'UpCloud Object Storage',
version: '0.0.4', version: '0.0.4',
logo: 'plugins/upcloud.png', logo: 'plugins/upcloud.png',
description: description:

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

@ -5,6 +5,8 @@ import type { XcPluginConfig } from '~/types/nc-plugin';
const config: XcPluginConfig = { const config: XcPluginConfig = {
builder: VultrPlugin, builder: VultrPlugin,
title: 'Vultr', title: 'Vultr',
id: 'vultr',
recoveryTitle: 'Vultr Object Storage',
version: '0.0.4', version: '0.0.4',
logo: 'plugins/vultr.png', logo: 'plugins/vultr.png',
description: description:

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

@ -31,7 +31,7 @@ export const InitMetaServiceProvider: FactoryProvider = {
const config = await NcConfig.createByEnv(); const config = await NcConfig.createByEnv();
// set version // set version
process.env.NC_VERSION = '0225002'; process.env.NC_VERSION = '0258003';
// set migration jobs version // set migration jobs version
process.env.NC_MIGRATION_JOBS_VERSION = '2'; process.env.NC_MIGRATION_JOBS_VERSION = '2';
@ -98,17 +98,17 @@ export const InitMetaServiceProvider: FactoryProvider = {
// load super admin user from env if env is set // load super admin user from env if env is set
await initAdminFromEnv(metaService); await initAdminFromEnv(metaService);
await Noco.loadEEState();
// run upgrader
await NcUpgrader.upgrade({ ncMeta: Noco._ncMeta });
// init plugin manager // init plugin manager
await NcPluginMgrv2.init(Noco.ncMeta); await NcPluginMgrv2.init(Noco.ncMeta);
await Noco.loadEEState();
if (process.env.NC_CLOUD === 'true') { if (process.env.NC_CLOUD === 'true') {
await populatePluginsForCloud({ ncMeta: Noco.ncMeta }); await populatePluginsForCloud({ ncMeta: Noco.ncMeta });
} }
// run upgrader
await NcUpgrader.upgrade({ ncMeta: Noco._ncMeta });
T.init({ T.init({
instance: getInstance, instance: getInstance,
}); });

4
packages/nocodb/src/schema/swagger-v2.json

@ -10877,13 +10877,13 @@
] ]
} }
}, },
"/api/v2/meta/plugins/{pluginTitle}/status": { "/api/v2/meta/plugins/{pluginId}/status": {
"parameters": [ "parameters": [
{ {
"schema": { "schema": {
"type": "string" "type": "string"
}, },
"name": "pluginTitle", "name": "pluginId",
"in": "path", "in": "path",
"required": true, "required": true,
"description": "Plugin Title" "description": "Plugin Title"

4
packages/nocodb/src/schema/swagger.json

@ -15069,13 +15069,13 @@
"tags": ["Plugin"] "tags": ["Plugin"]
} }
}, },
"/api/v1/db/meta/plugins/{pluginTitle}/status": { "/api/v1/db/meta/plugins/{pluginId}/status": {
"parameters": [ "parameters": [
{ {
"schema": { "schema": {
"type": "string" "type": "string"
}, },
"name": "pluginTitle", "name": "pluginId",
"in": "path", "in": "path",
"required": true, "required": true,
"description": "Plugin Title" "description": "Plugin Title"

2
packages/nocodb/src/services/command-palette.service.ts

@ -1,5 +1,5 @@
import { Injectable, Logger } from '@nestjs/common'; import { Injectable, Logger } from '@nestjs/common';
import { viewTypeAlias, type UserType } from 'nocodb-sdk'; import { type UserType, viewTypeAlias } from 'nocodb-sdk';
import { deserializeJSON } from '~/utils/serialize'; import { deserializeJSON } from '~/utils/serialize';
import { getCommandPaletteForUserWorkspace } from '~/helpers/commandPaletteHelpers'; import { getCommandPaletteForUserWorkspace } from '~/helpers/commandPaletteHelpers';

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

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

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

@ -4,7 +4,9 @@ import type XcPlugin from './XcPlugin';
import type XcPluginMigration from './XcPluginMigration'; import type XcPluginMigration from './XcPluginMigration';
export default interface XcPluginConfig { export default interface XcPluginConfig {
id: string;
title: string; title: string;
recoveryTitle?: string;
logo?: string; logo?: string;
tags?: string; tags?: string;
description?: 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 ncXcdbLTARIndexUpgrader from './upgraders/0111002_ncXcdbLTARIndexUpgrader';
import ncXcdbCreatedAndUpdatedSystemFieldsUpgrader from './upgraders/0111005_ncXcdbCreatedAndUpdatedSystemFieldsUpgrader'; import ncXcdbCreatedAndUpdatedSystemFieldsUpgrader from './upgraders/0111005_ncXcdbCreatedAndUpdatedSystemFieldsUpgrader';
import ncDatasourceDecrypt from './upgraders/0225002_ncDatasourceDecrypt'; import ncDatasourceDecrypt from './upgraders/0225002_ncDatasourceDecrypt';
import ncDuplicatePluginMerge from './upgraders/0258003_ncDuplicatePluginMerge';
import type { MetaService } from '~/meta/meta.service'; import type { MetaService } from '~/meta/meta.service';
import type { NcConfig } from '~/interface/config'; import type { NcConfig } from '~/interface/config';
import { T } from '~/utils'; import { T } from '~/utils';
@ -150,6 +151,7 @@ export default class NcUpgrader {
{ name: '0111002', handler: ncXcdbLTARIndexUpgrader }, { name: '0111002', handler: ncXcdbLTARIndexUpgrader },
{ name: '0111005', handler: ncXcdbCreatedAndUpdatedSystemFieldsUpgrader }, { name: '0111005', handler: ncXcdbCreatedAndUpdatedSystemFieldsUpgrader },
{ name: '0225002', handler: ncDatasourceDecrypt }, { name: '0225002', handler: ncDatasourceDecrypt },
{ name: '0258003', handler: ncDuplicatePluginMerge },
]; ];
} }
} }

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

@ -0,0 +1,127 @@
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/minio';
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,
];
const logger = {
log: (message: string) => {
console.log(`[0258003_ncDuplicatePluginMerge ${Date.now()}] ` + message);
},
error: (message: string) => {
console.error(`[0258003_ncDuplicatePluginMerge ${Date.now()}] ` + message);
},
};
// 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) {
logger.log('Merging duplicate plugins and updating the plugin id');
// 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 currentPlugin = await ncMeta
.knex(MetaTable.PLUGIN)
.where('title', pluginConfig.title)
.first();
if (currentPlugin) {
// update the plugin with the new id
await ncMeta
.knex(MetaTable.PLUGIN)
.where('id', currentPlugin.id)
.update({ id: pluginConfig.id });
currentPlugin.id = pluginConfig.id;
}
if (pluginConfig.recoveryTitle) {
// get the plugin with old title
const oldPlugin = await ncMeta
.knex(MetaTable.PLUGIN)
.where('title', pluginConfig.recoveryTitle)
.first();
// if the old plugin is not present then continue
if (!oldPlugin) continue;
if (currentPlugin) {
// if the old plugin is present then update the new plugin with the old plugin configuration
// and only if new plugin is not configured or active
if (
(!currentPlugin.active && oldPlugin?.active) ||
(!currentPlugin.input && oldPlugin?.input)
) {
await ncMeta
.knex(MetaTable.PLUGIN)
.update({
input: oldPlugin.input,
active: currentPlugin.active || oldPlugin.active,
})
// use the new plugin id since it's already updated at the start
.where('id', pluginConfig.id);
logger.log(
`Merged the old plugin with the new plugin: ${pluginConfig.id}`,
);
}
if (oldPlugin) {
// delete the old plugin
await ncMeta
.knex(MetaTable.PLUGIN)
.where('id', oldPlugin.id)
.delete();
logger.log(`Deleted the old duplicate plugin: ${oldPlugin.title}`);
}
} 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 });
logger.log(`Updated the old plugin id: ${pluginConfig.id}`);
}
}
}
logger.log('Merging duplicate plugins and updating the plugin id completed');
}
Loading…
Cancel
Save