Skip to content

Commit

Permalink
feat(core): write the mutation to login the user
Browse files Browse the repository at this point in the history
  • Loading branch information
tericcabrel committed Jun 11, 2022
1 parent e3d8f27 commit dde8c56
Show file tree
Hide file tree
Showing 13 changed files with 60 additions and 10 deletions.
1 change: 0 additions & 1 deletion apps/core/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,3 @@ WEB_APP_URL=https://localhost:7500
WEB_AUTH_SUCCESS_URL=https://localhost:7500/auth/success
WEB_AUTH_ERROR_URL=https://localhost:7500/auth/error
SESSION_LIFETIME=90# 90 days
AUTH_ENABLED=true
1 change: 0 additions & 1 deletion apps/core/env.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
export type EnvironmentVariables = {
ADMIN_PASSWORD: string;
AUTH_ENABLED: string;
CONVERTKIT_API_KEY: string;
CONVERTKIT_FORM_ID: string;
DATABASE_URL: string;
Expand Down
1 change: 0 additions & 1 deletion apps/core/src/configs/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ dotenv.config();

export const env: AppEnvironmentVariables = {
ADMIN_PASSWORD: getEnv('ADMIN_PASSWORD'),
AUTH_ENABLED: getEnv('AUTH_ENABLED') === 'true',
CONVERTKIT_API_KEY: getEnv('CONVERTKIT_API_KEY'),
CONVERTKIT_FORM_ID: getEnv('CONVERTKIT_FORM_ID'),
DATABASE_URL: getEnv('DATABASE_URL'),
Expand Down
2 changes: 2 additions & 0 deletions apps/core/src/resources/resolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { createSnippet } from './snippets/mutations/createSnippet';
import { allSnippets } from './snippets/queries/allSnippets';
import { mySnippets } from './snippets/queries/mySnippets';
import { dateScalar } from './types/date';
import { loginUser } from './users/mutations/login-user';
import { logoutUser } from './users/mutations/logout-user';
import { authenticatedUser } from './users/queries/authenticated-user';

Expand All @@ -27,6 +28,7 @@ export const resolvers: Resolvers = {
createFolder,
createSnippet,
deleteFolders,
loginUser,
logoutUser,
subscribeToNewsletter,
},
Expand Down
20 changes: 20 additions & 0 deletions apps/core/src/resources/users/mutations/login-user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { logger } from '../../../configs/logger';
import { MutationResolvers } from '../../../types/graphql';
import { createUserSession } from '../../../utils/auth/session';
import { LOGIN_FAILED_MESSAGE } from '../../../utils/constants';
import AppError from '../../../utils/errors/app-error';

export const loginUser: MutationResolvers['loginUser'] = async (_parent, args, context) => {
try {
const { email, password } = args;
const user = await context.db.user.login(email, password);

const session = await createUserSession(user.id);

return { token: session.token };
} catch (err) {
logger.error(err);

throw new AppError(LOGIN_FAILED_MESSAGE, 'LOGIN_FAILED');
}
};
5 changes: 5 additions & 0 deletions apps/core/src/resources/users/schema.graphql
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
type LoginResult {
token: String!
}

type Query {
authenticatedUser: User
}

type Mutation {
loginUser(email: String!, password: String!): LoginResult!
logoutUser: Boolean!
}
2 changes: 1 addition & 1 deletion apps/core/src/server/graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ export const startGraphqlServer = async (expressApplication: Application, httpSe
});

const apolloServer = new ApolloServer({
// formatError: (error) => { console.log(error); },
context: async ({ req, res }): Promise<AppContext> => await buildGraphQLContext(req, res),
debug: env.IS_DEV,
introspection: env.ENABLE_INTROSPECTION,
plugins: [
ApolloServerPluginDrainHttpServer({ httpServer }), // graceful shutdown
Expand Down
3 changes: 1 addition & 2 deletions apps/core/src/types/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@ import { EnvironmentVariables } from '../../env';

export type AppEnvironmentVariables = Omit<
EnvironmentVariables,
'ENABLE_INTROSPECTION' | 'PORT' | 'REQUEST_TIMEOUT' | 'SESSION_LIFETIME' | 'AUTH_ENABLED'
'ENABLE_INTROSPECTION' | 'PORT' | 'REQUEST_TIMEOUT' | 'SESSION_LIFETIME'
> & {
AUTH_ENABLED: boolean;
ENABLE_INTROSPECTION: boolean;
IS_DEV: boolean;
IS_PROD: boolean;
Expand Down
21 changes: 21 additions & 0 deletions apps/core/src/types/graphql.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,17 @@ export type Folder = {
user: User;
};

export type LoginResult = {
__typename?: 'LoginResult';
token: Scalars['String'];
};

export type Mutation = {
__typename?: 'Mutation';
createFolder: Folder;
createSnippet: Snippet;
deleteFolders: Scalars['Boolean'];
loginUser: LoginResult;
logoutUser: Scalars['Boolean'];
subscribeToNewsletter: Result;
};
Expand All @@ -75,6 +81,12 @@ export type MutationDeleteFoldersArgs = {
};


export type MutationLoginUserArgs = {
email: Scalars['String'];
password: Scalars['String'];
};


export type MutationSubscribeToNewsletterArgs = {
email: Scalars['String'];
};
Expand Down Expand Up @@ -226,6 +238,7 @@ export type ResolversTypes = {
Folder: ResolverTypeWrapper<Folder>;
ID: ResolverTypeWrapper<Scalars['ID']>;
Int: ResolverTypeWrapper<Scalars['Int']>;
LoginResult: ResolverTypeWrapper<LoginResult>;
Mutation: ResolverTypeWrapper<{}>;
OauthProvider: OauthProvider;
Query: ResolverTypeWrapper<{}>;
Expand All @@ -247,6 +260,7 @@ export type ResolversParentTypes = {
Folder: Folder;
ID: Scalars['ID'];
Int: Scalars['Int'];
LoginResult: LoginResult;
Mutation: {};
Query: {};
Result: Result;
Expand All @@ -272,10 +286,16 @@ export type FolderResolvers<ContextType = AppContext, ParentType extends Resolve
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};

export type LoginResultResolvers<ContextType = AppContext, ParentType extends ResolversParentTypes['LoginResult'] = ResolversParentTypes['LoginResult']> = {
token?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};

export type MutationResolvers<ContextType = AppContext, ParentType extends ResolversParentTypes['Mutation'] = ResolversParentTypes['Mutation']> = {
createFolder?: Resolver<ResolversTypes['Folder'], ParentType, ContextType, RequireFields<MutationCreateFolderArgs, 'input'>>;
createSnippet?: Resolver<ResolversTypes['Snippet'], ParentType, ContextType, RequireFields<MutationCreateSnippetArgs, 'input'>>;
deleteFolders?: Resolver<ResolversTypes['Boolean'], ParentType, ContextType, RequireFields<MutationDeleteFoldersArgs, 'folderIds'>>;
loginUser?: Resolver<ResolversTypes['LoginResult'], ParentType, ContextType, RequireFields<MutationLoginUserArgs, 'email' | 'password'>>;
logoutUser?: Resolver<ResolversTypes['Boolean'], ParentType, ContextType>;
subscribeToNewsletter?: Resolver<ResolversTypes['Result'], ParentType, ContextType, RequireFields<MutationSubscribeToNewsletterArgs, 'email'>>;
};
Expand Down Expand Up @@ -336,6 +356,7 @@ export type UserResolvers<ContextType = AppContext, ParentType extends Resolvers
export type Resolvers<ContextType = AppContext> = {
Date?: GraphQLScalarType;
Folder?: FolderResolvers<ContextType>;
LoginResult?: LoginResultResolvers<ContextType>;
Mutation?: MutationResolvers<ContextType>;
Query?: QueryResolvers<ContextType>;
Result?: ResultResolvers<ContextType>;
Expand Down
2 changes: 2 additions & 0 deletions apps/core/src/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ export const DATE_REGEX = /^([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]))$/;

export const CORS_APOLLO_STUDIO_URL = 'https://studio.apollographql.com';
export const NEWSLETTER_SUBSCRIBE_SUCCESS = 'Subscribed to the newsletter successfully';

export const LOGIN_FAILED_MESSAGE = 'Invalid email address or password.';
4 changes: 3 additions & 1 deletion apps/core/src/utils/db/data-init.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { roleService, userService } from '@sharingan/domain';

import { env } from '../../configs/env';

export const loadData = async () => {
await roleService.loadRoles();

Expand All @@ -9,5 +11,5 @@ export const loadData = async () => {
throw new Error('[Data Loader]: Role administrator not found');
}

await userService.loadAdminUsers(adminRole);
await userService.loadAdminUser(adminRole, env.ADMIN_PASSWORD);
};
5 changes: 3 additions & 2 deletions packages/domain/src/users/user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ export default class UserService {
return this._userRepository.update(currentUser.id, updateUserDto.toUser(currentUser));
}

async loadAdminUsers(role: Role): Promise<void> {
async loadAdminUser(role: Role, adminPassword: string): Promise<void> {
const userAdminDto = new CreateUserDto({
email: '[email protected]',
name: 'Eric Teco',
oauthProvider: 'github',
oauthProvider: 'email',
password: adminPassword,
pictureUrl: null,
roleId: role.id,
timezone: 'Europe/Paris',
Expand Down
3 changes: 2 additions & 1 deletion packages/domain/tests/services/users/user.service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ describe('Test User service', () => {

it('should load users in the database', async () => {
const [roleAdmin] = await roleService.findAll();
const adminPassword = 'VerStrongPassword';

await userService.loadAdminUsers(roleAdmin);
await userService.loadAdminUser(roleAdmin, adminPassword);

const adminUser = await userService.findByEmail('[email protected]');

Expand Down

0 comments on commit dde8c56

Please sign in to comment.