Skip to content

Commit

Permalink
Merge pull request #594 from VitNode/metadata/favicon
Browse files Browse the repository at this point in the history
feat: Add icon handle in metadata to handle manifest icons in AdminCP
  • Loading branch information
aXenDeveloper authored Nov 30, 2024
2 parents e531dca + 6fae025 commit d7f9457
Show file tree
Hide file tree
Showing 32 changed files with 527 additions and 272 deletions.
8 changes: 8 additions & 0 deletions apps/frontend/src/plugins/admin/langs/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,14 @@
"label": "Start URL",
"desc": "When user launches the app, this is the page that will be loaded."
},
"icon": {
"label": "Icon",
"desc": "Represent your website on devices (PWA). Recommended size: 512x512px."
},
"favicon": {
"label": "Favicon",
"desc": "Icon in browser tab. Recommended size: 32x32px."
},
"display": {
"label": "Display",
"desc": "The display property controls how the app is displayed.",
Expand Down
1 change: 1 addition & 0 deletions packages/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
"drizzle-orm": "^0.36.4",
"helmet": "^8.0.0",
"pg": "^8.13.1",
"rxjs": "^7.8.1",
"sharp": "^0.33.5",
"ua-parser-js": "^2.0.0",
"vitnode-shared": "workspace:*"
Expand Down
8 changes: 1 addition & 7 deletions packages/backend/scripts/generate-manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,7 @@ const generateDefaultManifest = ({
background_color: '#09090b',
start_url: `${frontendUrl}/${langCode}/`,
orientation: 'any',
icons: [
{
src: '/icons/favicon.ico',
sizes: 'any',
type: 'image/x-icon',
},
],
icons: [],
});

export const generateManifest = async ({
Expand Down
2 changes: 1 addition & 1 deletion packages/backend/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ const parseFrontendUrlFromEnv = () => {
};

const parseBackendUrlFromEnv = () => {
const envUrl = process.env.NEXT_PUBLIC_BACKEND_URL;
const envUrl = process.env.NEXT_PUBLIC_BACKEND_CLIENT_URL;
const frontendUrl = envUrl ? envUrl : 'http://localhost:8080';
const urlObj = new URL(frontendUrl);

Expand Down
30 changes: 8 additions & 22 deletions packages/backend/src/core/admin/settings/email/email.controller.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,9 @@
import { Controllers } from '@/helpers/controller.decorator';
import { FilesValidationPipe } from '@/helpers/files/files.pipe';
import { UploadFilesMethod } from '@/helpers/upload-files.decorator';
import { CurrentUser } from '@/helpers/user.decorator';
import {
Body,
Get,
Post,
Put,
Query,
UploadedFiles,
UseInterceptors,
} from '@nestjs/common';
import { FileFieldsInterceptor } from '@nestjs/platform-express';
import { ApiBody, ApiConsumes, ApiOkResponse } from '@nestjs/swagger';
import { Body, Get, Post, Put, Query, UploadedFiles } from '@nestjs/common';
import { ApiOkResponse } from '@nestjs/swagger';
import {
EditEmailSettingsAdminBody,
LogsEmailSettingsAdminObj,
Expand Down Expand Up @@ -40,33 +32,27 @@ export class EmailSettingsAdminController {
private readonly logsService: LogsEmailSettingsAdminService,
) {}

@ApiBody({
description: 'Edit email settings',
type: EditEmailSettingsAdminBody,
})
@ApiConsumes('multipart/form-data')
@ApiOkResponse({
description: 'Email settings updated',
type: ShowEmailSettingsAdminObj,
})
@Put()
@UseInterceptors(FileFieldsInterceptor([{ name: 'logo', maxCount: 1 }]))
@UploadFilesMethod({ fields: ['logo'] })
async edit(
@UploadedFiles(
new FilesValidationPipe({
logo: {
maxSize: 1024 * 1024, // 1 MB
acceptMimeType: ['image/jpeg', 'image/png', 'image/gif'],
isOptional: true,
maxCount: 1,
},
}),
)
files: {
logo?: Express.Multer.File[];
},
@Body() body: Omit<EditEmailSettingsAdminBody, 'logo'>,
files: Pick<EditEmailSettingsAdminBody, 'logo'>,
@Body() body: EditEmailSettingsAdminBody,
): Promise<ShowEmailSettingsAdminObj> {
return await this.editService.edit({ ...body, logo: files.logo?.at(0) });
return await this.editService.edit({ body, files });
}

@ApiOkResponse({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ export class EditEmailSettingsAdminService {
private readonly filesService: FilesHelperService,
) {}

async edit(
settings: EditEmailSettingsAdminBody,
): Promise<ShowEmailSettingsAdminObj> {
const { logo, color_primary, color_primary_foreground, delete_logo } =
settings;
async edit({
body: { color_primary, color_primary_foreground, delete_logo },
files: { logo },
}: {
body: Omit<EditEmailSettingsAdminBody, 'logo'>;
files: Pick<EditEmailSettingsAdminBody, 'logo'>;
}): Promise<ShowEmailSettingsAdminObj> {
const isEmailEnabled = this.mailService.checkIfEnable();
const configSettings = getConfigFile();
const emailSettings = configSettings.settings.email;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Body, Put } from '@nestjs/common';
import { ApiOkResponse } from '@nestjs/swagger';
import { MainSettingsAdminBody } from 'vitnode-shared/admin/settings/main.dto';

import { EditMainSettingsAdminService } from './services/edit.main.service';
import { EditMainSettingsAdminService } from './services/edit.service';

@Controllers({
plugin_name: 'Core',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Module } from '@nestjs/common';

import { MainSettingsAdminController } from './main.controller';
import { EditMainSettingsAdminService } from './services/edit.main.service';
import { EditMainSettingsAdminService } from './services/edit.service';

@Module({
providers: [EditMainSettingsAdminService],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,22 @@ import { join } from 'path';
import { MainSettingsAdminBody } from 'vitnode-shared/admin/settings/main.dto';
import { ManifestWithLang } from 'vitnode-shared/manifest.dto';

import { getManifest, ManifestType } from '../../metadata/helpers';

@Injectable()
export class EditMainSettingsAdminService {
constructor(private readonly databaseService: InternalDatabaseService) {}

protected async updateDescription({
languages,
site_description,
site_name,
site_short_name,
}: {
languages: { code: string }[];
site_description: MainSettingsAdminBody['site_description'];
site_name: MainSettingsAdminBody['site_name'];
site_short_name: MainSettingsAdminBody['site_short_name'];
}) {
const update = await Promise.all(
(site_description ?? []).map(async el => {
Expand All @@ -32,22 +38,25 @@ export class EditMainSettingsAdminService {
throw new InternalServerErrorException();
}

const path = join(
ABSOLUTE_PATHS.uploads.public,
'assets',
item.language_code,
'manifest.webmanifest',
);
const manifest: ManifestWithLang = JSON.parse(
await readFile(path, 'utf8'),
);
const newData: ManifestWithLang = {
const manifest = await getManifest({ lang_code: item.language_code });
const newData: ManifestType = {
...manifest,
lang: el.language_code,
description: item.value,
name: site_name,
short_name: site_short_name,
};

await writeFile(path, JSON.stringify(newData, null, 2), 'utf8');
await writeFile(
join(
ABSOLUTE_PATHS.uploads.public,
'assets',
item.language_code,
'manifest.webmanifest',
),
JSON.stringify(newData, null, 2),
'utf8',
);

return el.language_code;
}),
Expand Down Expand Up @@ -112,6 +121,8 @@ export class EditMainSettingsAdminService {
await this.updateDescription({
languages,
site_description,
site_name,
site_short_name,
});

return {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { ABSOLUTE_PATHS } from '@/app.module';
import { Injectable, NotFoundException } from '@nestjs/common';
import { NotFoundException } from '@nestjs/common';
import { existsSync } from 'fs';
import { readFile } from 'fs/promises';
import { join } from 'path';
import { ManifestDisplay } from 'vitnode-shared/admin/settings/metadata.enum';
import { FileObj } from 'vitnode-shared/utils/files.dto';

export interface ManifestType {
background_color: string;
Expand All @@ -16,12 +17,12 @@ export interface ManifestType {
| 'standalone'
| 'window-controls-overlay'
)[];
icons?: {
icons?: (FileObj & {
purpose?: 'any' | 'badge' | 'maskable' | 'monochrome';
sizes?: string;
src: string;
type?: string;
}[];
})[];
id: string;
lang: string;
name: string;
Expand Down Expand Up @@ -56,27 +57,24 @@ export interface ManifestType {
theme_color: string;
}

@Injectable()
export class HelpersShowMetadataAdminService {
async getManifest({
export const getManifest = async ({
lang_code,
}: {
lang_code: string;
}): Promise<ManifestType> => {
const path = join(
ABSOLUTE_PATHS.uploads.public,
'assets',
lang_code,
}: {
lang_code: string;
}): Promise<ManifestType> {
const path = join(
ABSOLUTE_PATHS.uploads.public,
'assets',
lang_code,
'manifest.webmanifest',
);
'manifest.webmanifest',
);

if (!existsSync(path)) {
throw new NotFoundException('MANIFEST_NOT_FOUND');
}
if (!existsSync(path)) {
throw new NotFoundException('MANIFEST_NOT_FOUND');
}

const file = await readFile(path, 'utf8');
const data: ManifestType = JSON.parse(file);
const file = await readFile(path, 'utf8');
const data: ManifestType = JSON.parse(file);

return data;
}
}
return data;
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Controllers } from '@/helpers/controller.decorator';
import { Body, Get, Put } from '@nestjs/common';
import { FilesValidationPipe } from '@/helpers/files/files.pipe';
import { UploadFilesMethod } from '@/helpers/upload-files.decorator';
import { Body, Get, Put, UploadedFiles } from '@nestjs/common';
import { ApiOkResponse } from '@nestjs/swagger';
import {
ShowMetadataAdminBody,
Expand All @@ -26,10 +28,28 @@ export class MetadataAdminController {
type: ShowMetadataAdminObj,
})
@Put()
@UploadFilesMethod({ fields: ['icon', 'favicon'] })
async edit(
@UploadedFiles(
new FilesValidationPipe({
icon: {
maxSize: 1024 * 1024, // 1 MB
acceptMimeType: ['image/png', 'image/jpeg', 'image/webp'],
isOptional: true,
maxCount: 1,
},
favicon: {
maxSize: 1024 * 1024, // 1 MB
acceptMimeType: ['image/x-icon', 'image/vnd.microsoft.icon'],
isOptional: true,
maxCount: 1,
},
}),
)
files: Pick<ShowMetadataAdminBody, 'favicon' | 'icon'>,
@Body() body: ShowMetadataAdminBody,
): Promise<ShowMetadataAdminObj> {
return this.editService.edit(body);
return this.editService.edit({ body, files });
}

@ApiOkResponse({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
import { Module } from '@nestjs/common';

import { HelpersShowMetadataAdminService } from './helpers.service';
import { MetadataAdminController } from './metadata.controller';
import { EditMetadataAdminService } from './services/edit.service';
import { ShowMetadataAdminService } from './services/show.service';

@Module({
providers: [
ShowMetadataAdminService,
HelpersShowMetadataAdminService,
EditMetadataAdminService,
],
providers: [ShowMetadataAdminService, EditMetadataAdminService],
controllers: [MetadataAdminController],
})
export class MetadataSettingsAdminModule {}
Loading

0 comments on commit d7f9457

Please sign in to comment.