@stamhoofd/backend 2.48.0 → 2.49.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stamhoofd/backend",
3
- "version": "2.48.0",
3
+ "version": "2.49.0",
4
4
  "main": "./dist/index.js",
5
5
  "exports": {
6
6
  ".": {
@@ -33,17 +33,17 @@
33
33
  "dependencies": {
34
34
  "@mollie/api-client": "3.7.0",
35
35
  "@simonbackx/simple-database": "1.25.0",
36
- "@simonbackx/simple-encoding": "2.15.1",
36
+ "@simonbackx/simple-encoding": "2.16.1",
37
37
  "@simonbackx/simple-endpoints": "1.14.0",
38
38
  "@simonbackx/simple-logging": "^1.0.1",
39
- "@stamhoofd/backend-i18n": "2.48.0",
40
- "@stamhoofd/backend-middleware": "2.48.0",
41
- "@stamhoofd/email": "2.48.0",
42
- "@stamhoofd/models": "2.48.0",
43
- "@stamhoofd/queues": "2.48.0",
44
- "@stamhoofd/sql": "2.48.0",
45
- "@stamhoofd/structures": "2.48.0",
46
- "@stamhoofd/utility": "2.48.0",
39
+ "@stamhoofd/backend-i18n": "2.49.0",
40
+ "@stamhoofd/backend-middleware": "2.49.0",
41
+ "@stamhoofd/email": "2.49.0",
42
+ "@stamhoofd/models": "2.49.0",
43
+ "@stamhoofd/queues": "2.49.0",
44
+ "@stamhoofd/sql": "2.49.0",
45
+ "@stamhoofd/structures": "2.49.0",
46
+ "@stamhoofd/utility": "2.49.0",
47
47
  "archiver": "^7.0.1",
48
48
  "aws-sdk": "^2.885.0",
49
49
  "axios": "1.6.8",
@@ -60,5 +60,5 @@
60
60
  "postmark": "^4.0.5",
61
61
  "stripe": "^16.6.0"
62
62
  },
63
- "gitHead": "64ace7d8f8dcfa887046c4415d0f0f4cac236ef4"
63
+ "gitHead": "ee78a53466f94dd4c58e7a3140198422f25ee961"
64
64
  }
@@ -71,7 +71,7 @@ export class GetMembersEndpoint extends Endpoint<Params, Query, Body, ResponseBo
71
71
  }
72
72
  }
73
73
 
