@unchainedshop/api 2.3.5 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/lib/api-index.js.map +1 -1
  2. package/lib/errors.d.ts +1 -0
  3. package/lib/errors.js +1 -0
  4. package/lib/errors.js.map +1 -1
  5. package/lib/express/createBulkImportMiddleware.js +1 -1
  6. package/lib/express/createBulkImportMiddleware.js.map +1 -1
  7. package/lib/express/createERCMetadataMiddleware.d.ts +1 -1
  8. package/lib/express/createERCMetadataMiddleware.js +1 -1
  9. package/lib/express/createERCMetadataMiddleware.js.map +1 -1
  10. package/lib/express/createSingleSignOnMiddleware.d.ts +1 -1
  11. package/lib/express/createSingleSignOnMiddleware.js +0 -1
  12. package/lib/express/createSingleSignOnMiddleware.js.map +1 -1
  13. package/lib/loaders/index.d.ts +1 -1
  14. package/lib/loaders/index.js.map +1 -1
  15. package/lib/locale-context.d.ts +1 -1
  16. package/lib/resolvers/mutations/accounts/impersonate.js +3 -3
  17. package/lib/resolvers/mutations/accounts/impersonate.js.map +1 -1
  18. package/lib/resolvers/mutations/accounts/stopImpersonation.d.ts +6 -0
  19. package/lib/resolvers/mutations/accounts/stopImpersonation.js +21 -0
  20. package/lib/resolvers/mutations/accounts/stopImpersonation.js.map +1 -0
  21. package/lib/resolvers/mutations/index.d.ts +16 -37
  22. package/lib/resolvers/mutations/index.js +17 -15
  23. package/lib/resolvers/mutations/index.js.map +1 -1
  24. package/lib/resolvers/mutations/payment/removePaymentCredentials.js.map +1 -1
  25. package/lib/resolvers/queries/index.d.ts +2 -0
  26. package/lib/resolvers/queries/index.js +2 -0
  27. package/lib/resolvers/queries/index.js.map +1 -1
  28. package/lib/resolvers/queries/users/impersonator.d.ts +2 -0
  29. package/lib/resolvers/queries/users/impersonator.js +12 -0
  30. package/lib/resolvers/queries/users/impersonator.js.map +1 -0
  31. package/lib/resolvers/type/delivery-provider-types.js.map +1 -1
  32. package/lib/resolvers/type/dispatch-types.js.map +1 -1
  33. package/lib/resolvers/type/order/order-delivery-discount-types.js.map +1 -1
  34. package/lib/resolvers/type/order/order-item-discount-types.js.map +1 -1
  35. package/lib/resolvers/type/order/order-item-types.js.map +1 -1
  36. package/lib/resolvers/type/order/order-payment-discount-types.js.map +1 -1
  37. package/lib/resolvers/type/order/order-types.js.map +1 -1
  38. package/lib/resolvers/type/payment/payment-provider-types.js.map +1 -1
  39. package/lib/resolvers/type/product/product-discount.js.map +1 -1
  40. package/lib/resolvers/type/product/product-types.js +3 -0
  41. package/lib/resolvers/type/product/product-types.js.map +1 -1
  42. package/lib/resolvers/type/stock-types.js.map +1 -1
  43. package/lib/resolvers/type/user-types.d.ts +7 -0
  44. package/lib/resolvers/type/user-types.js +16 -1
  45. package/lib/resolvers/type/user-types.js.map +1 -1
  46. package/lib/roles/all.js +16 -0
  47. package/lib/roles/all.js.map +1 -1
  48. package/lib/roles/index.js +16 -0
  49. package/lib/roles/index.js.map +1 -1
  50. package/lib/roles/loggedIn.js +3 -0
  51. package/lib/roles/loggedIn.js.map +1 -1
  52. package/lib/schema/mutation.js +5 -0
  53. package/lib/schema/mutation.js.map +1 -1
  54. package/lib/schema/query.js +4 -0
  55. package/lib/schema/query.js.map +1 -1
  56. package/lib/schema/types/product/bundle-product.js +1 -0
  57. package/lib/schema/types/product/bundle-product.js.map +1 -1
  58. package/lib/schema/types/product/configurable-product.js +1 -0
  59. package/lib/schema/types/product/configurable-product.js.map +1 -1
  60. package/lib/schema/types/product/plan-product.js +1 -0
  61. package/lib/schema/types/product/plan-product.js.map +1 -1
  62. package/lib/schema/types/product/product.js +1 -0
  63. package/lib/schema/types/product/product.js.map +1 -1
  64. package/lib/schema/types/product/simple-product.js +1 -0
  65. package/lib/schema/types/product/simple-product.js.map +1 -1
  66. package/lib/schema/types/product/tokenized-product.js +1 -0
  67. package/lib/schema/types/product/tokenized-product.js.map +1 -1
  68. package/lib/schema/types/user.js +2 -0
  69. package/lib/schema/types/user.js.map +1 -1
  70. package/lib/user-context.d.ts +1 -1
  71. package/package.json +13 -13
  72. package/src/api-index.ts +2 -2
  73. package/src/errors.ts +5 -0
  74. package/src/express/createBulkImportMiddleware.ts +1 -1
  75. package/src/express/createERCMetadataMiddleware.ts +2 -2
  76. package/src/express/createSingleSignOnMiddleware.ts +1 -1
  77. package/src/express/index.ts +1 -1
  78. package/src/loaders/index.ts +1 -1
  79. package/src/locale-context.ts +1 -1
  80. package/src/resolvers/mutations/accounts/impersonate.ts +3 -3
  81. package/src/resolvers/mutations/accounts/stopImpersonation.ts +31 -0
  82. package/src/resolvers/mutations/index.ts +21 -15
  83. package/src/resolvers/mutations/payment/removePaymentCredentials.ts +2 -3
  84. package/src/resolvers/queries/index.ts +2 -0
  85. package/src/resolvers/queries/users/impersonator.ts +19 -0
  86. package/src/resolvers/type/delivery-provider-types.ts +1 -1
  87. package/src/resolvers/type/dispatch-types.ts +1 -1
  88. package/src/resolvers/type/order/order-delivery-discount-types.ts +1 -1
  89. package/src/resolvers/type/order/order-item-discount-types.ts +1 -1
  90. package/src/resolvers/type/order/order-item-types.ts +1 -1
  91. package/src/resolvers/type/order/order-payment-discount-types.ts +1 -1
  92. package/src/resolvers/type/order/order-types.ts +1 -1
  93. package/src/resolvers/type/payment/payment-provider-types.ts +1 -1
  94. package/src/resolvers/type/product/product-discount.ts +1 -1
  95. package/src/resolvers/type/product/product-types.ts +3 -0
  96. package/src/resolvers/type/stock-types.ts +1 -1
  97. package/src/resolvers/type/user-types.ts +26 -0
  98. package/src/roles/all.ts +16 -0
  99. package/src/roles/index.ts +17 -0
  100. package/src/roles/loggedIn.ts +3 -0
  101. package/src/schema/mutation.ts +5 -0
  102. package/src/schema/query.ts +4 -0
  103. package/src/schema/types/product/bundle-product.ts +1 -0
  104. package/src/schema/types/product/configurable-product.ts +1 -0
  105. package/src/schema/types/product/plan-product.ts +1 -0
  106. package/src/schema/types/product/product.ts +1 -0
  107. package/src/schema/types/product/simple-product.ts +1 -0
  108. package/src/schema/types/product/tokenized-product.ts +1 -0
  109. package/src/schema/types/user.ts +2 -0
  110. package/src/user-context.ts +1 -1
