Skip to content

Commit

Permalink
feat: Add upload and delete avatar API
Browse files Browse the repository at this point in the history
  • Loading branch information
aXenDeveloper committed Dec 6, 2024
1 parent e4f01df commit 3879afc
Show file tree
Hide file tree
Showing 46 changed files with 257 additions and 58 deletions.
1 change: 1 addition & 0 deletions apps/frontend/src/plugins/core/langs/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@
"title": "Change Avatar",
"desc": "Show your personality with a new avatar.",
"submit": "Change Avatar",
"success": "Your avatar has been changed.",
"types": {
"upload": "Upload a new avatar",
"delete": "Delete avatar"
Expand Down
7 changes: 6 additions & 1 deletion packages/backend/src/core/auth/settings/settings.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@ import { Module } from '@nestjs/common';

import { DevicesSettingsAuthModule } from './devices/devices.module';
import { FilesSettingsAuthModule } from './files/files.module';
import { UserSettingsAuthModule } from './user/user.module';

@Module({
imports: [DevicesSettingsAuthModule, FilesSettingsAuthModule],
imports: [
DevicesSettingsAuthModule,
FilesSettingsAuthModule,
UserSettingsAuthModule,
],
})
export class SettingsAuthModule {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { core_files_avatars } from '@/database/schema/users';
import { FilesHelperService } from '@/helpers/files/files-helper.service';
import { InternalDatabaseService } from '@/utils/database/internal_database.service';
import { BadRequestException, Injectable } from '@nestjs/common';
import { eq } from 'drizzle-orm';
import { UploadAvatarUserSettingsAuthBody } from 'vitnode-shared/auth/settings/user.dto';
import { User } from 'vitnode-shared/user.dto';

@Injectable()
export class UploadAvatarUserSettingsAuthService {
constructor(
private readonly databaseService: InternalDatabaseService,
private readonly filesHelper: FilesHelperService,
) {}

async uploadAvatar({
body: { delete_avatar },
currentUser,
files: { avatar },
}: {
body: Omit<UploadAvatarUserSettingsAuthBody, 'avatar'>;
currentUser: User;
files: Pick<UploadAvatarUserSettingsAuthBody, 'avatar'>;
}): Promise<void> {
if (!delete_avatar && !avatar) {
throw new BadRequestException('No avatar provided');
}

const avatarFromDB =
await this.databaseService.db.query.core_files_avatars.findFirst({
where: (table, { eq }) => eq(table.user_id, currentUser.id),
});

if (avatarFromDB || (delete_avatar && avatarFromDB)) {
await this.filesHelper.delete({
dir_folder: avatarFromDB.dir_folder,
file_name: avatarFromDB.file_name,
});

await this.databaseService.db
.delete(core_files_avatars)
.where(eq(core_files_avatars.user_id, currentUser.id));

if (delete_avatar) return;
}

const file = await this.filesHelper.upload({
file: avatar,
folder: 'avatars',
plugin_code: 'core',
});

await this.databaseService.db.insert(core_files_avatars).values({
...file,
user_id: currentUser.id,
});
}
}
51 changes: 51 additions & 0 deletions packages/backend/src/core/auth/settings/user/user.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
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, Put, UploadedFiles } from '@nestjs/common';
import { ApiOkResponse } from '@nestjs/swagger';
import { UploadAvatarUserSettingsAuthBody } from 'vitnode-shared/auth/settings/user.dto';
import { User } from 'vitnode-shared/user.dto';

import { UploadAvatarUserSettingsAuthService } from './services/upload_avatar.service';

@Controllers({
plugin_name: 'Core',
plugin_code: 'core',
route: 'auth/settings/user',
isProtect: true,
})
export class UserSettingsAuthController {
constructor(
private readonly uploadAvatarService: UploadAvatarUserSettingsAuthService,
) {}

@ApiOkResponse({
description: 'Upload or delete avatar',
})
@Put('avatar')
@UploadFilesMethod({
fields: ['avatar'],
})
async uploadAvatar(
@UploadedFiles(
new FilesValidationPipe({
avatar: {
maxSize: 1024 * 1024 * 2, // 2 MB
acceptMimeType: ['image/png', 'image/jpeg', 'image/webp'],
isOptional: true,
maxCount: 1,
},
}),
)
files: Pick<UploadAvatarUserSettingsAuthBody, 'avatar'>,
@Body() body: UploadAvatarUserSettingsAuthBody,
@CurrentUser() currentUser: User,
): Promise<void> {
await this.uploadAvatarService.uploadAvatar({
body,
files,
currentUser,
});
}
}
10 changes: 10 additions & 0 deletions packages/backend/src/core/auth/settings/user/user.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Module } from '@nestjs/common';

