Skip to content

Commit

Permalink
Merge pull request #603 from unchainedshop/user-deletion-updated
Browse files Browse the repository at this point in the history
Right to be forgotten
  • Loading branch information
pozylon authored Dec 13, 2024
2 parents 445f073 + 6a4849f commit eddedbf
Show file tree
Hide file tree
Showing 23 changed files with 154 additions and 48 deletions.
2 changes: 2 additions & 0 deletions packages/api/src/resolvers/mutations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +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 removeUserProductReviews from './users/removeUserProductReviews.js';

export default {
logout: acl(actions.logout)(logout),
Expand Down Expand Up @@ -312,4 +313,5 @@ export default {
signPaymentProviderForCheckout: acl(actions.registerPaymentCredentials)(
signPaymentProviderForCheckout,
),
removeUserProductReviews,
};
14 changes: 9 additions & 5 deletions packages/api/src/resolvers/mutations/users/removeUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,20 @@ import { UserNotFoundError } from '../../../errors.js';

export default async function removeUser(
root: never,
params: { userId: string },
{ modules, userId }: Context,
params: { userId: string; removeUserReviews?: boolean },
unchainedAPI: Context,
) {
const { userId: paramUserId } = params;
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 UserNotFoundError({ id: normalizedUserId });
throw new UserNotFoundError({ userId: normalizedUserId });

return modules.users.delete(normalizedUserId);
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
@@ -0,0 +1,23 @@
import { log } from '@unchainedshop/logger';
import { InvalidIdError } from '../../../errors.js';
import { Context } from '../../../context.js';

export default async function removeUserProductReviews(
root: never,
params: {
userId?: string;
},
{ modules, userId: currentUserId }: Context,
) {
const normalizedUserId = params?.userId || currentUserId;
log(`mutation removeUserProductReviews ${normalizedUserId}`, {
userId: currentUserId,
});
if (!normalizedUserId) throw new InvalidIdError({ 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;
}
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: 1 addition & 0 deletions packages/api/src/roles/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ const actions: Record<string, string> = [
'heartbeat',
'confirmMediaUpload',
'viewStatistics',
'removeUser',
].reduce((oldValue, actionValue) => {
const newValue = oldValue;
newValue[actionValue] = actionValue;
Expand Down
1 change: 1 addition & 0 deletions packages/api/src/roles/loggedIn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ export const loggedIn = (role: any, actions: Record<string, string>) => {
role.allow(actions.viewUserProductReviews, isMyself);
role.allow(actions.viewUserTokens, isMyself);
role.allow(actions.updateUser, isMyself);
role.allow(actions.removeUser, isMyself);
role.allow(actions.sendEmail, isOwnedEmailAddress);
role.allow(actions.viewOrder, isOwnedOrder);
role.allow(actions.updateOrder, isOwnedOrder);
Expand Down
7 changes: 6 additions & 1 deletion packages/api/src/schema/mutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,12 @@ export default [
"""
Remove any user or logged in user if userId is not provided
"""
removeUser(userId: ID): User!
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
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export interface EnrollmentMutations {
params: { status: EnrollmentStatus; info?: string },
unchainedAPI,
) => Promise<Enrollment>;
deleteInactiveUserEnrollments: (userId: string) => Promise<number>;
}

export type EnrollmentsModule = EnrollmentQueries &
Expand Down Expand Up @@ -505,7 +506,7 @@ export const configureEnrollmentsModule = async ({
},
},
);
await emit('ORDER_REMOVE', { enrollmentId });
await emit('ENROLLMENT_REMOVE', { enrollmentId });
return deletedCount;
},

Expand Down Expand Up @@ -554,5 +555,12 @@ export const configureEnrollmentsModule = async ({
},

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

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

const ORDER_DELIVERY_EVENTS: string[] = ['ORDER_DELIVER', 'ORDER_UPDATE_DELIVERY'];
Expand Down Expand Up @@ -270,5 +271,9 @@ export const configureOrderDeliveriesModule = ({
},
);
},
deleteOrderDeliveries: async (orderId: string) => {
const { deletedCount } = await OrderDeliveries.deleteMany({ orderId });
return deletedCount;
},
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export type OrderDiscountsModule = {
create: (doc: OrderDiscount) => Promise<OrderDiscount>;
update: (orderDiscountId: string, doc: OrderDiscount) => Promise<OrderDiscount>;
delete: (orderDiscountId: string, unchainedAPI) => Promise<OrderDiscount>;
deleteOrderDiscounts: (orderId: string) => Promise<number>;
};

const ORDER_DISCOUNT_EVENTS: string[] = [
Expand Down Expand Up @@ -251,5 +252,9 @@ export const configureOrderDiscountsModule = ({
await emit('ORDER_UPDATE_DISCOUNT', { discount });
return discount;
},
deleteOrderDiscounts: async (orderId: string) => {
const { deletedCount } = await OrderDiscounts.deleteMany({ orderId });
return deletedCount;
},
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export type OrderPaymentsModule = {
) => Promise<OrderPayment>;

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

const ORDER_PAYMENT_EVENTS: string[] = ['ORDER_UPDATE_PAYMENT', 'ORDER_SIGN_PAYMENT', 'ORDER_PAY'];
Expand Down Expand Up @@ -409,5 +410,9 @@ export const configureOrderPaymentsModule = ({
},
);
},
deleteOrderPayments: async (orderId: string) => {
const { deletedCount } = await OrderPayments.deleteMany({ orderId });
return deletedCount;
},
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export type OrderPositionsModule = {
params: { order: Order; product: Product },
unchainedAPI,
) => Promise<OrderPosition>;
deleteOrderPositions: (orderId: string) => Promise<number>;
};

const ORDER_POSITION_EVENTS: string[] = [
Expand Down Expand Up @@ -349,5 +350,9 @@ export const configureOrderPositionsModule = ({

return upsertedOrderPosition;
},
deleteOrderPositions: async (orderId: string) => {
const { deletedCount } = await OrderPositions.deleteMany({ orderId });
return deletedCount;
},
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ export const configureOrdersModuleQueries = ({ Orders }: { Orders: mongodb.Colle
const orderCount = await Orders.countDocuments(buildFindSelector(query));
return orderCount;
},

findOrder: async (
{
orderId,
Expand Down
1 change: 1 addition & 0 deletions packages/core-orders/src/module/configureOrdersModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export type OrdersModule = OrderQueries &
OrderTransformations &
OrderProcessing &
OrderMutations & {
// Sub entities
deliveries: OrderDeliveriesModule;
discounts: OrderDiscountsModule;
positions: OrderPositionsModule;
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 @@ -220,7 +220,6 @@ export const configureProductReviewsModule = async ({

return productReview;
},

votes: {
userIdsThatVoted,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export interface QuotationQueries {
) => Promise<Array<Quotation>>;
count: (query: QuotationQuery) => Promise<number>;
openQuotationWithProduct: (param: { productId: string }) => Promise<Quotation | null>;
deleteRequestedUserQuotations: (userId: string) => Promise<number>;
}

// Transformations
Expand Down Expand Up @@ -398,7 +399,13 @@ export const configureQuotationsModule = async ({

return quotation;
},

deleteRequestedUserQuotations: async (userId: string) => {
const { deletedCount } = await Quotations.deleteMany({
userId,
status: { $in: [QuotationStatus.REQUESTED, null] },
});
return deletedCount;
},
updateContext: updateQuotationFields(['context']),
updateProposal: updateQuotationFields(['price', 'expires', 'meta']),

Expand Down
2 changes: 2 additions & 0 deletions packages/core-quotations/src/quotations-index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ export { QuotationAdapter } from './director/QuotationAdapter.js';
export { QuotationDirector } from './director/QuotationDirector.js';

export { QuotationError } from './director/QuotationError.js';

export { configureQuotationsModule } from './module/configureQuotationsModule.js';
Loading

0 comments on commit eddedbf

Please sign in to comment.