@@ -1,9 +1,9 @@
1
+ import { IncomingMessage } from 'http';
2
+ import path from 'path';
1
3
  import { createLogger } from '@unchainedshop/logger';
2
4
  import { UnchainedContextResolver } from '@unchainedshop/types/api.js';
3
5
  import { systemLocale } from '@unchainedshop/utils';
4
- import { IncomingMessage } from 'http';
5
6
  import localePkg from 'locale';
6
- import path from 'path';
7
7
 
8
8
  const { Locale } = localePkg;
9
9
 
@@ -1,8 +1,8 @@
1
1
  /// <reference lib="dom" />
2
+ import { IncomingMessage } from 'http';
2
3
  import { createLogger } from '@unchainedshop/logger';
3
4
  import { UnchainedContextResolver } from '@unchainedshop/types/api.js';
4
5
  import { UnchainedCore } from '@unchainedshop/types/core.js';
5
- import { IncomingMessage } from 'http';
6
6
  import cookie from 'cookie';
7
7
 
8
8
  const { ROOT_URL, NODE_ENV, UNCHAINED_CLOUD_ENDPOINT } = process.env;
@@ -1,5 +1,5 @@
1
- import { UnchainedCore } from '@unchainedshop/types/core.js';
2
1
  import { IncomingMessage, OutgoingMessage } from 'http';