74
- if (organization) {
74
+ if (organization && !Context.auth.canAccessAllPlatformMembers()) {
75
75
  // Add organization scope filter
76
76
  const groups = await Context.auth.getAccessibleGroups(organization.id);
77
77
 
@@ -65,7 +65,7 @@ export class RegisterMembersEndpoint extends Endpoint<Params, Query, Body, Respo
65
65
  const { user } = await Context.authenticate();
66
66
 
67
67
  if (request.body.asOrganizationId && request.body.asOrganizationId !== organization.id) {
68
- if (!await Context.auth.hasFullAccess(request.body.asOrganizationId)) {
68
+ if (!await Context.auth.canManageFinances(request.body.asOrganizationId)) {
69
69
  throw new SimpleError({
70
70
  code: 'forbidden',
71
71
  message: 'No permission to register as this organization for a different organization',
@@ -73,13 +73,15 @@ export class GetEmailTemplatesEndpoint extends Endpoint<Params, Query, Body, Res
73
73
  );
74
74
 
75
75
  const defaultTemplateTypes = organization ? types.filter(type => type !== EmailTemplateType.SavedMembersEmail) : types;
76
- const defaultTemplates = await EmailTemplate.where({
77
- organizationId: null,
78
- type: {
79
- sign: 'IN',
80
- value: defaultTemplateTypes,
81
- },
82
- });
76
+ const defaultTemplates = defaultTemplateTypes.length === 0
77
+ ? []
78
+ : (await EmailTemplate.where({
79
+ organizationId: null,
80
+ type: {
81
+ sign: 'IN',
82
+ value: defaultTemplateTypes,
83
+ },
84
+ }));
83
85
 
84
86
  return new Response(templates.concat(defaultTemplates).map(template => EmailTemplateStruct.create(template)));
85
87
  }
@@ -94,11 +94,11 @@ export class PatchBalanceItemsEndpoint extends Endpoint<Params, Query, Body, Res
94
94
  }
95
95
 
96
96
  if (patch.unitPrice !== undefined) {
97
- throw new SimpleError({
98
- code: 'invalid_field',
99
- message: 'You cannot change the unit price of a balance item',
100
- human: 'Het is niet mogelijk om de eenheidsprijs van een openstaande schuld te wijzigen. Je kan de openstaande schuld verwijderen en opnieuw aanmaken indien noodzakelijk.',
101
- });
97
+ // throw new SimpleError({
98
+ // code: 'invalid_field',
99
+ // message: 'You cannot change the unit price of a balance item',
100
+ // human: 'Het is niet mogelijk om de eenheidsprijs van een openstaande schuld te wijzigen. Je kan de openstaande schuld verwijderen en opnieuw aanmaken indien noodzakelijk.',
101
+ // });
102
102
  }
103
103
 
104
104
  // Check permissions
@@ -1,9 +1,10 @@
1
1
  import { Decoder } from '@simonbackx/simple-encoding';
2
2
  import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
3
- import { assertSort, CountFilteredRequest, getSortFilter, LimitedFilteredRequest, PaginatedResponse, PrivateOrder, StamhoofdFilter } from '@stamhoofd/structures';
3
+ import { assertSort, CountFilteredRequest, getOrderSearchFilter, getSortFilter, LimitedFilteredRequest, PaginatedResponse, PrivateOrder, StamhoofdFilter } from '@stamhoofd/structures';
4
4
 
5
5
  import { Order } from '@stamhoofd/models';
6
6
  import { compileToSQLFilter, compileToSQLSorter, SQL, SQLFilterDefinitions, SQLSortDefinitions } from '@stamhoofd/sql';
7
+ import { parsePhoneNumber } from 'libphonenumber-js/max';
7
8
  import { AuthenticatedStructures } from '../../../../helpers/AuthenticatedStructures';
8
9
  import { Context } from '../../../../helpers/Context';
9
10
  import { LimitedFilteredRequestHelper } from '../../../../helpers/LimitedFilteredRequestHelper';
@@ -51,16 +52,8 @@ export class GetWebshopOrdersEndpoint extends Endpoint<Params, Query, Body, Resp
51
52
  query.where(compileToSQLFilter(q.filter, filterCompilers));
52
53
  }
53
54
 
54
- // todo: use same logic as frontend
55
55
  if (q.search) {
56
- let searchFilter: StamhoofdFilter | null = null;
57
-
58
- // todo: detect special search patterns and adjust search filter if needed
59
- searchFilter = {
60
- name: {
61
- $contains: q.search,
62
- },
63
- };
56
+ const searchFilter: StamhoofdFilter | null = getOrderSearchFilter(q.search, parsePhoneNumber);
64
57
 
65
58
  if (searchFilter) {
66
59
  query.where(compileToSQLFilter(searchFilter, filterCompilers));
@@ -19,6 +19,10 @@ export class ModelHelper {
19
19
 
20
20
  await onBatchReceived(models);
21
21
 
22
+ if (models.length < limit) {
23
+ break;
24
+ }
25
+
22
26
  lastId
23
27
  = models[
24
28
  models.length - 1
@@ -50,9 +50,9 @@ describe('TagHelper', () => {
50
50
  ]);
51
51
 
52
52
  // act
53
- const doesTag3ContainTag4 = TagHelper.containsDeep('id3', 'id4', tags);
54
- const doesTag3ContainTag5 = TagHelper.containsDeep('id3', 'id5', tags);
55
- const doesTag3ContainTag1 = TagHelper.containsDeep('id3', 'id1', tags);
53
+ const doesTag3ContainTag4 = TagHelper.containsDeep('id3', 'id4', { tagMap: tags });
54
+ const doesTag3ContainTag5 = TagHelper.containsDeep('id3', 'id5', { tagMap: tags });
55
+ const doesTag3ContainTag1 = TagHelper.containsDeep('id3', 'id1', { tagMap: tags });
56
56
 
57
57
  // assert
58
58
  expect(doesTag3ContainTag4).toBe(true);
@@ -16,8 +16,12 @@ export default new Migration(async () => {
16
16
 
17
17
  await ModelHelper.loop(Order, 'id', async (batch: Order[]) => {
18
18
  console.log('Saving orders...', `(${count})`);
19
+
19
20
  // save all orders to update the new columns
20
- await Promise.all(batch.map(order => order.save()));
21
+ for (const order of batch) {
22
+ await order.save();
23
+ }
24
+
21
25
  count += limit;
22
26
  },
23
27
  { limit });
@@ -27,6 +27,7 @@ export const memberFilterCompilers: SQLFilterDefinitions = {
27
27
  SQL.jsonValue(SQL.column('details'), '$.value.gender'),
28
28
  { isJSONValue: true, type: SQLValueType.JSONString },
29
29
  ),
30
+
30
31
  'birthDay': createSQLColumnFilterCompiler('birthDay', {
31
32
  normalizeValue: (d) => {
32
33
  if (typeof d === 'number') {
@@ -36,6 +37,7 @@ export const memberFilterCompilers: SQLFilterDefinitions = {
36
37
  return d;
37
38
  },
38
39
  }),
40
+
39
41
  'organizationName': createSQLExpressionFilterCompiler(
40
42
  SQL.column('organizations', 'name'),
41
43
  ),
@@ -55,6 +57,28 @@ export const memberFilterCompilers: SQLFilterDefinitions = {
55
57
  { isJSONValue: true, isJSONObject: true, type: SQLValueType.JSONString },
56
58
  ),
57
59
 
60
+ 'details.parents[0]': createSQLFilterNamespace({
61
+ name: createSQLExpressionFilterCompiler(
62
+ new SQLConcat(
63
+ SQL.jsonUnquotedValue(SQL.column('details'), '$.value.parents[0].firstName'),
64
+ new SQLScalar(' '),
65
+ SQL.jsonUnquotedValue(SQL.column('details'), '$.value.parents[0].lastName'),
66
+ ),
67
+ { isJSONValue: true, isJSONObject: false, type: SQLValueType.JSONString },
68
+ ),
69
+ }),
70
+
71
+ 'details.parents[1]': createSQLFilterNamespace({
72
+ name: createSQLExpressionFilterCompiler(
73
+ new SQLConcat(
74
+ SQL.jsonUnquotedValue(SQL.column('details'), '$.value.parents[1].firstName'),
75
+ new SQLScalar(' '),
76
+ SQL.jsonUnquotedValue(SQL.column('details'), '$.value.parents[1].lastName'),
77
+ ),
78
+ { isJSONValue: true, isJSONObject: false, type: SQLValueType.JSONString },
79
+ ),
80
+ }),
81
+
58
82
  'unverifiedEmail': createSQLExpressionFilterCompiler(
59
83
  SQL.jsonValue(SQL.column('details'), '$.value.unverifiedEmails'),
60
84
  { isJSONValue: true, isJSONObject: true, type: SQLValueType.JSONString },
@@ -78,6 +102,10 @@ export const memberFilterCompilers: SQLFilterDefinitions = {
78
102
  SQL.jsonValue(SQL.column('details'), '$.value.address.street'),
79
103
  { isJSONValue: true, type: SQLValueType.JSONString },
80
104
  ),
105
+ number: createSQLExpressionFilterCompiler(
106
+ SQL.jsonValue(SQL.column('details'), '$.value.address.number'),
107
+ { isJSONValue: true, type: SQLValueType.JSONString },
108
+ ),
81
109
  }),
82
110
 
83
111
  'details.parents[*].address': createSQLFilterNamespace({
@@ -93,6 +121,10 @@ export const memberFilterCompilers: SQLFilterDefinitions = {
93
121
  SQL.jsonValue(SQL.column('details'), '$.value.parents[*].address.street'),
94
122
  { isJSONValue: true, isJSONObject: true },
95
123
  ),
124
+ number: createSQLExpressionFilterCompiler(
125
+ SQL.jsonValue(SQL.column('details'), '$.value.parents[*].address.number'),
126
+ { isJSONValue: true, isJSONObject: true },
127
+ ),
96
128
  }),
97
129
 
98
130
  'parentPhone': createSQLExpressionFilterCompiler(
@@ -1,4 +1,4 @@
1
- import { baseSQLFilterCompilers, createSQLColumnFilterCompiler, createSQLExpressionFilterCompiler, SQL, SQLConcat, SQLFilterDefinitions, SQLScalar, SQLValueType } from '@stamhoofd/sql';
1
+ import { baseSQLFilterCompilers, createSQLColumnFilterCompiler, createSQLExpressionFilterCompiler, SQL, SQLCast, SQLConcat, SQLFilterDefinitions, SQLJsonUnquote, SQLScalar, SQLValueType } from '@stamhoofd/sql';
2
2
 
3
3
  export const orderFilterCompilers: SQLFilterDefinitions = {
4
4
  ...baseSQLFilterCompilers,
@@ -36,17 +36,14 @@ export const orderFilterCompilers: SQLFilterDefinitions = {
36
36
  { isJSONValue: true, type: SQLValueType.JSONString },
37
37
  ),
38
38
  validAt: createSQLColumnFilterCompiler('validAt'),
39
-
40
- // todo: TEST!
41
39
  name: createSQLExpressionFilterCompiler(
42
- new SQLConcat(
43
- SQL.jsonValue(SQL.column('data'), '$.value.customer.firstName'),
44
- new SQLScalar(' '),
45
- SQL.jsonValue(SQL.column('data'), '$.value.customer.lastName'),
46
- ),
47
- // SQL.jsonValue(SQL.column('data'), '$.value.customer.name'),
48
- // todo: type?
49
- { isJSONValue: true, type: SQLValueType.JSONString },
40
+ new SQLCast(
41
+ new SQLConcat(
42
+ new SQLJsonUnquote(SQL.jsonValue(SQL.column('data'), '$.value.customer.firstName')),
43
+ new SQLScalar(' '),
44
+ new SQLJsonUnquote(SQL.jsonValue(SQL.column('data'), '$.value.customer.lastName')),
45
+ ),
46
+ 'CHAR'),
50
47
  ),
51
48
  email: createSQLExpressionFilterCompiler(
52
49
  SQL.jsonValue(SQL.column('data'), '$.value.customer.email'),
@@ -61,8 +58,4 @@ export const orderFilterCompilers: SQLFilterDefinitions = {
61
58
  totalPrice: createSQLColumnFilterCompiler('totalPrice'),
62
59
  amount: createSQLColumnFilterCompiler('amount'),
63
60
  timeSlotTime: createSQLColumnFilterCompiler('timeSlotTime'),
64
-
65
- // only frontend
66
- // openBalance
67
- // location
68
61
  };