Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: Delete default plugin column from database #637

Merged
merged 2 commits into from
Jan 6, 2025
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
5 changes: 2 additions & 3 deletions apps/backend/src/plugins/welcome/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,5 @@
"code": "welcome",
"author": "VitNode",
"author_url": "https://vitnode.com/",
"support_url": "https://github.com/VitNode/vitnode/issues",
"allow_default": true
}
"support_url": "https://github.com/VitNode/vitnode/issues"
}
18 changes: 3 additions & 15 deletions apps/frontend/src/app/[locale]/(main)/(layout)/page.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,9 @@
// ! DO NOT TOUCH THIS FILE!!!
// ! If you remove this then default page plugin will not work
import DefaultPage from '@/plugins/welcome/templates/default-page';
import React from 'react';
import { getMiddlewareData } from 'vitnode-frontend/api/get-middleware-data';
import { generateMetadataDefaultPage } from 'vitnode-frontend/views/theme/views/default-page';

export const generateMetadata = generateMetadataDefaultPage;

export default async function Page() {
const { plugin_code_default } = await getMiddlewareData();

const PageFromTheme = React.lazy(async () =>
import(`@/plugins/${plugin_code_default}/templates/default-page`).then(
module => ({
default: module.default,
}),
),
);

return <PageFromTheme />;
export default function Page() {
return <DefaultPage />;
}
12 changes: 0 additions & 12 deletions docs/dev/i18n/namespaces.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -66,15 +66,3 @@ Provide the list of namespaces that you want to get access to the translation st
You don't need to include the `core.global` namespace in the `namespaces`
prop. It's already included by default.
</Callout>

### Default page

VitNode has plugin system with option to set plugin as default. That means default plugin will be loaded on the home page.

To set default page make sure your have `default-page.tsx` inside `templates` folder plugin with `export default` function.

```tsx title="apps/frontend/src/plugins/{your_plugin}/templates/default-page.tsx"
export default function Page() {
return <div>Hello World</div>;
}
```
1 change: 0 additions & 1 deletion docs/dev/permissions-admin.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ Edit the `permissions_admin` in the `config.json` file from your plugin.
"author": "VitNode",
"author_url": "https://vitnode.com/",
"support_url": "https://github.com/VitNode/vitnode/issues",
"allow_default": true,
// [!code ++]
"permissions_admin": [
// [!code ++]
Expand Down
95 changes: 43 additions & 52 deletions packages/backend/scripts/update-plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,6 @@ export const updatePlugins = async ({
db: NodePgDatabase<typeof coreSchemaDatabase>;
pluginsPath: string;
}) => {
let isDefaultIndex: null | number = null;
const defaultPlugin = await db.query.core_plugins.findFirst({
where: (table, { eq }) => eq(table.default, true),
});
const plugins = (await readdir(pluginsPath)).filter(
plugin => !['core', 'plugins.module.ts'].includes(plugin),
);
Expand All @@ -30,58 +26,53 @@ export const updatePlugins = async ({
},
});

for (const [index, code] of plugins.entries()) {
const pluginPath = join(pluginsPath, code);
const configPath = join(pluginPath, 'config.json');
if (!existsSync(configPath)) {
continue;
}

const config = JSON.parse(
await readFile(join(pluginPath, 'config.json'), 'utf8'),
);
await Promise.all(
plugins.map(async code => {
const pluginPath = join(pluginsPath, code);
const configPath = join(pluginPath, 'config.json');
if (!existsSync(configPath)) {
return;
}

if (config.allow_default && isDefaultIndex === null) {
isDefaultIndex = index;
}
const config = JSON.parse(
await readFile(join(pluginPath, 'config.json'), 'utf8'),
);

const plugin = pluginsFromDatabase.find(
plugin => plugin.code === config.code,
);
const plugin = pluginsFromDatabase.find(
plugin => plugin.code === config.code,
);

if (plugin) {
await tx
.update(core_plugins)
.set({
name: config.name,
description: config.description,
support_url: config.support_url,
author: config.author,
author_url: config.author_url,
allow_default: config.allow_default,
version: config.version,
version_code: config.version_code,
})
.where(eq(core_plugins.id, plugin.id));
} else {
await tx.insert(core_plugins).values([
{
name: config.name,
description: config.description,
code: config.code,
support_url: config.support_url,
author: config.author,
author_url: config.author_url,
allow_default: config.allow_default,
version: config.version,
version_code: config.version_code,
default: isDefaultIndex === index && !defaultPlugin,
},
]);
}
if (plugin) {
await tx
.update(core_plugins)
.set({
name: config.name,
description: config.description,
support_url: config.support_url,
author: config.author,
author_url: config.author_url,
version: config.version,
version_code: config.version_code,
})
.where(eq(core_plugins.id, plugin.id));
} else {
await tx.insert(core_plugins).values([
{
name: config.name,
description: config.description,
code: config.code,
support_url: config.support_url,
author: config.author,
author_url: config.author_url,
version: config.version,
version_code: config.version_code,
},
]);
}

await tx.execute(sql`commit`);
}
await tx.execute(sql`commit`);
}),
);

// Remove plugins that are not in the plugins folder
const pluginsToDelete = pluginsFromDatabase.filter(
Expand Down
7 changes: 0 additions & 7 deletions packages/backend/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,6 @@ export const ABSOLUTE_PATHS = {
plugin: join(internalPaths.frontend, 'plugins', code),
templates: join(internalPaths.frontend, 'plugins', code, 'templates'),
languages: join(internalPaths.frontend, 'plugins', code, 'langs'),
default_page: join(
internalPaths.frontend,
'plugins',
code,
'templates',
'default-page.tsx',
),
admin_pages_auth: join(
internalPaths.frontend,
'app',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ export class CreatePluginsAdminService {
$schema: 'https://api.vitnode.com/public/vitnode/plugin.schema.json',
code,
...rest,
allow_default: true,
nav: [],
version: '0.0.1',
version_code: 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
Injectable,
NotFoundException,
} from '@nestjs/common';
import { eq } from 'drizzle-orm';
import { count, eq } from 'drizzle-orm';
import { existsSync } from 'fs';
import { rm } from 'fs/promises';
import { join } from 'path';
Expand All @@ -35,16 +35,21 @@ export class DeletePluginsAdminService {
where: (table, { eq }) => eq(table.id, id),
columns: {
code: true,
default: true,
},
});

if (!plugin) {
throw new NotFoundException();
}

if (plugin.default) {
throw new BadRequestException('DEFAULT_PLUGIN_CANNOT_BE_DELETED');
const [pluginCount] = await this.databaseService.db
.select({
count: count(),
})
.from(core_plugins);

if (pluginCount.count === 1) {
throw new BadRequestException('Cannot delete the last plugin');
}

await this.changeFilesHelper.changeFiles({
Expand Down
33 changes: 8 additions & 25 deletions packages/backend/src/core/admin/plugins/services/edit.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
Injectable,
NotFoundException,
} from '@nestjs/common';
import { eq, ne } from 'drizzle-orm';
import { eq } from 'drizzle-orm';
import { readFile, writeFile } from 'fs/promises';
import {
ConfigPlugin,
Expand All @@ -20,7 +20,7 @@ export class EditPluginsAdminService {

async edit({
code,
body: { default: isDefault = false, ...rest },
body,
}: {
body: EditPluginsAdminBody;
code: string;
Expand All @@ -37,26 +37,9 @@ export class EditPluginsAdminService {
throw new BadRequestException('PLUGIN_CODE_MISMATCH');
}

if (isDefault) {
if (!plugin.enabled) {
throw new BadRequestException('PLUGIN_NOT_ENABLED');
}

// Set all other plugins to default: false
await this.databaseService.db
.update(core_plugins)
.set({
default: false,
})
.where(ne(core_plugins.code, code));
}

const [updatePlugin] = await this.databaseService.db
.update(core_plugins)
.set({
...rest,
default: isDefault,
})
.set(body)
.where(eq(core_plugins.code, code))
.returning();

Expand All @@ -66,11 +49,11 @@ export class EditPluginsAdminService {
await readFile(path, 'utf8'),
);

config.name = rest.name;
config.description = rest.description;
config.author = rest.author;
config.author_url = rest.author_url;
config.support_url = rest.support_url;
config.name = body.name;
config.description = body.description;
config.author = body.author;
config.author_url = body.author_url;
config.support_url = body.support_url;

await writeFile(path, JSON.stringify(config, null, 2));

Expand Down
32 changes: 8 additions & 24 deletions packages/backend/src/core/admin/plugins/services/export.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,6 @@ export class ExportPluginsAdminService {
const configJSON: ConfigPlugin = JSON.parse(
await readFile(pathInfoJSON, 'utf8'),
);
const allow_default = existsSync(
ABSOLUTE_PATHS.plugin({ code }).frontend.default_page,
);

if (
(!version && !configJSON.version) ||
Expand All @@ -66,32 +63,19 @@ export class ExportPluginsAdminService {
});
}

configJSON.allow_default = allow_default;
configJSON.version = version ?? configJSON.version;
configJSON.version_code = version_code ?? configJSON.version_code;

await writeFile(pathInfoJSON, JSON.stringify(configJSON, null, 2), 'utf8');

// Update only allow_default
if (!version || !version_code) {
await this.databaseService.db
.update(core_plugins)
.set({
allow_default,
updated_at: new Date(),
})
.where(eq(core_plugins.code, code));
} else {
await this.databaseService.db
.update(core_plugins)
.set({
version,
version_code,
allow_default,
updated_at: new Date(),
})
.where(eq(core_plugins.code, code));
}
await this.databaseService.db
.update(core_plugins)
.set({
version,
version_code,
updated_at: new Date(),
})
.where(eq(core_plugins.code, code));

// Prepare the export
const tempFolderName = removeSpecialCharacters(
Expand Down
6 changes: 0 additions & 6 deletions packages/backend/src/core/middleware/services/show.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import {
Inject,
Injectable,
InternalServerErrorException,

Check warning on line 12 in packages/backend/src/core/middleware/services/show.service.ts

View workflow job for this annotation

GitHub Actions / linting

'InternalServerErrorException' is defined but never used
} from '@nestjs/common';
import { readFile } from 'fs/promises';
import { join } from 'path';
Expand Down Expand Up @@ -60,7 +60,6 @@
this.databaseService.db.query.core_plugins.findMany({
columns: {
code: true,
default: true,
},
}),
this.databaseService.db.query.core_languages.findMany({
Expand All @@ -76,10 +75,6 @@
}),
]);

const plugin_code_default = plugins.find(plugin => plugin.default)?.code;
if (!plugin_code_default) {
throw new InternalServerErrorException('Plugin not found');
}
const manifest = await this.getManifests({
langCodes: langs.map(lang => lang.code),
});
Expand Down Expand Up @@ -124,7 +119,6 @@
editor: {
sticky: configFromDb.editor_sticky ?? false,
},
plugin_code_default,
site_description: manifest.map(item => ({
language_code: item.lang,
value: item.description,
Expand Down
2 changes: 0 additions & 2 deletions packages/backend/src/database/schema/plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ export const core_plugins = pgTable(
support_url: t.varchar({ length: 255 }).notNull(),
author: t.varchar({ length: 100 }).notNull(),
author_url: t.varchar({ length: 255 }),
default: t.boolean().notNull().default(false),
allow_default: t.boolean().notNull().default(true),
}),
t => [
index('core_plugins_code_idx').on(t.code),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"$schema": "https://api.vitnode.com/public/vitnode/plugin.schema.json",
"name": "Welcome",
"description": "Basic plugin with default page.",
"version": "1.0.0",
Expand All @@ -7,6 +8,5 @@
"author": "VitNode",
"author_url": "https://vitnode.com/",
"support_url": "https://github.com/VitNode/vitnode/issues",
"allow_default": true,
"nav": []
}
}
Loading
Loading