Skip to content

Commit

Permalink
coupon resolver authorization
Browse files Browse the repository at this point in the history
  • Loading branch information
rwieruch committed Apr 16, 2020
1 parent 52d9f99 commit 1551580
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 23 deletions.
4 changes: 2 additions & 2 deletions src/api/authorization/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import { isFreeCourse } from './isFreeCourse';

export default shield({
Query: {
me: isAuthenticated,
discountedPrice: isAuthenticated,
// me: isAuthenticated,
// discountedPrice: isAuthenticated,

// Partner

Expand Down
20 changes: 20 additions & 0 deletions src/api/middleware/resolver/isAdmin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { MiddlewareFn } from 'type-graphql';
import { ForbiddenError } from 'apollo-server';

import { ResolverContext } from '@typeDefs/resolver';
import { hasAdminRole } from '@validation/admin';

export const isAdmin: MiddlewareFn<ResolverContext> = async (
{ context },
next
) => {
if (!context.me) {
throw new ForbiddenError('Not authenticated as user.');
}

if (!hasAdminRole(context.me)) {
throw new ForbiddenError('No admin user.');
}

return next();
};
2 changes: 1 addition & 1 deletion src/api/middleware/resolver/isAuthenticated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const isAuthenticated: MiddlewareFn<ResolverContext> = async (
next
) => {
if (!context.me) {
return new ForbiddenError('Not authenticated as user.');
throw new ForbiddenError('Not authenticated as user.');
}

return next();
Expand Down
17 changes: 9 additions & 8 deletions src/api/resolvers/coupon/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@ import {
Resolver,
Query,
Mutation,
UseMiddleware,
} from 'type-graphql';

import { ResolverContext } from '@typeDefs/resolver';
import { priceWithDiscount } from '@services/discount';
import storefront from '@data/course-storefront';
import { COURSE } from '@data/course-keys-types';
import { BUNDLE } from '@data/bundle-keys-types';
import { isAuthenticated } from '@api/middleware/resolver/isAuthenticated';
import { isAdmin } from '@api/middleware/resolver/isAdmin';
@ObjectType()
class Discount {
@Field()
Expand All @@ -25,19 +28,16 @@ class Discount {
@Resolver()
export default class CouponResolver {
@Query(() => Discount)
@UseMiddleware(isAuthenticated)
async discountedPrice(
@Arg('courseId') courseId: string,
@Arg('bundleId') bundleId: string,
@Arg('coupon') coupon: string,
@Ctx() ctx: ResolverContext
) {
): Promise<Discount> {
const course = storefront[courseId as COURSE];
const bundle = course.bundles[bundleId as BUNDLE];

if (!ctx.me) {
return bundle.price;
}

const price = await priceWithDiscount(
ctx.couponConnector,
ctx.courseConnector
Expand All @@ -46,7 +46,7 @@ export default class CouponResolver {
bundleId as BUNDLE,
bundle.price,
coupon,
ctx.me.uid
ctx.me!.uid
);

return {
Expand All @@ -55,13 +55,14 @@ export default class CouponResolver {
};
}

@Mutation(() => Boolean, { nullable: true })
@Mutation(() => Boolean)
@UseMiddleware(isAuthenticated, isAdmin)
async couponCreate(
@Arg('coupon') coupon: string,
@Arg('discount') discount: number,
@Arg('count') count: number,
@Ctx() ctx: ResolverContext
) {
): Promise<Boolean> {
try {
await ctx.couponConnector.createCoupons(
coupon,
Expand Down
10 changes: 6 additions & 4 deletions src/api/resolvers/session/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export default class SessionResolver {
@Arg('username') username: string,
@Arg('email') email: string,
@Arg('password') password: string
) {
): Promise<SessionToken> {
try {
await firebaseAdmin.auth().createUser({
email,
Expand Down Expand Up @@ -112,7 +112,9 @@ export default class SessionResolver {
}

@Mutation(() => Boolean)
async passwordForgot(@Arg('email') email: string) {
async passwordForgot(
@Arg('email') email: string
): Promise<Boolean> {
try {
await firebase.auth().sendPasswordResetEmail(email);
} catch (error) {
Expand All @@ -127,7 +129,7 @@ export default class SessionResolver {
async passwordChange(
@Arg('password') password: string,
@Ctx() ctx: ResolverContext
) {
): Promise<Boolean> {
try {
await firebaseAdmin.auth().updateUser(ctx.me!.uid, {
password,
Expand All @@ -144,7 +146,7 @@ export default class SessionResolver {
async emailChange(
@Arg('email') email: string,
@Ctx() ctx: ResolverContext
) {
): Promise<Boolean> {
try {
await firebaseAdmin.auth().updateUser(ctx.me!.uid, {
email,
Expand Down
18 changes: 11 additions & 7 deletions src/api/resolvers/user/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,19 @@ import {
Ctx,
Resolver,
Query,
UseMiddleware,
} from 'type-graphql';

import { ResolverContext } from '@typeDefs/resolver';
import { isAuthenticated } from '@api/middleware/resolver/isAuthenticated';

@ObjectType()
class User {
@Field()
email: string;
uid: string;

@Field()
uid: string;
email: string;

@Field()
username: string;
Expand All @@ -26,16 +28,18 @@ class User {
@Resolver()
export default class UserResolver {
@Query(() => User)
async me(@Ctx() ctx: ResolverContext) {
const rolesObject = ctx.me?.customClaims || {};
@UseMiddleware(isAuthenticated)
async me(@Ctx() ctx: ResolverContext): Promise<User> {
const rolesObject = ctx.me!.customClaims || {};

const roles = Object.keys(rolesObject).filter(
key => rolesObject[key]
);

return {
email: ctx.me?.email,
uid: ctx.me?.uid,
username: ctx.me?.displayName,
uid: ctx.me!.uid,
email: ctx.me!.email || '',
username: ctx.me!.displayName || '',
roles,
};
}
Expand Down
2 changes: 1 addition & 1 deletion src/validation/admin.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as ROLES from '@constants/roles';
import { User } from '@typeDefs/user';

export const hasAdminRole = (user: User) =>
export const hasAdminRole = (user: User | null | undefined) =>
user && user.customClaims && user.customClaims[ROLES.ADMIN];

0 comments on commit 1551580

Please sign in to comment.