2
+ import { UnchainedCore } from '@unchainedshop/types/core.js';
3
3
  import { ApolloServer } from '@apollo/server';
4
4
  import type e from 'express';
5
5
  import { getCurrentContextResolver } from '../context.js';
@@ -1,6 +1,6 @@
1
+ import { IncomingMessage, OutgoingMessage } from 'http';
1
2
  import { UnchainedLoaders } from '@unchainedshop/types/api.js';
2
3
  import DataLoader from 'dataloader';
3
- import { IncomingMessage, OutgoingMessage } from 'http';
4
4
  import { systemLocale } from '@unchainedshop/utils';
5
5
  import localePkg from 'locale';
6
6
  import { Assortment, AssortmentText } from '@unchainedshop/types/assortments.js';
@@ -1,5 +1,5 @@
1
- import { UnchainedLocaleContext } from '@unchainedshop/types/api.js';
2
1
  import { IncomingMessage, OutgoingMessage } from 'http';
2
+ import { UnchainedLocaleContext } from '@unchainedshop/types/api.js';
3
3
  import localePkg from 'locale';
4
4
  import 'abort-controller/polyfill.js';
5
5
  import { LRUCache } from 'lru-cache';
@@ -1,9 +1,9 @@
1
1
  import { log } from '@unchainedshop/logger';
2
2
  import { Context } from '@unchainedshop/types/api.js';
3
- import { UserNotFoundError, NoPermissionError } from '../../../errors.js';
3
+ import { ImpersonatingAdminUserError, UserNotFoundError } from '../../../errors.js';
4
4
 
