Skip to content

Commit

Permalink
Cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
pozylon committed Dec 13, 2024
1 parent e3c6189 commit 6a4849f
Show file tree
Hide file tree
Showing 19 changed files with 109 additions and 569 deletions.
449 changes: 0 additions & 449 deletions changes.diff

This file was deleted.

4 changes: 2 additions & 2 deletions packages/api/src/resolvers/mutations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ import prepareUserAvatarUpload from './users/prepareUserAvatarUpload.js';
import rejectOrder from './orders/rejectOrder.js';
import removePushSubscription from './users/removePushSubscription.js';
import addPushSubscription from './users/addPushSubscription.js';
import deleteUserProductReviews from './products/deleteUserProductReviews.js';
import removeUserProductReviews from './users/removeUserProductReviews.js';

export default {
logout: acl(actions.logout)(logout),
Expand Down Expand Up @@ -313,5 +313,5 @@ export default {
signPaymentProviderForCheckout: acl(actions.registerPaymentCredentials)(
signPaymentProviderForCheckout,
),
deleteUserProductReviews,
removeUserProductReviews,
};
11 changes: 7 additions & 4 deletions packages/api/src/resolvers/mutations/users/removeUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,19 @@ import { UserNotFoundError } from '../../../errors.js';
export default async function removeUser(
root: never,
params: { userId: string; removeUserReviews?: boolean },
unchainedApi: Context,
unchainedAPI: Context,
) {
const { modules, userId } = unchainedApi;
const { modules, userId } = unchainedAPI;
const { userId: paramUserId, removeUserReviews = false } = params;
const normalizedUserId = paramUserId || userId;

log(`mutation removeUser ${normalizedUserId}`, { userId });

if (!(await modules.users.userExists({ userId: normalizedUserId })))
throw new UserNotFoundError({ id: normalizedUserId });
throw new UserNotFoundError({ userId: normalizedUserId });

return modules.users.delete({ userId: normalizedUserId, removeUserReviews }, unchainedApi);
if (removeUserReviews) {
await modules.products.reviews.deleteMany({ authorId: userId });
}
return modules.users.delete({ userId: normalizedUserId }, unchainedAPI);
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
import { log } from '@unchainedshop/logger';
import { InvalidIdError, UserNotFoundError } from '../../../errors.js';
import { InvalidIdError } from '../../../errors.js';
import { Context } from '../../../context.js';

export default async function deleteUserProductReviews(
export default async function removeUserProductReviews(
root: never,
params: {
userId?: string;
},
{ modules, userId: currentUserId }: Context,
) {
const normalizedUserId = params?.userId || currentUserId;
log(`mutation deleteUserProductReviews ${normalizedUserId}`, {
log(`mutation removeUserProductReviews ${normalizedUserId}`, {
userId: currentUserId,
});
if (!normalizedUserId) throw new InvalidIdError({ userId: normalizedUserId });
if (!(await modules.users.userExists({ userId: normalizedUserId })))
throw new UserNotFoundError({ userId: normalizedUserId });

// Do not check for existance of user as the existance check would return false if the user is in status
// 'deleted' and we still want to remove the reviews in that case
await modules.products.reviews.deleteMany({ authorId: normalizedUserId });

return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export default async function updateUserProfile(
log(`mutation updateUserProfile ${normalizedUserId}`, { userId });

if (!(await modules.users.userExists({ userId: normalizedUserId })))
throw UserNotFoundError({ id: normalizedUserId });
throw UserNotFoundError({ userId: normalizedUserId });

return modules.users.updateProfile(normalizedUserId, profile);
}
1 change: 0 additions & 1 deletion packages/api/src/roles/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@ const actions: Record<string, string> = [
'confirmMediaUpload',
'viewStatistics',
'removeUser',
'deleteUserProductReviews',
].reduce((oldValue, actionValue) => {
const newValue = oldValue;
newValue[actionValue] = actionValue;
Expand Down
1 change: 0 additions & 1 deletion packages/api/src/roles/loggedIn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,6 @@ export const loggedIn = (role: any, actions: Record<string, string>) => {
role.allow(actions.viewUserTokens, isMyself);
role.allow(actions.updateUser, isMyself);
role.allow(actions.removeUser, isMyself);
role.allow(actions.deleteUserProductReviews, isMyself);
role.allow(actions.sendEmail, isOwnedEmailAddress);
role.allow(actions.viewOrder, isOwnedOrder);
role.allow(actions.updateOrder, isOwnedOrder);
Expand Down
6 changes: 5 additions & 1 deletion packages/api/src/schema/mutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,11 @@ export default [
"""
removeUser(userId: ID, removeUserReviews: Boolean): User!
"""
Remove product reviews of a user
"""
removeUserProductReviews(userId: ID!): Boolean!
"""
Enroll a new user, setting enroll to true will let the user choose his password (e-mail gets sent)
"""
Expand Down Expand Up @@ -867,7 +872,6 @@ export default [
Remove user W3C push subscription object
"""
removePushSubscription(p256dh: String!): User!
deleteUserProductReviews(userId: ID): Boolean
}
`,
];
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export interface EnrollmentMutations {
params: { status: EnrollmentStatus; info?: string },
unchainedAPI,
) => Promise<Enrollment>;
deleteOpenUserEnrollments: (userId: string) => Promise<number>;
deleteInactiveUserEnrollments: (userId: string) => Promise<number>;
}

export type EnrollmentsModule = EnrollmentQueries &
Expand Down Expand Up @@ -555,8 +555,11 @@ export const configureEnrollmentsModule = async ({
},

updateStatus,
deleteOpenUserEnrollments: async (userId: string) => {
const { deletedCount } = await Enrollments.deleteMany({ userId });
deleteInactiveUserEnrollments: async (userId: string) => {
const { deletedCount } = await Enrollments.deleteMany({
userId,
status: { $in: [null, EnrollmentStatus.INITIAL, EnrollmentStatus.TERMINATED] },
});
return deletedCount;
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export type OrderDeliveriesModule = {
) => Promise<OrderDelivery>;

updateCalculation: (orderDelivery: OrderDelivery, unchainedAPI) => Promise<OrderDelivery>;
deleteOrderDelivery: (orderId: string) => Promise<number>;
deleteOrderDeliveries: (orderId: string) => Promise<number>;
};

const ORDER_DELIVERY_EVENTS: string[] = ['ORDER_DELIVER', 'ORDER_UPDATE_DELIVERY'];
Expand Down Expand Up @@ -271,7 +271,7 @@ export const configureOrderDeliveriesModule = ({
},
);
},
deleteOrderDelivery: async (orderId: string) => {
deleteOrderDeliveries: async (orderId: string) => {
const { deletedCount } = await OrderDeliveries.deleteMany({ orderId });
return deletedCount;
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export type OrderPaymentsModule = {
) => Promise<OrderPayment>;

updateCalculation: (orderPayment: OrderPayment, unchainedAPI) => Promise<OrderPayment>;
deleteOrderPayment: (orderId: string) => Promise<number>;
deleteOrderPayments: (orderId: string) => Promise<number>;
};

const ORDER_PAYMENT_EVENTS: string[] = ['ORDER_UPDATE_PAYMENT', 'ORDER_SIGN_PAYMENT', 'ORDER_PAY'];
Expand Down Expand Up @@ -410,7 +410,7 @@ export const configureOrderPaymentsModule = ({
},
);
},
deleteOrderPayment: async (orderId: string) => {
deleteOrderPayments: async (orderId: string) => {
const { deletedCount } = await OrderPayments.deleteMany({ orderId });
return deletedCount;
},
Expand Down
2 changes: 0 additions & 2 deletions packages/core-products/src/mock/product.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@ export default {
authorId: 'PKve0k9fLCUzn2EUi',
tags: [],
created: new Date('2022-10-28T10:41:13.346Z'),
createdBy: 'PKve0k9fLCUzn2EUi',
slugs: ['test'],
updated: new Date('2022-12-04T13:50:24.245Z'),
updatedBy: 'PKve0k9fLCUzn2EUi',
commerce: {
pricing: [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ export const configureQuotationsModule = async ({
deleteRequestedUserQuotations: async (userId: string) => {
const { deletedCount } = await Quotations.deleteMany({
userId,
status: QuotationStatus.REQUESTED,
status: { $in: [QuotationStatus.REQUESTED, null] },
});
return deletedCount;
},
Expand Down
118 changes: 52 additions & 66 deletions packages/core-users/src/module/configureUsersModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,6 @@ import * as pbkdf2 from './pbkdf2.js';
import * as sha256 from './sha256.js';
import crypto from 'crypto';
import { UnchainedCore } from '@unchainedshop/core';
import { Context } from 'vm';

const maskUserPropertyValues = (user, deletedById: string): User => {
if (!user || typeof user !== 'object') {
throw new Error('Invalid user object');
}
return {
...user,
username: `deleted-${Date.now()}`,
deleted: new Date(),
deletedBy: deletedById,
emails: null,
roles: null,
profile: null,
lastBillingAddress: {},
services: {},
pushSubscriptions: [],
avatarId: null,
initialPassword: null,
lastContact: null,
};
};

export type UsersModule = {
// Submodules
Expand Down Expand Up @@ -95,7 +73,7 @@ export type UsersModule = {
_id: string,
{ profile, meta }: { profile?: UserProfile; meta?: any },
) => Promise<User>;
delete: (params: { userId: string; removeUserReviews?: boolean }, context: Context) => Promise<User>;
delete: (params: { userId: string }, context: UnchainedCore) => Promise<User>;
updateRoles: (_id: string, roles: Array<string>) => Promise<User>;
updateTags: (_id: string, tags: Array<string>) => Promise<User>;
updateUser: (
Expand Down Expand Up @@ -133,7 +111,6 @@ const USER_EVENTS = [
'USER_UPDATE_BILLING_ADDRESS',
'USER_UPDATE_LAST_CONTACT',
'USER_REMOVE',
'USER_PURGE',
];
export const removeConfidentialServiceHashes = (rawUser: User): User => {
const user = rawUser;
Expand Down Expand Up @@ -164,33 +141,19 @@ export const configureUsersModule = async ({

const webAuthn = await configureUsersWebAuthnModule({ db, options });

const findUserById = async (userId: string): Promise<User> => {
if (!userId) return null;
return Users.findOne(generateDbFilterById(userId), {});
};
const updateUser = async (
selector: mongodb.Filter<User>,
modifier: mongodb.UpdateFilter<User>,
updateOptions?: mongodb.FindOneAndUpdateOptions,
): Promise<User> => {
const user = await Users.findOneAndUpdate(selector, modifier, {
...updateOptions,
returnDocument: 'after',
});
await emit('USER_UPDATE', {
user: removeConfidentialServiceHashes(user),
});
return user;
};

return {
// Queries
webAuthn,
async count(query: UserQuery): Promise<number> {
const userCount = await Users.countDocuments(buildFindSelector(query));
return userCount;
},
findUserById,

findUserById: async (userId: string): Promise<User> => {
if (!userId) return null;
return Users.findOne(generateDbFilterById(userId), {});
},

async findUserByUsername(username: string): Promise<User> {
if (!username) return null;
return Users.findOne({ username }, {});
Expand Down Expand Up @@ -317,9 +280,7 @@ export const configureUsersModule = async ({
},

async userExists({ userId }: { userId: string }): Promise<boolean> {
const selector = generateDbFilterById<User>(userId);
selector.deleted = null; // skip deleted users when checked for existance!
const userCount = await Users.countDocuments(selector, { limit: 1 });
const userCount = await Users.countDocuments({ _id: userId, deleted: null }, { limit: 1 });
return userCount === 1;
},

Expand Down Expand Up @@ -624,40 +585,50 @@ export const configureUsersModule = async ({
return user;
},

delete: async (
params: { userId: string; removeUserReviews?: boolean },
context: Context,
): Promise<User> => {
delete: async ({ userId }: { userId: string }, context: UnchainedCore): Promise<User> => {
const { services, modules } = context as UnchainedCore;
const { userId, removeUserReviews = false } = params;
const userFilter = generateDbFilterById(userId);

const existingUser = await Users.findOne(userFilter, {
projection: { emails: true, username: true },
});
if (!existingUser) return null;
const maskedUserData = maskUserPropertyValues(existingUser, context?.userId);
await updateUser({ _id: userId }, { $set: { ...maskedUserData, deleted: new Date() } }, {});
const user = await Users.findOneAndUpdate(
{ _id: userId },
{
$set: {
username: `deleted-${Date.now()}`,
deleted: new Date(),
emails: [],
roles: [],
profile: null,
lastBillingAddress: null,
services: {},
pushSubscriptions: [],
avatarId: null,
initialPassword: false,
lastContact: null,
lastLogin: null,
},
},
{ returnDocument: 'after' },
);

if (!user) return null;

await modules.bookmarks.deleteByUserId(userId);
await services.orders.deleteUserCart(userId, context as UnchainedCore);
await services.orders.deleteUserCarts(userId, context as UnchainedCore);
await modules.quotations.deleteRequestedUserQuotations(userId);
await modules.enrollments.deleteOpenUserEnrollments(userId);
if (removeUserReviews) await modules.products.reviews.deleteMany({ authorId: userId });
await modules.enrollments.deleteInactiveUserEnrollments(userId);

const ordersCount = await modules.orders.count({ userId, includeCarts: true });
const quotationsCount = await modules.quotations.count({ userId });
const reviewsCount = await modules.products.reviews.count({ authorId: userId });
const enrollmentsCount = await modules.enrollments.count({ userId });
const tokens = await modules.warehousing.findTokensForUser(existingUser);
const tokens = await modules.warehousing.findTokensForUser(user);
if (!ordersCount && !reviewsCount && !enrollmentsCount && !quotationsCount && !tokens?.length) {
await Users.deleteOne({ _id: userId });
}

await emit('USER_REMOVE', {
user: removeConfidentialServiceHashes(existingUser),
user,
});
return existingUser;
return user;
},

updateProfile: async (
Expand Down Expand Up @@ -794,7 +765,22 @@ export const configureUsersModule = async ({
});
return user;
},
updateUser,

updateUser: async (
selector: mongodb.Filter<User>,
modifier: mongodb.UpdateFilter<User>,
updateOptions?: mongodb.FindOneAndUpdateOptions,
): Promise<User> => {
const user = await Users.findOneAndUpdate(selector, modifier, {
...updateOptions,
returnDocument: 'after',
});
await emit('USER_UPDATE', {
user: removeConfidentialServiceHashes(user),
});
return user;
},

addPushSubscription: async (
userId: string,
subscription: any,
Expand Down
1 change: 0 additions & 1 deletion packages/core-users/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ export type User = {
pushSubscriptions: Array<PushSubscriptionObject>;
username?: string;
meta?: any;
deletedBy?: string;
} & TimestampFields;

export type UserQuery = mongodb.Filter<User> & {
Expand Down
Loading

0 comments on commit 6a4849f

Please sign in to comment.