Skip to content

Commit

Permalink
[FEATURE]: created the front-bo part of the authentication (#32)
Browse files Browse the repository at this point in the history
  • Loading branch information
helabenkhalfallah authored Dec 4, 2024
2 parents 7028a57 + 0809c11 commit e0b4aaf
Show file tree
Hide file tree
Showing 54 changed files with 1,485 additions and 368 deletions.
125 changes: 106 additions & 19 deletions src/v6y-bff/src/resolvers/account/AccountMutations.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import {
AccountInputType,
AccountProvider,
AccountType,
AccountUpdatePasswordType,
AppLogger,
PasswordUtils,
SearchQueryType,
Expand All @@ -12,32 +14,52 @@ const { hashPassword } = PasswordUtils;
* Create or edit account
* @param _
* @param params
* @param context
*/
const createOrEditAccount = async (_: unknown, params: { accountInput: AccountInputType }) => {
const createOrEditAccount = async (
_: unknown,
params: { input: AccountInputType },
context: { user: AccountType },
) => {
try {
const { _id, username, password, email, role, applications } = params?.accountInput || {};
const { _id, username, password, email, role, applications } = params?.input || {};

AppLogger.info(`[AccountMutations - createOrEditAccount] _id : ${_id}`);
AppLogger.info(`[AccountMutations - createOrEditAccount] username : ${username}`);
AppLogger.info(`[AccountMutations - createOrEditAccount] password : ${password}`);
AppLogger.info(`[AccountMutations - createOrEditAccount] email : ${email}`);
AppLogger.info(`[AccountMutations - createOrEditAccount] role : ${role}`);
AppLogger.info(
`[AccountMutations - createOrEditAccount] applications : ${applications?.join(',')}`,
);
AppLogger.info(`[AccountMutations - createOrEditAccount] applications : ${applications}`);

if (_id) {
const editedAccount = await AccountProvider.editAccount({
_id,
username,
password: await hashPassword(password),
email,
role,
applications,
});
let editedAccount = null;
if (!password) {
editedAccount = await AccountProvider.editAccount({
account: {
_id,
username,
email,
role,
applications,
},
currentUser: context.user,
});
} else {
editedAccount = await AccountProvider.editAccount({
account: {
_id,
username,
password: await hashPassword(password),
email,
role,
applications,
},
currentUser: context.user,
});
}

if (!editedAccount || !editedAccount._id) {
return null;
throw new Error('Invalid account');
}

AppLogger.info(
Expand All @@ -49,6 +71,14 @@ const createOrEditAccount = async (_: unknown, params: { accountInput: AccountIn
};
}

if (!password) {
throw new Error('Password is required');
}

const user = await AccountProvider.getAccountDetailsByParams({ email });
if (user) {
throw new Error('User already exists with this email');
}
const createdAccount = await AccountProvider.createAccount({
username,
password: await hashPassword(password),
Expand All @@ -74,22 +104,78 @@ const createOrEditAccount = async (_: unknown, params: { accountInput: AccountIn
}
};

/**
* Update password
* @param _
* @param params
* @param context
**/
const updateAccountPassword = async (
_: unknown,
params: { input: AccountUpdatePasswordType },
context: { user: AccountType },
) => {
try {
const { _id, password } = params?.input || {};

AppLogger.info(`[AccountMutations - updatePassword] _id : ${_id}`);

const accountDetails = await AccountProvider.getAccountDetailsByParams({ _id });

if (!accountDetails) {
throw new Error('Invalid account');
}

const updatedAccount = await AccountProvider.updateAccountPassword({
_id,
password: await PasswordUtils.hashPassword(password),
currentUser: context.user,
});

if (!updatedAccount || !updatedAccount._id) {
throw new Error('Invalid account');
}

AppLogger.info(
`[AccountMutations - updatePassword] updatedAccount : ${updatedAccount._id}`,
);

return {
_id: updatedAccount._id,
};
} catch (error) {
AppLogger.error(`[AccountMutations - updatePassword] error : ${error}`);
return null;
}
};

/**
* Delete account
* @param _
* @param params
*/
const deleteAccount = async (_: unknown, params: { input: SearchQueryType }) => {
const deleteAccount = async (
_: unknown,
params: { input: SearchQueryType },
context: { user: AccountType },
) => {
try {
const whereClause = params?.input?.where;
if (!whereClause) {

if (!whereClause?.id) {
return null;
}

const accountId = whereClause._id;
const accountId = parseInt(whereClause.id, 10);
AppLogger.info(`[AccountMutations - deleteAccount] accountId : ${accountId}`);

await AccountProvider.deleteAccount({ _id: accountId });
const user = await AccountProvider.getAccountDetailsByParams({
_id: accountId,
});
if (!user) {
throw new Error('User does not exist');
}

await AccountProvider.deleteAccount({ userToDelete: user, currentUser: context.user });
AppLogger.info(`[AccountMutations - deleteAccount] deleted account : ${accountId}`);
return {
_id: accountId,
Expand All @@ -102,6 +188,7 @@ const deleteAccount = async (_: unknown, params: { input: SearchQueryType }) =>

const AccountMutations = {
createOrEditAccount,
updateAccountPassword,
deleteAccount,
};

Expand Down
10 changes: 4 additions & 6 deletions src/v6y-bff/src/resolvers/account/AccountQueries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,6 @@ const getAccountDetailsByParams = async (_: unknown, args: AccountType) => {
const accountDetails = await AccountProvider.getAccountDetailsByParams({
_id,
});

AppLogger.info(
`[AccountQueries - getAccountDetailsByParams] accountDetails : ${accountDetails?._id}`,
);

return accountDetails;
} catch (error) {
AppLogger.info(`[AccountQueries - getAccountDetailsByParams] error : ${error}`);
Expand Down Expand Up @@ -105,11 +100,14 @@ const loginAccount = async (_: unknown, params: { input: AccountLoginType }) =>

const token = generateAuthenticationToken(accountDetails);

AppLogger.info(`[AccountMutations - loginAccount] login success : ${accountDetails._id}`);
AppLogger.info(
`[AccountMutations - loginAccount] login success : ${accountDetails._id} - ${accountDetails.role}`,
);

return {
_id: accountDetails._id,
token,
role: accountDetails.role,
};
} catch (error) {
AppLogger.info(`[AccountMutations - loginAccount] error : ${error}`);
Expand Down
29 changes: 29 additions & 0 deletions src/v6y-bff/src/resolvers/application/ApplicationQueries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,34 @@ const getApplicationListByPageAndParams = async (_: unknown, args: SearchQueryTy
}
};

/**
* Get application list
* @param _
* @param args
*/
const getApplicationList = async (_: unknown, args: SearchQueryType) => {
try {
const { where, sort } = args || {};

AppLogger.info(`[ApplicationQueries - getApplicationListByPageAndParams] where : ${where}`);
AppLogger.info(`[ApplicationQueries - getApplicationListByPageAndParams] sort : ${sort}`);

const appList = await ApplicationProvider.getApplicationListByPageAndParams({
where,
sort,
});

AppLogger.info(
`[ApplicationQueries - getApplicationListByPageAndParams] appList : ${appList?.length}`,
);

return appList;
} catch (error) {
AppLogger.info(`[ApplicationQueries - getApplicationListByPageAndParams] error : ${error}`);
return [];
}
};

/**
* Get application stats by params
* @param _
Expand Down Expand Up @@ -251,6 +279,7 @@ const ApplicationQueries = {
getApplicationDetailsKeywordsByParams,
getApplicationTotalByParams,
getApplicationListByPageAndParams,
getApplicationList,
getApplicationStatsByParams,
};

Expand Down
4 changes: 4 additions & 0 deletions src/v6y-bff/src/types/VitalityTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import AccountLoginOutput from './account/AccountLoginOutput.ts';
import AccountMutationsType from './account/AccountMutationsType.ts';
import AccountQueriesType from './account/AccountQueriesType.ts';
import AccountType from './account/AccountType.ts';
import AccountUpdatePasswordInput from './account/AccountUpdatePasswordInput.ts';
import AccountUpdatePasswordOutput from './account/AccountUpdatePasswordOutput.ts';
import ApplicationCreateOrEditInput from './application/ApplicationCreateOrEditInput.ts';
import ApplicationDeleteInput from './application/ApplicationDeleteInput.ts';
import ApplicationDeleteOutput from './application/ApplicationDeleteOutput.ts';
Expand Down Expand Up @@ -134,6 +136,8 @@ const VitalityTypes = gql(`
${AccountCreateOrEditInput}
${AccountCreateOrEditOutput}
${AccountUpdatePasswordInput}
${AccountUpdatePasswordOutput}
${AccountDeleteInput}
${AccountDeleteOutput}
${AccountMutationsType}
Expand Down
2 changes: 1 addition & 1 deletion src/v6y-bff/src/types/account/AccountCreateOrEditInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const AccountCreateOrEditInput = `
username: String!
""" Account Password """
password: String!
password: String
""" Account Role """
role: String!
Expand Down
2 changes: 1 addition & 1 deletion src/v6y-bff/src/types/account/AccountDeleteInput.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const AccountDeleteInput = `
input AccountDeleteInputClause {
""" Account to delete id """
_id: Int!
id: String!
}
input AccountDeleteInput {
Expand Down
2 changes: 2 additions & 0 deletions src/v6y-bff/src/types/account/AccountLoginOutput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ const AccountLoginOutput = `
_id: Int!
""" Account token """
token: String!
""" Account role """
role: String!
}
`;

Expand Down
3 changes: 2 additions & 1 deletion src/v6y-bff/src/types/account/AccountMutationsType.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const AccountMutationsType = `
type Mutation {
createOrEditAccount(accountInput: AccountCreateOrEditInput!): AccountCreateOrEditOutput
createOrEditAccount(input: AccountCreateOrEditInput!): AccountCreateOrEditOutput
updateAccountPassword(input: AccountUpdatePasswordInput!): AccountUpdatePasswordOutput
deleteAccount(input: AccountDeleteInput!): AccountDeleteOutput
}
`;
Expand Down
11 changes: 11 additions & 0 deletions src/v6y-bff/src/types/account/AccountUpdatePasswordInput.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const AccountUpdatePasswordInput = `
input AccountUpdatePasswordInput {
""" Account Id """
_id: Int!
""" Account New Password """
password : String!
}
`;

export default AccountUpdatePasswordInput;
8 changes: 8 additions & 0 deletions src/v6y-bff/src/types/account/AccountUpdatePasswordOutput.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const AccountUpdatePasswordOutput = `
type AccountUpdatePasswordOutput {
""" Account id """
_id: Int!
}
`;

export default AccountUpdatePasswordOutput;
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const ApplicationQueriesType = `
type Query {
getApplicationList(where: JSON, sort: [String]): [ApplicationType]
getApplicationListByPageAndParams(start: Int, offset: Int, limit: Int, keywords: [String], searchText: String, where: JSON, sort: String): [ApplicationType]
getApplicationStatsByParams(keywords: [String]): [KeywordStatsType]
getApplicationTotalByParams(keywords: [String], searchText: String): Int
Expand Down
2 changes: 1 addition & 1 deletion src/v6y-commons/eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export default [
...tsEslint.configs.recommended,
{
files: ['src/**/*.js', 'src/**/*.mjs', 'src/**/*.tsx', 'src/**/*.ts'],
ignores: ['**/*.test.js', '*.d.ts'],
ignores: ['**/*test.js', '**/*test.ts', '*.d.ts'],
rules: {
'max-depth': ['error', 3],
'max-nested-callbacks': ['error', 3],
Expand Down
25 changes: 24 additions & 1 deletion src/v6y-commons/src/core/AuthenticationHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,13 @@ export const createJwtOptions = () => {
* Creates a verification function for JWT strategy.
* @returns {Function} A function that verifies JWT payload.
*/
const createJwtStrategyVerify = () => {
export const createJwtStrategyVerify = () => {
return async (jwtPayload: JwtPayload, done: VerifiedCallback) => {
try {
AppLogger.info(
`[AuthenticationHelper - createJwtStrategyVerify] JwtPayload: ${JwtPayload?._id}`,
);

// Ensure the token contains the `_id` field.
if (!jwtPayload._id) {
return done(Error('Token does not contain _id'), undefined);
Expand All @@ -46,13 +50,18 @@ const createJwtStrategyVerify = () => {
_id: jwtPayload._id,
});

AppLogger.info(
`[AuthenticationHelper - createJwtStrategyVerify] _id : ${accountDetails?._id}`,
);

if (!accountDetails) {
return done(Error('User not Found'), undefined);
}

AppLogger.info(
`[AuthenticationHelper - createJwtStrategyVerify] User Found : ${accountDetails._id}`,
);

return done(null, accountDetails);
} catch (error) {
AppLogger.error(`[AuthenticationHelper- createJwtStrategyVerify] : ${error}`);
Expand Down Expand Up @@ -104,6 +113,20 @@ export const validateCredentials = <T>(request: T): Promise<unknown> => {
*/
export const configureAuthMiddleware = <T>(): T => passport.initialize() as T;

/**
* Check if user role is ADMIN.
* @param {object} account
* @returns {boolean}
*/
export const isAdmin = (account: AccountType) => account?.role === 'ADMIN';

/**
* Check if user role is SUPERADMIN.
* @param {object} account
* @returns {boolean}
*/
export const isSuperAdmin = (account: AccountType) => account?.role === 'SUPERADMIN';

/**
* Configures the authentication strategy.
*/
Expand Down
Loading

0 comments on commit e0b4aaf

Please sign in to comment.