import { UploadAvatarUserSettingsAuthService } from './services/upload_avatar.service';
import { UserSettingsAuthController } from './user.controller';

@Module({
providers: [UploadAvatarUserSettingsAuthService],
controllers: [UserSettingsAuthController],
})
export class UserSettingsAuthModule {}
9 changes: 6 additions & 3 deletions packages/backend/src/database/schema/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,12 @@ export const core_files_avatars = pgTable('core_files_avatars', t => ({
file_size: t.integer().notNull(),
mimetype: t.varchar({ length: 255 }).notNull(),
extension: t.varchar({ length: 32 }).notNull(),
user_id: t.integer().references(() => core_users.id, {
onDelete: 'cascade',
}),
user_id: t
.integer()
.references(() => core_users.id, {
onDelete: 'cascade',
})
.unique(),
}));

export const core_files_avatars_relations = relations(
Expand Down
1 change: 1 addition & 0 deletions packages/backend/src/helpers/user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ export class UserHelper {
language: user.language,
name: user.name,
name_seo: user.name_seo,
avatar: user.avatar,
};

if (!withDangerousData) {
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const nextConfig = config => {
},
experimental: {
...(config.experimental || {}),
reactCompiler: true,
// reactCompiler: true,
},
transpilePackages: [
...transpilePackages,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { Input } from '@/components/ui/input';
import { zodResolver } from '@hookform/resolvers/zod';
import { useTranslations } from 'next-intl';
import { useForm } from 'react-hook-form';
import * as z from 'zod';
import { z } from 'zod';

import { useEditorState } from '../../../hooks/use-editor-state';

Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/src/components/form/auto-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
useForm,
UseFormReturn,
} from 'react-hook-form';
import * as z from 'zod';
import { z } from 'zod';

import { Button } from '../ui/button';
import { useDialog } from '../ui/dialog';
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/src/components/form/fields/combobox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { Check } from 'lucide-react';
import { useTranslations } from 'next-intl';
import React from 'react';
import { StringLanguage } from 'vitnode-shared/string-language.dto';
import * as z from 'zod';
import { z } from 'zod';

import { getBaseSchema } from '../utils';
import { AutoFormLabel } from './common/label';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { AutoFormComponentProps } from '@/components/form/auto-form';
import { FormControl, FormItem, FormLabel } from '@/components/ui/form';
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
import * as z from 'zod';
import { z } from 'zod';

import { getBaseSchema } from '../utils';
import { AutoFormLabel } from './common/label';
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/src/components/form/fields/select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
SelectValue,
} from '@/components/ui/select';
import { useTranslations } from 'next-intl';
import * as z from 'zod';
import { z } from 'zod';

import { getBaseSchema } from '../utils';
import { AutoFormLabel } from './common/label';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { FormField, FormMessage } from '@/components/ui/form';
import React from 'react';
import { Control, FieldPath, FieldValues, UseFormWatch } from 'react-hook-form';
import * as z from 'zod';
import { z } from 'zod';

import { AutoFormComponentProps } from '../../auto-form';
import resolveDependencies, {
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/src/components/form/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { DefaultValues, FieldValues, UseFormWatch } from 'react-hook-form';
import * as z from 'zod';
import { z } from 'zod';

import { DependencyType } from './auto-form';

Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/src/helpers/zod.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as z from 'zod';
import { z } from 'zod';

export const zodLanguageInput = z.array(
z.object({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useDialog } from '@/components/ui/dialog';
import { useTranslations } from 'next-intl';
import { UseFormReturn } from 'react-hook-form';
import { toast } from 'sonner';
import * as z from 'zod';
import { z } from 'zod';

import { CreateEditLangAdmin } from '../create-edit';
import { locales } from '../locales';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useAlertDialog } from '@/components/ui/alert-dialog';
import { usePathname, useRouter } from '@/navigation';
import { useTranslations } from 'next-intl';
import { toast } from 'sonner';
import * as z from 'zod';
import { z } from 'zod';

import { ContentDeleteActionsTableLangsCoreAdmin } from '../content';
import { mutationApi } from './mutation-api';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useTranslations } from 'next-intl';
import { UseFormReturn } from 'react-hook-form';
import { toast } from 'sonner';
import { ShowPluginAdmin } from 'vitnode-shared/admin/plugins.dto';
import * as z from 'zod';
import { z } from 'zod';

import { mutationCreateApi } from './mutation-create-api';
import { mutationEditApi } from './mutation-edit-api';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { zodTag } from '@/helpers/zod';
import { useTranslations } from 'next-intl';
import { UseFormReturn } from 'react-hook-form';
import { toast } from 'sonner';
import * as z from 'zod';
import { z } from 'zod';

import { useDevPluginAdmin } from '../../../hooks/use-dev-plugin';
import { CreateEditNavDevPluginAdmin } from '../create-edit';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useDialog } from '@/components/ui/dialog';
import { useTranslations } from 'next-intl';
import { UseFormReturn } from 'react-hook-form';
import { toast } from 'sonner';
import * as z from 'zod';
import { z } from 'zod';

import { useDevPluginAdmin } from '../../../hooks/use-dev-plugin';
import { PermissionsAdminWithI18n } from '../../permissions-admin';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useTranslations } from 'next-intl';
import { UseFormReturn } from 'react-hook-form';
import { toast } from 'sonner';
import { CaptchaTypeEnum } from 'vitnode-shared/utils/global';
import * as z from 'zod';
import { z } from 'zod';

