From 8df8b056d9862cf33c021f2986715e9ba1c3bcb4 Mon Sep 17 00:00:00 2001 From: Mir Arif Hasan Date: Tue, 28 Nov 2023 16:47:29 +0600 Subject: [PATCH] feat: added mutations and query --- .../src/admin/infra.resolver.ts | 47 ++++++++++++ packages/hoppscotch-backend/src/errors.ts | 6 ++ .../src/infra-config/helper.ts | 5 ++ .../src/infra-config/infra-config.model.ts | 24 ++++--- .../src/infra-config/infra-config.service.ts | 71 ++++++++++++++++--- .../src/infra-config/input-args.ts | 6 +- .../src/types/InfraConfig.ts | 14 ++++ 7 files changed, 149 insertions(+), 24 deletions(-) diff --git a/packages/hoppscotch-backend/src/admin/infra.resolver.ts b/packages/hoppscotch-backend/src/admin/infra.resolver.ts index 146d510fe..0fd945bc8 100644 --- a/packages/hoppscotch-backend/src/admin/infra.resolver.ts +++ b/packages/hoppscotch-backend/src/admin/infra.resolver.ts @@ -26,6 +26,8 @@ import { ShortcodeWithUserEmail } from 'src/shortcode/shortcode.model'; import { InfraConfig } from 'src/infra-config/infra-config.model'; import { InfraConfigService } from 'src/infra-config/infra-config.service'; import { InfraConfigArgs } from 'src/infra-config/input-args'; +import { AuthProvider } from 'src/auth/helper'; +import { Status } from 'src/infra-config/helper'; @UseGuards(GqlThrottlerGuard) @Resolver(() => Infra) @@ -236,6 +238,14 @@ export class InfraResolver { ); } + @Query(() => [String], { + description: 'Allowed Auth Provider list', + }) + @UseGuards(GqlAuthGuard, GqlAdminGuard) + allowedAuthProviders() { + return this.infraConfigService.getAllowedAuthProviders(); + } + /* Mutations */ @Mutation(() => [InfraConfig], { @@ -254,4 +264,41 @@ export class InfraResolver { if (E.isLeft(updatedRes)) throwErr(updatedRes.left); return updatedRes.right; } + + @Mutation(() => Boolean, { + description: 'Reset Infra Configs with default values (.env)', + }) + @UseGuards(GqlAuthGuard, GqlAdminGuard) + async resetInfraConfigs() { + const resetRes = await this.infraConfigService.reset(); + if (E.isLeft(resetRes)) throwErr(resetRes.left); + return true; + } + + @Mutation(() => Boolean, { + description: 'Enable or Disable SSO for login/signup', + }) + @UseGuards(GqlAuthGuard, GqlAdminGuard) + async enableAndDisableSSO( + @Args({ + name: 'provider', + type: () => AuthProvider, + description: 'Auth Provider to enable or disable', + }) + provider: AuthProvider, + @Args({ + name: 'status', + type: () => Status, + description: 'Status to enable or disable', + }) + status: Status, + ) { + const isUpdated = await this.infraConfigService.enableAndDisableSSO( + provider, + status, + ); + if (E.isLeft(isUpdated)) throwErr(isUpdated.left); + + return true; + } } diff --git a/packages/hoppscotch-backend/src/errors.ts b/packages/hoppscotch-backend/src/errors.ts index d51593e4f..f59545b31 100644 --- a/packages/hoppscotch-backend/src/errors.ts +++ b/packages/hoppscotch-backend/src/errors.ts @@ -664,6 +664,12 @@ export const INFRA_CONFIG_UPDATE_FAILED = 'infra_config/update_failed' as const; export const INFRA_CONFIG_NOT_LISTED = 'infra_config/properly_not_listed' as const; +/** + * Infra Config reset failed + * (InfraConfigService) + */ +export const INFRA_CONFIG_RESET_FAILED = 'infra_config/reset_failed' as const; + /** * Error message for when the database table does not exist * (InfraConfigService) diff --git a/packages/hoppscotch-backend/src/infra-config/helper.ts b/packages/hoppscotch-backend/src/infra-config/helper.ts index ea8b12af6..bbb34256b 100644 --- a/packages/hoppscotch-backend/src/infra-config/helper.ts +++ b/packages/hoppscotch-backend/src/infra-config/helper.ts @@ -1,5 +1,10 @@ import { PrismaService } from 'src/prisma/prisma.service'; +export enum Status { + ENABLE = 'ENABLE', + DISABLE = 'DISABLE', +} + /** * Load environment variables from the database and set them in the process * diff --git a/packages/hoppscotch-backend/src/infra-config/infra-config.model.ts b/packages/hoppscotch-backend/src/infra-config/infra-config.model.ts index b431721e3..8e6295e26 100644 --- a/packages/hoppscotch-backend/src/infra-config/infra-config.model.ts +++ b/packages/hoppscotch-backend/src/infra-config/infra-config.model.ts @@ -1,18 +1,14 @@ -import { - ArgsType, - Field, - InputType, - ObjectType, - registerEnumType, -} from '@nestjs/graphql'; -import { InfraConfigEnum } from 'src/types/InfraConfig'; +import { Field, ObjectType, registerEnumType } from '@nestjs/graphql'; +import { AuthProvider } from 'src/auth/helper'; +import { InfraConfigEnumForClient } from 'src/types/InfraConfig'; +import { Status } from './helper'; @ObjectType() export class InfraConfig { @Field({ description: 'Infra Config Name', }) - name: InfraConfigEnum; + name: InfraConfigEnumForClient; @Field({ description: 'Infra Config Value', @@ -20,6 +16,14 @@ export class InfraConfig { value: string; } -registerEnumType(InfraConfigEnum, { +registerEnumType(InfraConfigEnumForClient, { name: 'InfraConfigEnum', }); + +registerEnumType(AuthProvider, { + name: 'AuthProvider', +}); + +registerEnumType(Status, { + name: 'Status', +}); diff --git a/packages/hoppscotch-backend/src/infra-config/infra-config.service.ts b/packages/hoppscotch-backend/src/infra-config/infra-config.service.ts index 4f78ab5b1..913a122b4 100644 --- a/packages/hoppscotch-backend/src/infra-config/infra-config.service.ts +++ b/packages/hoppscotch-backend/src/infra-config/infra-config.service.ts @@ -8,12 +8,14 @@ import { DATABASE_TABLE_NOT_EXIST, INFRA_CONFIG_NOT_FOUND, INFRA_CONFIG_NOT_LISTED, + INFRA_CONFIG_RESET_FAILED, INFRA_CONFIG_UPDATE_FAILED, } from 'src/errors'; import { throwErr } from 'src/utils'; import { ConfigService } from '@nestjs/config'; -import { stopApp } from './helper'; +import { Status, stopApp } from './helper'; import { InfraConfigArgs } from './input-args'; +import { AuthProvider } from 'src/auth/helper'; @Injectable() export class InfraConfigService implements OnModuleInit { @@ -26,9 +28,9 @@ export class InfraConfigService implements OnModuleInit { await this.initializeInfraConfigTable(); } - getDefaultInfraConfigs(): InfraConfig[] { - // Prepare rows for 'infra_config' table with default values for each 'name' - const infraConfigDefaultObjs: InfraConfig[] = [ + getDefaultInfraConfigs(): { name: InfraConfigEnum; value: string }[] { + // Prepare rows for 'infra_config' table with default values (from .env) for each 'name' + const infraConfigDefaultObjs: { name: InfraConfigEnum; value: string }[] = [ { name: InfraConfigEnum.MAILER_SMTP_URL, value: process.env.MAILER_SMTP_URL, @@ -72,6 +74,7 @@ export class InfraConfigService implements OnModuleInit { /** * Initialize the 'infra_config' table with values from .env + * @description This function create rows 'infra_config' in very first time (only once) */ async initializeInfraConfigTable() { try { @@ -167,11 +170,40 @@ export class InfraConfigService implements OnModuleInit { return E.right(infraConfigs); } catch (e) { - console.log(e); return E.left(INFRA_CONFIG_UPDATE_FAILED); } } + /** + * Enable or Disable SSO for login/signup + * @param provider Auth Provider to enable or disable + * @param status Status to enable or disable + * @returns Either true or an error + */ + async enableAndDisableSSO(provider: AuthProvider, status: Status) { + const enabledAuthProviders = this.configService + .get('INFRA.VITE_ALLOWED_AUTH_PROVIDERS') + .split(','); + const isProviderEnabled = enabledAuthProviders.includes(provider); + + let newEnabledAuthProviders = enabledAuthProviders; + if (status === Status.ENABLE && !isProviderEnabled) { + newEnabledAuthProviders = [...enabledAuthProviders, provider]; + } else if (status === Status.DISABLE && isProviderEnabled) { + newEnabledAuthProviders = enabledAuthProviders.filter( + (p) => p !== provider, + ); + } + + const isUpdated = await this.update( + InfraConfigEnum.VITE_ALLOWED_AUTH_PROVIDERS, + newEnabledAuthProviders.join(','), + ); + if (E.isLeft(isUpdated)) throwErr(isUpdated.left); + + return E.right(true); + } + /** * Get InfraConfig by name * @param name Name of the InfraConfig @@ -189,18 +221,35 @@ export class InfraConfigService implements OnModuleInit { } } + /** + * Get allowed auth providers for login/signup + * @returns string[] + */ + getAllowedAuthProviders() { + return this.configService + .get('INFRA.VITE_ALLOWED_AUTH_PROVIDERS') + .split(','); + } + /** * Reset all the InfraConfigs to their default values (from .env) */ async reset() { - const infraConfigDefaultObjs = this.getDefaultInfraConfigs(); + try { + const infraConfigDefaultObjs = this.getDefaultInfraConfigs(); - await this.prisma.infraConfig.deleteMany({ - where: { name: { in: infraConfigDefaultObjs.map((p) => p.name) } }, - }); + await this.prisma.infraConfig.deleteMany({ + where: { name: { in: infraConfigDefaultObjs.map((p) => p.name) } }, + }); + await this.prisma.infraConfig.createMany({ + data: infraConfigDefaultObjs, + }); - await this.prisma.infraConfig.createMany({ data: infraConfigDefaultObjs }); + stopApp(); - stopApp(); + return E.right(true); + } catch (e) { + return E.left(INFRA_CONFIG_RESET_FAILED); + } } } diff --git a/packages/hoppscotch-backend/src/infra-config/input-args.ts b/packages/hoppscotch-backend/src/infra-config/input-args.ts index f283ff432..df2c46544 100644 --- a/packages/hoppscotch-backend/src/infra-config/input-args.ts +++ b/packages/hoppscotch-backend/src/infra-config/input-args.ts @@ -1,12 +1,12 @@ import { Field, InputType } from '@nestjs/graphql'; -import { InfraConfigEnum } from 'src/types/InfraConfig'; +import { InfraConfigEnumForClient } from 'src/types/InfraConfig'; @InputType() export class InfraConfigArgs { - @Field(() => InfraConfigEnum, { + @Field(() => InfraConfigEnumForClient, { description: 'Infra Config Name', }) - name: InfraConfigEnum; + name: InfraConfigEnumForClient; @Field({ description: 'Infra Config Value', diff --git a/packages/hoppscotch-backend/src/types/InfraConfig.ts b/packages/hoppscotch-backend/src/types/InfraConfig.ts index d41ba1d40..5c47eb9e0 100644 --- a/packages/hoppscotch-backend/src/types/InfraConfig.ts +++ b/packages/hoppscotch-backend/src/types/InfraConfig.ts @@ -13,3 +13,17 @@ export enum InfraConfigEnum { VITE_ALLOWED_AUTH_PROVIDERS = 'VITE_ALLOWED_AUTH_PROVIDERS', } + +export enum InfraConfigEnumForClient { + MAILER_SMTP_URL = 'MAILER_SMTP_URL', + MAILER_ADDRESS_FROM = 'MAILER_ADDRESS_FROM', + + GOOGLE_CLIENT_ID = 'GOOGLE_CLIENT_ID', + GOOGLE_CLIENT_SECRET = 'GOOGLE_CLIENT_SECRET', + + GITHUB_CLIENT_ID = 'GITHUB_CLIENT_ID', + GITHUB_CLIENT_SECRET = 'GITHUB_CLIENT_SECRET', + + MICROSOFT_CLIENT_ID = 'MICROSOFT_CLIENT_ID', + MICROSOFT_CLIENT_SECRET = 'MICROSOFT_CLIENT_SECRET', +}