5
5
  const impersonate = async (root, { userId }, context: Context) => {
6
- log(`mutation impersonate ${userId}`);
6
+ log(`mutation impersonate ${userId}`, { userId: context.userId });
7
7
 
8
8
  const userToImpersonate = await context.modules.users.findUserById(userId);
9
9
 
@@ -12,7 +12,7 @@ const impersonate = async (root, { userId }, context: Context) => {
12
12
  }
13
13
 
14
14
  if ((userToImpersonate.roles || []).includes('admin')) {
15
- throw new NoPermissionError("Cannot impersonate users with role 'admin'");
15
+ throw new ImpersonatingAdminUserError({ impersonatedUserId: userId, userId: context.userId });
16
16
  }
17
17
 
18
18
  return context.modules.accounts.createImpersonationToken(userToImpersonate._id, context);
@@ -0,0 +1,31 @@
1
+ import { UserNotFoundError } from '@unchainedshop/api/errors.js';
2
+ import { log } from '@unchainedshop/logger';
3
+ import { Context, Root } from '@unchainedshop/types/api.js';
4
+
5
+ export default async function stopImpersonation(root: Root, _, context: Context) {
6
+ const { userId, modules, loginToken } = context;
7
+
8
+ log(`mutation stopImpersonation for ${userId}`);
9
+
10
+ const impersonatedUser = await modules.users.findUserById(userId);
11
+
12
+ if (!impersonatedUser) throw new UserNotFoundError({ userId });
13
+ const impersonatedUserToken = impersonatedUser?.services?.resume?.loginTokens.find(
14
+ ({ hashedToken, impersonatorId }) =>
15
+ hashedToken === modules.accounts.createHashLoginToken(loginToken) && impersonatorId,
16
+ );
17
+
18
+ if (!impersonatedUserToken) throw new Error('Current session is not being impersonated');
19
+
20
+ await modules.accounts.logout({ loginToken }, context);
21
+
22
+ const accountsServer = modules.accounts.getAccountsServer();
23
+
24
+ const { token } = await accountsServer.loginWithUser(impersonatedUserToken.impersonatorId);
25
+
26
+ return {
27
+ id: impersonatedUserToken.impersonatorId,
28
+ token: token.token,
29
+ tokenExpires: token.when,
30
+ };
31
+ }
@@ -3,6 +3,7 @@ import { checkResolver as acl } from '../../acl.js';
3
3
  import loginWithPassword from './accounts/loginWithPassword.js';
4
4
  import loginWithWebAuthn from './accounts/loginWithWebAuthn.js';
5
5
  import impersonate from './accounts/impersonate.js';
6
+ import stopImpersonation from './accounts/stopImpersonation.js';
6
7
  import loginAsGuest from './accounts/loginAsGuest.js';
7
8
  import logout from './accounts/logout.js';
8
9
  import logoutAllSessions from './accounts/logoutAllSessions.js';
@@ -162,11 +163,15 @@ import linkOAuthAccount from './accounts/linkOAuthAccount.js';
162
163
  import unlinkOAuthAccount from './accounts/unlinkOAuthAccount.js';
163
164
 
164
165
  export default {
165
- logout,
166
- logoutAllSessions,
167
- loginAsGuest,
168
- createWebAuthnCredentialCreationOptions,
169
- createWebAuthnCredentialRequestOptions,
166
+ logout: acl(actions.logout)(logout),
167
+ logoutAllSessions: acl(actions.logoutAllSessions)(logoutAllSessions),
168
+ loginAsGuest: acl(actions.loginAsGuest)(loginAsGuest),
169
+ createWebAuthnCredentialCreationOptions: acl(actions.useWebAuthn)(
170
+ createWebAuthnCredentialCreationOptions,
171
+ ),
172
+ createWebAuthnCredentialRequestOptions: acl(actions.useWebAuthn)(
173
+ createWebAuthnCredentialRequestOptions,
174
+ ),
170
175
  addPushSubscription: acl(actions.updateUser)(addPushSubscription),
171
176
  removePushSubscription: acl(actions.updateUser)(removePushSubscription),
172
177
  addWebAuthnCredentials: acl(actions.updateUser)(addWebAuthnCredentials),
@@ -176,22 +181,23 @@ export default {
176
181
  verifyWeb3Address: acl(actions.updateUser)(verifyWeb3Address),
177
182
  linkOAuthAccount: acl(actions.updateUser)(linkOAuthAccount),
178
183
  unlinkOAuthAccount: acl(actions.updateUser)(unlinkOAuthAccount),
179
- verifyEmail,
180
- loginWithPassword,
181
- loginWithWebAuthn,
182
- loginWithOAuth,
184
+ verifyEmail: acl(actions.verifyEmail)(verifyEmail),
185
+ loginWithPassword: acl(actions.loginWithPassword)(loginWithPassword),
186
+ loginWithWebAuthn: acl(actions.loginWithWebAuthn)(loginWithWebAuthn),
187
+ loginWithOAuth: acl(actions.loginWithOAuth)(loginWithOAuth),
183
188
  impersonate: acl(actions.impersonate)(impersonate),
189
+ stopImpersonation: acl(actions.stopImpersonation)(stopImpersonation),
184
190
  buildSecretTOTPAuthURL: acl(actions.authTwoFactor)(buildSecretTOTPAuthURL),
185
191
  enableTOTP: acl(actions.authTwoFactor)(enableTOTP),
186
192
  disableTOTP: acl(actions.manageTwoFactor)(disableTOTP),
187
- pageView,
188
- createUser,
189
- forgotPassword,
190
- resetPassword,
193
+ pageView: acl(actions.pageView)(pageView),
194
+ createUser: acl(actions.createUser)(createUser),
195
+ forgotPassword: acl(actions.forgotPassword)(forgotPassword),
196
+ resetPassword: acl(actions.resetPassword)(resetPassword),
191
197
  sendVerificationEmail: acl(actions.sendEmail)(sendVerificationEmail),
192
198
  sendEnrollmentEmail: acl(actions.sendEmail)(sendEnrollmentEmail),
193
- changePassword,
194
- heartbeat,
199
+ changePassword: acl(actions.changePassword)(changePassword),
200
+ heartbeat: acl(actions.heartbeat)(heartbeat),
195
201
  addEmail: acl(actions.updateUser)(addEmail),
196
202
  removeEmail: acl(actions.updateUser)(removeEmail),
197
203
  updateUserAvatar: acl(actions.updateUser)(updateUserAvatar),
@@ -10,9 +10,8 @@ export default async (
10
10
  log(`mutation removePaymentCredentials ${paymentCredentialsId}`, { userId });
11
11
 
12
12
  if (!paymentCredentialsId) throw new InvalidIdError({ paymentCredentialsId });
13
- const removedCredentials = await modules.payment.paymentCredentials.removeCredentials(
14
- paymentCredentialsId,
15
- );
13
+ const removedCredentials =
14
+ await modules.payment.paymentCredentials.removeCredentials(paymentCredentialsId);
16
15
  if (!removedCredentials) throw new PaymentCredentialsNotFoundError({ paymentCredentialsId });
17
16
 
18
17
  return removedCredentials;
@@ -65,9 +65,11 @@ import token from './warehousing/token.js';
65
65
  import work from './worker/work.js';
66
66
  import workQueue from './worker/workQueue.js';
67
67
  import workQueueCount from './worker/workQueueCount.js';
68
+ import impersonator from './users/impersonator.js';
68
69
 
69
70
  export default {
70
71
  me,
72
+ impersonator,
71
73
  user: acl(actions.viewUser)(user),
72
74
  users: acl(actions.viewUsers)(users),
73
75
  usersCount: acl(actions.viewUsers)(usersCount),
@@ -0,0 +1,19 @@
1
+ import { log } from '@unchainedshop/logger';
2
+ import { Context, Root } from '@unchainedshop/types/api.js';
3
+
4
+ export default async function impersonator(
5
+ root: Root,
6
+ params: any,
7
+ { userId, user, remoteAddress, modules, loginToken }: Context,
8
+ ) {
9
+ log(`query impersonator ${remoteAddress}`, { userId });
10
+ if (!user?.services || !user?.services?.resume || !user?.services?.resume?.loginTokens) return null;
11
+
12
+ const { loginTokens } = user.services.resume;
13
+ const impersonatedSession = loginTokens.find(
14
+ ({ hashedToken, impersonatorId }) =>
15
+ hashedToken === modules.accounts.createHashLoginToken(loginToken) && impersonatorId,
16
+ );
17
+ if (!impersonatedSession) return null;
18
+ return modules.users.findUserById(impersonatedSession.impersonatorId);
19
+ }
@@ -1,9 +1,9 @@
1
+ import crypto from 'crypto';
1
2
  import { Context } from '@unchainedshop/types/api.js';
2
3
  import {
3
4
  DeliveryError,
4
5
  DeliveryProvider as DeliveryProviderType,
5
6
  } from '@unchainedshop/types/delivery.js';
6
- import crypto from 'crypto';
7
7
  import { DeliveryPricingDirector } from '@unchainedshop/core-delivery';
8
8
 
9
9
  export type HelperType<P, T> = (provider: DeliveryProviderType, params: P, context: Context) => T;
@@ -1,7 +1,7 @@
1
+ import crypto from 'crypto';
1
2
  import { DeliveryProvider } from '@unchainedshop/types/delivery.js';
2
3
  import { Product } from '@unchainedshop/types/products.js';
3
4
  import { WarehousingProvider } from '@unchainedshop/types/warehousing.js';
4
- import crypto from 'crypto';
5
5
 
6
6
  export const Dispatch = {
7
7
  _id: (params: {
@@ -1,8 +1,8 @@
1
+ import crypto from 'crypto';
1
2
  import { Context } from '@unchainedshop/types/api.js';
2
3
  import { OrderDeliveryDiscount as OrderDeliveryDiscountType } from '@unchainedshop/types/orders.deliveries.js';
3
4
  import { OrderDiscount } from '@unchainedshop/types/orders.discounts.js';
4
5
  import { OrderPrice } from '@unchainedshop/types/orders.pricing.js';
5
- import crypto from 'crypto';
6
6
 
7
7
  type HelperType<P, T> = (orderDelivery: OrderDeliveryDiscountType, params: P, context: Context) => T;
8
8
 
@@ -1,8 +1,8 @@
1
+ import crypto from 'crypto';
1
2
  import { Context } from '@unchainedshop/types/api.js';
2
3
  import { OrderDiscount } from '@unchainedshop/types/orders.discounts.js';
3
4
  import { OrderPositionDiscount } from '@unchainedshop/types/orders.positions.js';
4
5
  import { OrderPrice } from '@unchainedshop/types/orders.pricing.js';
5
- import crypto from 'crypto';
6
6
 
7
7
  type HelperType<P, T> = (orderPositionDiscount: OrderPositionDiscount, params: P, context: Context) => T;
8
8
 
@@ -1,3 +1,4 @@
1
+ import crypto from 'crypto';
1
2
  import { Context } from '@unchainedshop/types/api.js';
2
3
  import { DeliveryProvider } from '@unchainedshop/types/delivery.js';
3
4
  import { Order } from '@unchainedshop/types/orders.js';
@@ -6,7 +7,6 @@ import { OrderPrice } from '@unchainedshop/types/orders.pricing.js';
6
7
  import { Product } from '@unchainedshop/types/products.js';
7
8
  import { Quotation } from '@unchainedshop/types/quotations.js';
8
9
  import { WarehousingProvider } from '@unchainedshop/types/warehousing.js';
9
- import crypto from 'crypto';
10
10
 
11
11
  type HelperType<P, T> = (orderPosition: OrderPosition, params: P, context: Context) => T;
12
12
 
@@ -1,8 +1,8 @@
1
+ import crypto from 'crypto';
1
2
  import { Context } from '@unchainedshop/types/api.js';
2
3
  import { OrderDiscount } from '@unchainedshop/types/orders.discounts.js';
3
4
  import { OrderPayment } from '@unchainedshop/types/orders.payments.js';
4
5
  import { OrderPrice } from '@unchainedshop/types/orders.pricing.js';
5
- import crypto from 'crypto';
6
6
 
7
7
  type HelperType<P, T> = (
8
8
  orderDelivery: OrderPrice & { discountId: string; item: OrderPayment },
@@ -1,3 +1,4 @@
1
+ import crypto from 'crypto';
1
2
  import { Context } from '@unchainedshop/types/api.js';
2
3
  import { Country } from '@unchainedshop/types/countries.js';
3
4
  import { Currency } from '@unchainedshop/types/currencies.js';
@@ -11,7 +12,6 @@ import { OrderPosition } from '@unchainedshop/types/orders.positions.js';
11
12
  import { OrderPrice } from '@unchainedshop/types/orders.pricing.js';
12
13
  import { PaymentProvider } from '@unchainedshop/types/payments.js';
13
14
  import { User } from '@unchainedshop/types/user.js';
14
- import crypto from 'crypto';
15
15
 
16
16
  type HelperType<P, T> = (order: OrderType, params: P, context: Context) => T;
17
17
 
@@ -1,6 +1,6 @@
1
+ import crypto from 'crypto';
1
2
  import { Context } from '@unchainedshop/types/api.js';
2
3
  import { PaymentError, PaymentProvider as PaymentProviderType } from '@unchainedshop/types/payments.js';
3
- import crypto from 'crypto';
4
4
  import { PaymentPricingDirector } from '@unchainedshop/core-payment';
5
5
 
6
6
  export interface PaymentProviderHelperTypes {
@@ -1,6 +1,6 @@
1
+ import crypto from 'crypto';
1
2
  import { Context } from '@unchainedshop/types/api.js';
2
3
  import { ProductDiscount as ProductDiscountType } from '@unchainedshop/types/products.js';
3
- import crypto from 'crypto';
4
4
 
5
5
  type HelperType<T> = (product: ProductDiscountType, _: never, context: Context) => T;
6
6
 
@@ -30,6 +30,9 @@ export const Product: ProductHelperTypes = {
30
30
  queryString,
31
31
  });
32
32
  },
33
+ reviewsCount: async (obj, params, { modules }) => {
34
+ return modules.products.reviews.count({ ...params, productId: obj._id });
35
+ },
33
36
 
34
37
  siblings: async (product, params, { modules }) => {
35
38
  const { assortmentId, limit, offset, includeInactive = false } = params;
@@ -1,7 +1,7 @@
1
+ import crypto from 'crypto';
1
2
  import { DeliveryProvider } from '@unchainedshop/types/delivery.js';
2
3
  import { Product } from '@unchainedshop/types/products.js';
3
4
  import { WarehousingProvider } from '@unchainedshop/types/warehousing.js';
4
- import crypto from 'crypto';
5
5
 
6
6
  export const Stock = {
7
7
  _id: (params: {
@@ -20,6 +20,7 @@ import {
20
20
  import type { Locale } from 'locale';
21
21
  import { TokenSurrogate } from '@unchainedshop/types/warehousing.js';
22
22
  import { Roles, permissions } from '@unchainedshop/roles';
23
+ import { ProductReview } from '@unchainedshop/types/products.reviews.js';
23
24
  import { checkAction, checkTypeResolver } from '../../acl.js';
24
25
  import { actions } from '../../roles/index.js';
25
26
 
@@ -82,6 +83,15 @@ export interface UserHelperTypes {
82
83
  username: HelperType<any, string>;
83
84
  pushSubscriptions: HelperType<any, Array<PushSubscription>>;
84
85
  oAuthAccounts: HelperType<any, Array<OAuthAccount>>;
86
+ reviews: HelperType<
87
+ {
88
+ sort?: Array<SortOption>;
89
+ limit?: number;
90
+ offset?: number;
91
+ },
92
+ Array<ProductReview>
93
+ >;
94
+ reviewsCount: HelperType<any, number>;
85
95
  }
86
96
 
87
97
  const {
@@ -90,6 +100,7 @@ const {
90
100
  viewUserOrders,
91
101
  viewUserEnrollments,
92
102
  viewUserQuotations,
103
+ viewUserProductReviews,
93
104
  } = actions as Record<string, string>;
94
105
 
95
106
  const getPrimaryEmail = (user: UserType) => {
@@ -242,4 +253,19 @@ export const User: UserHelperTypes = {
242
253
  }));
243
254
  });
244
255
  },
256
+ async reviews(user, params, context) {
257
+ const { modules } = context;
258
+ await checkAction(context, viewUserProductReviews, [user, params]);
259
+ return modules.products.reviews.findProductReviews({
260
+ ...(params || {}),
261
+ authorId: user._id,
262
+ });
263
+ },
264
+ async reviewsCount(user, params, context) {
265
+ const { modules } = context;
266
+ await checkAction(context, viewUserProductReviews, [user, params]);
267
+ return modules.products.reviews.count({
268
+ authorId: user._id,
269
+ });
270
+ },
245
271
  };
package/src/roles/all.ts CHANGED
@@ -55,6 +55,7 @@ export const all = (role, actions) => {
55
55
  role.allow(actions.viewUserQuotations, isInLoginMutationResponse);
56
56
  role.allow(actions.viewUserPrivateInfos, isInLoginMutationResponse);
57
57
  role.allow(actions.viewUserEnrollments, isInLoginMutationResponse);
58
+ role.allow(actions.viewUserProductReviews, isInLoginMutationResponse);
58
59
  role.allow(actions.reviewProduct, () => false);
59
60
  role.allow(actions.updateProductReview, () => false);
60
61
  role.allow(actions.manageProductReviews, () => false);
@@ -79,6 +80,7 @@ export const all = (role, actions) => {
79
80
  role.allow(actions.authTwoFactor, () => false);
80
81
  role.allow(actions.manageTwoFactor, () => false);
81
82
  role.allow(actions.impersonate, () => false);
83
+ role.allow(actions.stopImpersonation, () => false);
82
84
 
83
85
  // only allow if query is not demanding for drafts
84
86
  role.allow(actions.viewProducts, (root, { includeDrafts }) => !includeDrafts);
@@ -99,4 +101,18 @@ export const all = (role, actions) => {
99
101
  role.allow(actions.viewFilters, () => true);
100
102
  role.allow(actions.viewTranslations, () => true);
101
103
  role.allow(actions.search, () => true);
104
+ role.allow(actions.logout, () => true);
105
+ role.allow(actions.logoutAllSessions, () => true);
106
+ role.allow(actions.loginAsGuest, () => true);
107
+ role.allow(actions.loginWithPassword, () => true);
108
+ role.allow(actions.loginWithWebAuthn, () => true);
109
+ role.allow(actions.loginWithOAuth, () => true);
110
+ role.allow(actions.verifyEmail, () => true);
111
+ role.allow(actions.useWebAuthn, () => true);
112
+ role.allow(actions.pageView, () => true);
113
+ role.allow(actions.createUser, () => true);
114
+ role.allow(actions.forgotPassword, () => true);
115
+ role.allow(actions.resetPassword, () => true);
116
+ role.allow(actions.changePassword, () => true);
117
+ role.allow(actions.heartbeat, () => true);
102
118
  };
@@ -101,6 +101,22 @@ const actions: Record<string, string> = [
101
101
  'authTwoFactor',
102
102
  'manageTwoFactor',
103
103
  'impersonate',
104
+ 'stopImpersonation',
105
+ 'logout',
106
+ 'logoutAllSessions',
107
+ 'loginAsGuest',
108
+ 'loginWithPassword',
109
+ 'loginWithWebAuthn',
110
+ 'loginWithOAuth',
111
+ 'verifyEmail',
112
+ 'useWebAuthn',
113
+ 'pageView',
114
+ 'createUser',
115
+ 'forgotPassword',
116
+ 'resetPassword',
117
+ 'changePassword',
118
+ 'viewUserProductReviews',
119
+ 'heartbeat',
104
120
  ].reduce((oldValue, actionValue) => {
105
121
  const newValue = oldValue;
106
122
  newValue[actionValue] = actionValue;
@@ -115,6 +131,7 @@ const configureRoles = ({ additionalRoles = {}, additionalActions = [] }) => {
115
131
  allRoles[key] = new Role(key);
116
132
  val(allRoles[key], actions);
117
133
  });
134
+
118
135
  all(allRoles.ALL, actions);
119
136
  loggedIn(allRoles.LOGGEDIN, actions);
120
137
  admin(allRoles.ADMIN, actions);
@@ -213,6 +213,7 @@ export const loggedIn = (role: any, actions: Record<string, string>) => {
213
213
  role.allow(actions.viewUserQuotations, isMyself);
214
214
  role.allow(actions.viewUserEnrollments, isMyself);
215
215
  role.allow(actions.viewUserPrivateInfos, isMyself);
216
+ role.allow(actions.viewUserProductReviews, isMyself);
216
217
  role.allow(actions.viewUserTokens, isMyself);
217
218
  role.allow(actions.updateUser, isMyself);
218
219
  role.allow(actions.authTwoFactor, isMyself);
@@ -241,4 +242,6 @@ export const loggedIn = (role: any, actions: Record<string, string>) => {
241
242
  role.allow(actions.managePaymentCredentials, isOwnedPaymentCredential);
242
243
  role.allow(actions.updateToken, isOwnedToken);
243
244
  role.allow(actions.viewToken, isOwnedToken);
245
+ role.allow(actions.stopImpersonation, () => true);
246
+ role.allow(actions.impersonate, () => false);
244
247
  };
@@ -449,6 +449,11 @@ export default [
449
449
  """
450
450
  impersonate(userId: ID!): LoginMethodResponse!
451
451
 
452
+ """
453
+ End customer impersonated user session and resume the impersonator session
454
+ """
455
+ stopImpersonation: LoginMethodResponse!
456
+
452
457
  """
453
458
  Reorder a media asset (first is primary)
454
459
  """
@@ -5,6 +5,10 @@ export default [
5
5
  Currently logged in user
6
6
  """
7
7
  me: User
8
+ """
9
+ User impersonating current user session using the impersonate API
10
+ """
11
+ impersonator: User
8
12
 
9
13
  """
10
14
  Get list of users, by default sorted by creation date (ascending) unless a queryString is set
@@ -20,6 +20,7 @@ export default [
20
20
  sort: [SortOptionInput!]
21
21
  queryString: String
22
22
  ): [ProductReview!]!
23
+ reviewsCount(queryString: String): Int!
23
24
  assortmentPaths: [ProductAssortmentPath!]!
24
25
  siblings(
25
26
  assortmentId: ID
@@ -85,6 +85,7 @@ export default [
85
85
  sort: [SortOptionInput!]
86
86
  queryString: String
87
87
  ): [ProductReview!]!
88
+ reviewsCount(queryString: String): Int!
88
89
  catalogPriceRange(
89
90
  quantity: Int = 0
90
91
  vectors: [ProductAssignmentVectorInput!]
@@ -62,6 +62,7 @@ export default [
62
62
  sort: [SortOptionInput!]
63
63
  queryString: String
64
64
  ): [ProductReview!]!
65
+ reviewsCount(queryString: String): Int!
65
66
  plan: ProductPlanConfiguration
66
67
  }
67
68
  `,
@@ -69,6 +69,7 @@ export default [
69
69
  sort: [SortOptionInput!]
70
70
  queryString: String
71
71
  ): [ProductReview!]!
72
+ reviewsCount(queryString: String): Int!
72
73
  assortmentPaths: [ProductAssortmentPath!]!
73
74
  siblings(
74
75
  assortmentId: ID
@@ -45,6 +45,7 @@ export default [
45
45
  sort: [SortOptionInput!]
46
46
  queryString: String
47
47
  ): [ProductReview!]!
48
+ reviewsCount(queryString: String): Int!
48
49
  }
49
50
  `,
50
51
  ];
@@ -50,6 +50,7 @@ export default [
50
50
  sort: [SortOptionInput!]
51
51
  queryString: String
52
52
  ): [ProductReview!]!
53
+ reviewsCount(queryString: String): Int!
53
54
  contractAddress: String
54
55
  contractStandard: SmartContractStandard
55
56
  contractConfiguration: ContractConfiguration
@@ -153,6 +153,8 @@ export default [
153
153
  allowedActions: [RoleAction!]!
154
154
  tokens: [Token!]!
155
155
  oAuthAccounts: [OAuthAccount!]!
156
+ reviews(limit: Int = 10, offset: Int = 0, sort: [SortOptionInput!]): [ProductReview!]!
157
+ reviewsCount: Int!
156
158
  }
157
159
  `,
158
160
  ];
@@ -1,6 +1,6 @@
1
+ import { IncomingMessage, OutgoingMessage } from 'http';
1
2
  import { UnchainedUserContext } from '@unchainedshop/types/api.js';
2
3
  import { UnchainedCore } from '@unchainedshop/types/core.js';
3
- import { IncomingMessage, OutgoingMessage } from 'http';
4
4
  import cookie from 'cookie';
5
5
 
6
6
  function isString(input) {