import { ContentCaptchaSpamSecurityAdmin } from '../content';
import { mutationApi } from './mutation-api';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useTranslations } from 'next-intl';
import { toast } from 'sonner';
import { ShowAuthSettingsAdminObj } from 'vitnode-shared/admin/settings/auth.dto';
import * as z from 'zod';
import { z } from 'zod';

import { mutationApi } from './mutation-api';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useDialog } from '@/components/ui/dialog';
import { useTranslations } from 'next-intl';
import React from 'react';
import { toast } from 'sonner';
import * as z from 'zod';
import { z } from 'zod';

import { ContentCreateEditMethodsAuthSettingsAdmin } from '../content';
import { createMutationApi } from './create-mutation-api';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useDialog } from '@/components/ui/dialog';
import { useTranslations } from 'next-intl';
import { toast } from 'sonner';
import * as z from 'zod';
import { z } from 'zod';

import { mutationApi } from './mutation-api';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
EditEmailSettingsAdminBody,
ShowEmailSettingsAdminObj,
} from 'vitnode-shared/admin/settings/email.dto';
import * as z from 'zod';
import { z } from 'zod';

import { ContentEmailSettingsAdmin } from '../content';
import { revalidateApi } from './revalidate-api';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { UseFormReturn } from 'react-hook-form';
import { toast } from 'sonner';
import { CreateLegalSettingsAdminBody } from 'vitnode-shared/admin/settings/legal.dto';
import { LegalsObj } from 'vitnode-shared/legal.dto';
import * as z from 'zod';
import { z } from 'zod';

import { createMutationApi } from './create-mutation-api';
import { editMutationApi } from './edit-mutation-api';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { zodLanguageInput } from '@/helpers/zod';
import { useTranslations } from 'next-intl';
import { toast } from 'sonner';
import { ShowMiddlewareObj } from 'vitnode-shared/middleware.dto';
import * as z from 'zod';
import { z } from 'zod';

import { mutationApi } from './mutation-api';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
ShowMetadataAdminObj,
} from 'vitnode-shared/admin/settings/metadata.dto';
import { ManifestDisplay } from 'vitnode-shared/admin/settings/metadata.enum';
import * as z from 'zod';
import { z } from 'zod';

import { revalidateAllApi } from '../../../diagnostic/actions/clear_cache/hooks/revalidate-all-api';
import { ContentMetadataSettingsAdmin } from '../content';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { UseFormReturn } from 'react-hook-form';
import { toast } from 'sonner';
import { ShowMiddlewareObj } from 'vitnode-shared/middleware.dto';
import { AllowTypeFilesEnum } from 'vitnode-shared/utils/global';
import * as z from 'zod';
import { z } from 'zod';

import { mutationApi } from './mutation-api';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { zodLanguageInput } from '@/helpers/zod';
import { useTextLang } from '@/hooks/use-text-lang';
import { useTranslations } from 'next-intl';
import { toast } from 'sonner';
import * as z from 'zod';
import { z } from 'zod';

import { ContentCreateEditNavAdmin } from '../create-edit';
import { createMutationApi } from './create-mutation-api';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { FilesInputValue } from '@/components/ui/file-input';
import { zodFile } from '@/helpers/zod';
import React from 'react';
import { UseFormReturn } from 'react-hook-form';
import * as z from 'zod';
import { z } from 'zod';

export enum ThemeEditorIds {
dark = 'vitnode_logo_dark',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
EditThemeEditorStylesAdminBody,
EditThemeEditorStylesAdminObj,
} from 'vitnode-shared/admin/styles/theme-editor.dto';
import * as z from 'zod';
import { z } from 'zod';

import { revalidateAllApi } from '../../diagnostic/actions/clear_cache/hooks/revalidate-all-api';
import {
Expand Down
Loading

0 comments on commit 3879afc

Please sign in to comment.