HBE-147 refactor: Introduce shortcodes into self-host refactored to pseudo-fp format (#22)

* refactor: refactor all queries,mutations and subscriptions for shortcode module

* test: rewrote test cases for shortcodes

* chore: modified shortcode error code

* chore: created helper function to do shortcode type conversion in service file

* chore: simplifed logic to fetch user shortcodes with cursor pagination

* chore: removed migrations file

* chore: removed unused imports in shortcodes module

* chore: modified generateUniqueShortCodeID function

* chore: modified generateUniqueShortCodeID function

* chore: changed jwtService to use verify instead of decode

* docs: added teacher comments to all shortcodes service methods

* chore: removed stale test cases from shortcode modules
This commit is contained in:
Balu Babu
2023-02-22 17:40:53 +05:30
committed by GitHub
parent 24dd535d9e
commit 1860057a25
7 changed files with 470 additions and 743 deletions

View File

@@ -7,23 +7,19 @@ import {
Resolver,
Subscription,
} from '@nestjs/graphql';
import { pipe } from 'fp-ts/function';
import * as E from 'fp-ts/Either';
import * as T from 'fp-ts/Task';
import * as TO from 'fp-ts/TaskOption';
import * as TE from 'fp-ts/TaskEither';
import { UseGuards } from '@nestjs/common';
import { Shortcode } from './shortcode.model';
import { ShortcodeService } from './shortcode.service';
import { UserService } from 'src/user/user.service';
import { throwErr } from 'src/utils';
import { SHORTCODE_INVALID_JSON } from 'src/errors';
import { GqlUser } from 'src/decorators/gql-user.decorator';
import { GqlAuthGuard } from 'src/guards/gql-auth.guard';
import { User } from 'src/user/user.model';
import { PubSubService } from 'src/pubsub/pubsub.service';
import { AuthUser } from '../types/AuthUser';
import { JwtService } from '@nestjs/jwt';
import { PaginationArgs } from 'src/types/input-types.args';
@Resolver(() => Shortcode)
export class ShortcodeResolver {
@@ -31,155 +27,95 @@ export class ShortcodeResolver {
private readonly shortcodeService: ShortcodeService,
private readonly userService: UserService,
private readonly pubsub: PubSubService,
private jwtService: JwtService,
) {}
/* Queries */
@Query(() => Shortcode, {
description: 'Resolves and returns a shortcode data',
nullable: true,
})
shortcode(
async shortcode(
@Args({
name: 'code',
type: () => ID,
description: 'The shortcode to resolve',
})
code: string,
): Promise<Shortcode | null> {
return pipe(
this.shortcodeService.resolveShortcode(code),
TO.getOrElseW(() => T.of(null)),
)();
) {
const result = await this.shortcodeService.getShortCode(code);
if (E.isLeft(result)) throwErr(result.left);
return result.right;
}
@Query(() => [Shortcode], {
description: 'List all shortcodes the current user has generated',
})
@UseGuards(GqlAuthGuard)
myShortcodes(
@GqlUser() user: AuthUser,
@Args({
name: 'cursor',
type: () => ID,
description:
'The ID of the last returned shortcode (used for pagination)',
nullable: true,
})
cursor?: string,
): Promise<Shortcode[]> {
return this.shortcodeService.fetchUserShortCodes(
user.uid,
cursor ?? null,
)();
async myShortcodes(@GqlUser() user: AuthUser, @Args() args: PaginationArgs) {
return this.shortcodeService.fetchUserShortCodes(user.uid, args);
}
/* Mutations */
@Mutation(() => Shortcode, {
description: 'Create a shortcode for the given request.',
})
async createShortcode(
@Args({
name: 'request',
description: 'JSON string of the request object',
})
request: string,
@Context() ctx: any,
) {
const decodedAccessToken = this.jwtService.verify(
ctx.req.cookies['access_token'],
);
const result = await this.shortcodeService.createShortcode(
request,
decodedAccessToken?.sub,
);
// TODO: Create a shortcode resolver pending implementation
// @Mutation(() => Shortcode, {
// description: 'Create a shortcode for the given request.',
// })
// createShortcode(
// @Args({
// name: 'request',
// description: 'JSON string of the request object',
// })
// request: string,
// @Context() ctx: any,
// ): Promise<Shortcode> {
// return pipe(
// TE.Do,
//
// // Get the user
// TE.bind('user', () =>
// pipe(
// TE.tryCatch(
// () => {
// const authString: string | undefined | null =
// ctx.reqHeaders.authorization;
//
// if (
// !authString ||
// !authString.includes(' ') ||
// !authString.startsWith('Bearer ')
// ) {
// return Promise.reject('no auth token');
// }
//
// const authToken = authString.split(' ')[1];
//
// return this.userService.authenticateWithIDToken(authToken);
// },
// (e) => e,
// ),
// TE.getOrElseW(() => T.of(undefined)),
// TE.fromTask,
// ),
// ),
//
// // Get the Request JSON
// TE.bind('reqJSON', () =>
// pipe(
// E.tryCatch(
// () => JSON.parse(request),
// () => SHORTCODE_INVALID_JSON,
// ),
// TE.fromEither,
// ),
// ),
//
// // Create the shortcode
// TE.chain(({ reqJSON, user }) => {
// return TE.fromTask(
// this.shortcodeService.createShortcode(reqJSON, user),
// );
// }),
//
// // Return or throw if there is an error
// TE.getOrElse(throwErr),
// )();
// }
if (E.isLeft(result)) throwErr(result.left);
return result.right;
}
// TODO: Implement revoke shortcode
// @Mutation(() => Boolean, {
// description: 'Revoke a user generated shortcode',
// })
// @UseGuards(GqlAuthGuard)
// revokeShortcode(
// @GqlUser() user: User,
// @Args({
// name: 'code',
// type: () => ID,
// description: 'The shortcode to resolve',
// })
// code: string,
// ): Promise<boolean> {
// return pipe(
// this.shortcodeService.revokeShortCode(code, user.uid),
// TE.map(() => true), // Just return true on success, no resource to return
// TE.getOrElse(throwErr),
// )();
// }
@Mutation(() => Boolean, {
description: 'Revoke a user generated shortcode',
})
@UseGuards(GqlAuthGuard)
async revokeShortcode(
@GqlUser() user: User,
@Args({
name: 'code',
type: () => ID,
description: 'The shortcode to resolve',
})
code: string,
) {
const result = await this.shortcodeService.revokeShortCode(code, user.uid);
if (E.isLeft(result)) throwErr(result.left);
return result.right;
}
/* Subscriptions */
@Subscription(() => Shortcode, {
description: 'Listen for shortcode creation',
resolve: (value) => value,
})
@UseGuards(GqlAuthGuard)
myShortcodesCreated(@GqlUser() user: AuthUser) {
return this.pubsub.asyncIterator(`shortcode/${user.uid}/created`);
}
// TODO: update subscription after fixing service methods
// @Subscription(() => Shortcode, {
// description: 'Listen for shortcode creation',
// resolve: (value) => value,
// })
// @UseGuards(GqlAuthGuard)
// myShortcodesCreated(@GqlUser() user: AuthUser) {
// return this.pubsub.asyncIterator(`shortcode/${user.uid}/created`);
// }
//
// @Subscription(() => Shortcode, {
// description: 'Listen for shortcode deletion',
// resolve: (value) => value,
// })
// @UseGuards(GqlAuthGuard)
// myShortcodesRevoked(@GqlUser() user: AuthUser): AsyncIterator<Shortcode> {
// return this.pubsub.asyncIterator(`shortcode/${user.uid}/revoked`);
// }
@Subscription(() => Shortcode, {
description: 'Listen for shortcode deletion',
resolve: (value) => value,
})
@UseGuards(GqlAuthGuard)
myShortcodesRevoked(@GqlUser() user: AuthUser): AsyncIterator<Shortcode> {
return this.pubsub.asyncIterator(`shortcode/${user.uid}/revoked`);
}
}