@labdigital/commercetools-mock 2.14.0 → 2.14.2
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/dist/index.cjs +65 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +65 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/repositories/customer.ts +72 -0
- package/src/services/customer.test.ts +154 -0
- package/src/services/my-customer.test.ts +55 -2
- package/src/services/my-customer.ts +36 -1
package/package.json
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
Customer,
|
|
3
|
+
CustomerChangeAddressAction,
|
|
3
4
|
CustomerChangeEmailAction,
|
|
4
5
|
CustomerDraft,
|
|
5
6
|
CustomerSetAuthenticationModeAction,
|
|
7
|
+
CustomerSetCompanyNameAction,
|
|
6
8
|
CustomerSetCustomFieldAction,
|
|
9
|
+
CustomerSetFirstNameAction,
|
|
10
|
+
CustomerSetLastNameAction,
|
|
11
|
+
CustomerSetVatIdAction,
|
|
7
12
|
DuplicateFieldError,
|
|
8
13
|
InvalidInputError,
|
|
9
14
|
InvalidJsonInputError,
|
|
@@ -16,6 +21,7 @@ import {
|
|
|
16
21
|
type RepositoryContext,
|
|
17
22
|
} from './abstract.js'
|
|
18
23
|
import { hashPassword } from '../lib/password.js'
|
|
24
|
+
import { createAddress } from './helpers.js'
|
|
19
25
|
|
|
20
26
|
export class CustomerRepository extends AbstractResourceRepository<'customer'> {
|
|
21
27
|
getTypeId() {
|
|
@@ -97,6 +103,72 @@ export class CustomerRepository extends AbstractResourceRepository<'customer'> {
|
|
|
97
103
|
) => {
|
|
98
104
|
resource.email = email
|
|
99
105
|
},
|
|
106
|
+
setFirstName: (
|
|
107
|
+
_context: RepositoryContext,
|
|
108
|
+
resource: Writable<Customer>,
|
|
109
|
+
{ firstName }: CustomerSetFirstNameAction
|
|
110
|
+
) => {
|
|
111
|
+
resource.firstName = firstName
|
|
112
|
+
},
|
|
113
|
+
setLastName: (
|
|
114
|
+
_context: RepositoryContext,
|
|
115
|
+
resource: Writable<Customer>,
|
|
116
|
+
{ lastName }: CustomerSetLastNameAction
|
|
117
|
+
) => {
|
|
118
|
+
resource.lastName = lastName
|
|
119
|
+
},
|
|
120
|
+
setCompanyName: (
|
|
121
|
+
_context: RepositoryContext,
|
|
122
|
+
resource: Writable<Customer>,
|
|
123
|
+
{ companyName }: CustomerSetCompanyNameAction
|
|
124
|
+
) => {
|
|
125
|
+
resource.companyName = companyName
|
|
126
|
+
},
|
|
127
|
+
setVatId: (
|
|
128
|
+
_context: RepositoryContext,
|
|
129
|
+
resource: Writable<Customer>,
|
|
130
|
+
{ vatId }: CustomerSetVatIdAction
|
|
131
|
+
) => {
|
|
132
|
+
resource.vatId = vatId
|
|
133
|
+
},
|
|
134
|
+
changeAddress: (
|
|
135
|
+
context: RepositoryContext,
|
|
136
|
+
resource: Writable<Customer>,
|
|
137
|
+
{ addressId, addressKey, address }: CustomerChangeAddressAction
|
|
138
|
+
) => {
|
|
139
|
+
const oldAddressIndex = resource.addresses.findIndex((a) => {
|
|
140
|
+
if (a.id != undefined && addressId != undefined && a.id === addressId) {
|
|
141
|
+
return true
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return (
|
|
145
|
+
a.key != undefined && addressKey != undefined && a.key === addressKey
|
|
146
|
+
)
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
if (oldAddressIndex === -1) {
|
|
150
|
+
throw new CommercetoolsError<InvalidInputError>(
|
|
151
|
+
{
|
|
152
|
+
code: 'InvalidInput',
|
|
153
|
+
message: `Address with id '${addressId}' or key '${addressKey}' not found.`,
|
|
154
|
+
},
|
|
155
|
+
400
|
|
156
|
+
)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const newAddress = createAddress(
|
|
160
|
+
address,
|
|
161
|
+
context.projectKey,
|
|
162
|
+
this._storage
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
if (newAddress) {
|
|
166
|
+
resource.addresses[oldAddressIndex] = {
|
|
167
|
+
id: addressId,
|
|
168
|
+
...newAddress,
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
},
|
|
100
172
|
setAuthenticationMode: (
|
|
101
173
|
_context: RepositoryContext,
|
|
102
174
|
resource: Writable<Customer>,
|
|
@@ -176,4 +176,158 @@ describe('Customer Update Actions', () => {
|
|
|
176
176
|
expect(response.body.version).toBe(2)
|
|
177
177
|
expect(response.body.custom.fields.isValidCouponCode).toBe(false)
|
|
178
178
|
})
|
|
179
|
+
|
|
180
|
+
test('setFirstName', async () => {
|
|
181
|
+
assert(customer, 'customer not created')
|
|
182
|
+
|
|
183
|
+
customer = {
|
|
184
|
+
...customer,
|
|
185
|
+
firstName: 'John',
|
|
186
|
+
}
|
|
187
|
+
ctMock.project('dummy').add('customer', customer)
|
|
188
|
+
|
|
189
|
+
const response = await supertest(ctMock.app)
|
|
190
|
+
.post(`/dummy/customers/${customer.id}`)
|
|
191
|
+
.send({
|
|
192
|
+
version: 1,
|
|
193
|
+
actions: [{ action: 'setFirstName', firstName: 'Mary' }],
|
|
194
|
+
})
|
|
195
|
+
expect(response.status).toBe(200)
|
|
196
|
+
expect(response.body.version).toBe(2)
|
|
197
|
+
expect(response.body.firstName).toBe('Mary')
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
test('setLastName', async () => {
|
|
201
|
+
assert(customer, 'customer not created')
|
|
202
|
+
|
|
203
|
+
customer = {
|
|
204
|
+
...customer,
|
|
205
|
+
lastName: 'Doe',
|
|
206
|
+
}
|
|
207
|
+
ctMock.project('dummy').add('customer', customer)
|
|
208
|
+
|
|
209
|
+
const response = await supertest(ctMock.app)
|
|
210
|
+
.post(`/dummy/customers/${customer.id}`)
|
|
211
|
+
.send({
|
|
212
|
+
version: 1,
|
|
213
|
+
actions: [{ action: 'setLastName', lastName: 'Smith' }],
|
|
214
|
+
})
|
|
215
|
+
expect(response.status).toBe(200)
|
|
216
|
+
expect(response.body.version).toBe(2)
|
|
217
|
+
expect(response.body.lastName).toBe('Smith')
|
|
218
|
+
})
|
|
219
|
+
|
|
220
|
+
test('setCompanyName', async () => {
|
|
221
|
+
assert(customer, 'customer not created')
|
|
222
|
+
|
|
223
|
+
customer = {
|
|
224
|
+
...customer,
|
|
225
|
+
companyName: 'Acme',
|
|
226
|
+
}
|
|
227
|
+
ctMock.project('dummy').add('customer', customer)
|
|
228
|
+
|
|
229
|
+
const response = await supertest(ctMock.app)
|
|
230
|
+
.post(`/dummy/customers/${customer.id}`)
|
|
231
|
+
.send({
|
|
232
|
+
version: 1,
|
|
233
|
+
actions: [{ action: 'setCompanyName', companyName: 'Acme Inc.' }],
|
|
234
|
+
})
|
|
235
|
+
expect(response.status).toBe(200)
|
|
236
|
+
expect(response.body.version).toBe(2)
|
|
237
|
+
expect(response.body.companyName).toBe('Acme Inc.')
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
test('setVatId', async () => {
|
|
241
|
+
assert(customer, 'customer not created')
|
|
242
|
+
|
|
243
|
+
customer = {
|
|
244
|
+
...customer,
|
|
245
|
+
vatId: '123456789',
|
|
246
|
+
}
|
|
247
|
+
ctMock.project('dummy').add('customer', customer)
|
|
248
|
+
|
|
249
|
+
const response = await supertest(ctMock.app)
|
|
250
|
+
.post(`/dummy/customers/${customer.id}`)
|
|
251
|
+
.send({
|
|
252
|
+
version: 1,
|
|
253
|
+
actions: [{ action: 'setVatId', vatId: 'ABCD' }],
|
|
254
|
+
})
|
|
255
|
+
expect(response.status).toBe(200)
|
|
256
|
+
expect(response.body.version).toBe(2)
|
|
257
|
+
expect(response.body.vatId).toBe('ABCD')
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
test('changeAddress', async () => {
|
|
261
|
+
assert(customer, 'customer not created')
|
|
262
|
+
|
|
263
|
+
customer = {
|
|
264
|
+
...customer,
|
|
265
|
+
addresses: [
|
|
266
|
+
{
|
|
267
|
+
...getBaseResourceProperties(),
|
|
268
|
+
id: 'other-address-uid',
|
|
269
|
+
firstName: 'Foo',
|
|
270
|
+
lastName: 'Bar',
|
|
271
|
+
streetName: 'Baz Street',
|
|
272
|
+
streetNumber: '99',
|
|
273
|
+
postalCode: '12ab',
|
|
274
|
+
country: 'NL',
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
...getBaseResourceProperties(),
|
|
278
|
+
id: 'address-uuid',
|
|
279
|
+
firstName: 'John',
|
|
280
|
+
lastName: 'Doe',
|
|
281
|
+
streetName: 'Main Street',
|
|
282
|
+
streetNumber: '1',
|
|
283
|
+
postalCode: '12345',
|
|
284
|
+
country: 'DE',
|
|
285
|
+
},
|
|
286
|
+
],
|
|
287
|
+
defaultBillingAddressId: 'address-uuid',
|
|
288
|
+
}
|
|
289
|
+
ctMock.project('dummy').add('customer', customer)
|
|
290
|
+
|
|
291
|
+
const response = await supertest(ctMock.app)
|
|
292
|
+
.post(`/dummy/customers/${customer.id}`)
|
|
293
|
+
.send({
|
|
294
|
+
version: 1,
|
|
295
|
+
actions: [
|
|
296
|
+
{
|
|
297
|
+
action: 'changeAddress',
|
|
298
|
+
addressId: 'address-uuid',
|
|
299
|
+
address: {
|
|
300
|
+
firstName: 'Marie',
|
|
301
|
+
lastName: 'Johnson',
|
|
302
|
+
streetName: 'Last Street',
|
|
303
|
+
streetNumber: '2',
|
|
304
|
+
postalCode: 'ABCS',
|
|
305
|
+
country: 'US',
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
],
|
|
309
|
+
})
|
|
310
|
+
expect(response.status).toBe(200)
|
|
311
|
+
expect(response.body.version).toBe(2)
|
|
312
|
+
expect(response.body.addresses).toMatchObject([
|
|
313
|
+
{
|
|
314
|
+
id: 'other-address-uid',
|
|
315
|
+
firstName: 'Foo',
|
|
316
|
+
lastName: 'Bar',
|
|
317
|
+
streetName: 'Baz Street',
|
|
318
|
+
streetNumber: '99',
|
|
319
|
+
postalCode: '12ab',
|
|
320
|
+
country: 'NL',
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
id: 'address-uuid',
|
|
324
|
+
firstName: 'Marie',
|
|
325
|
+
lastName: 'Johnson',
|
|
326
|
+
streetName: 'Last Street',
|
|
327
|
+
streetNumber: '2',
|
|
328
|
+
postalCode: 'ABCS',
|
|
329
|
+
country: 'US',
|
|
330
|
+
},
|
|
331
|
+
])
|
|
332
|
+
})
|
|
179
333
|
})
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
CustomerChangePassword,
|
|
3
|
+
MyCustomerDraft,
|
|
4
|
+
} from '@commercetools/platform-sdk'
|
|
2
5
|
import supertest from 'supertest'
|
|
3
6
|
import { afterEach, beforeEach, describe, expect, test } from 'vitest'
|
|
4
|
-
import { CommercetoolsMock } from '../index.js'
|
|
7
|
+
import { CommercetoolsMock, getBaseResourceProperties } from '../index.js'
|
|
8
|
+
import { hashPassword } from '../lib/password.js'
|
|
5
9
|
|
|
6
10
|
const ctMock = new CommercetoolsMock()
|
|
7
11
|
|
|
@@ -120,6 +124,55 @@ describe('/me', () => {
|
|
|
120
124
|
expect(newResponse.status).toBe(404)
|
|
121
125
|
})
|
|
122
126
|
|
|
127
|
+
test('Change my password', async () => {
|
|
128
|
+
const customer = {
|
|
129
|
+
...getBaseResourceProperties(),
|
|
130
|
+
id: 'customer-uuid',
|
|
131
|
+
email: 'user@example.com',
|
|
132
|
+
password: hashPassword('p4ssw0rd'),
|
|
133
|
+
addresses: [],
|
|
134
|
+
isEmailVerified: true,
|
|
135
|
+
authenticationMode: 'Password', //default in Commercetools
|
|
136
|
+
version: 1,
|
|
137
|
+
}
|
|
138
|
+
ctMock.project('dummy').add('customer', customer)
|
|
139
|
+
|
|
140
|
+
const draft: CustomerChangePassword = {
|
|
141
|
+
id: customer.id,
|
|
142
|
+
version: customer.version,
|
|
143
|
+
newPassword: 'newP4ssw0rd',
|
|
144
|
+
currentPassword: 'p4ssw0rd',
|
|
145
|
+
}
|
|
146
|
+
const response = await supertest(ctMock.app)
|
|
147
|
+
.post('/dummy/me/password')
|
|
148
|
+
.send(draft)
|
|
149
|
+
|
|
150
|
+
expect(response.status).toBe(200)
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
test('Fail to change password', async () => {
|
|
154
|
+
const draft: CustomerChangePassword = {
|
|
155
|
+
id: 'foo',
|
|
156
|
+
version: 1,
|
|
157
|
+
newPassword: 'newP4ssw0rd',
|
|
158
|
+
currentPassword: 'p4ssw0rd',
|
|
159
|
+
}
|
|
160
|
+
const response = await supertest(ctMock.app)
|
|
161
|
+
.post('/dummy/me/password')
|
|
162
|
+
.send(draft)
|
|
163
|
+
|
|
164
|
+
expect(response.status).toBe(404)
|
|
165
|
+
expect(response.body).toEqual({
|
|
166
|
+
errors: [
|
|
167
|
+
{
|
|
168
|
+
code: 'InvalidCurrentPassword',
|
|
169
|
+
message: 'Account with the given credentials not found.',
|
|
170
|
+
},
|
|
171
|
+
],
|
|
172
|
+
message: 'Account with the given credentials not found.',
|
|
173
|
+
})
|
|
174
|
+
})
|
|
175
|
+
|
|
123
176
|
test('setCustomField', async () => {
|
|
124
177
|
const response = await supertest(ctMock.app)
|
|
125
178
|
.post(`/dummy/me`)
|
|
@@ -3,7 +3,11 @@ import { CustomerRepository } from '../repositories/customer.js'
|
|
|
3
3
|
import { getRepositoryContext } from '../repositories/helpers.js'
|
|
4
4
|
import AbstractService from './abstract.js'
|
|
5
5
|
import { hashPassword } from '../lib/password.js'
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
Customer,
|
|
8
|
+
Update,
|
|
9
|
+
InvalidCurrentPasswordError,
|
|
10
|
+
} from '@commercetools/platform-sdk'
|
|
7
11
|
|
|
8
12
|
export class MyCustomerService extends AbstractService {
|
|
9
13
|
public repository: CustomerRepository
|
|
@@ -31,6 +35,7 @@ export class MyCustomerService extends AbstractService {
|
|
|
31
35
|
router.post('/signup', this.signUp.bind(this))
|
|
32
36
|
|
|
33
37
|
router.post('/login', this.signIn.bind(this))
|
|
38
|
+
router.post('/password', this.changePassword.bind(this))
|
|
34
39
|
|
|
35
40
|
parent.use(`/${basePath}`, router)
|
|
36
41
|
}
|
|
@@ -79,6 +84,36 @@ export class MyCustomerService extends AbstractService {
|
|
|
79
84
|
return response.status(this.createStatusCode).send({ customer: result })
|
|
80
85
|
}
|
|
81
86
|
|
|
87
|
+
changePassword(request: Request, response: Response) {
|
|
88
|
+
const { currentPassword, newPassword } = request.body
|
|
89
|
+
const encodedPassword = hashPassword(currentPassword)
|
|
90
|
+
|
|
91
|
+
const result = this.repository.query(getRepositoryContext(request), {
|
|
92
|
+
where: [`password = "${encodedPassword}"`],
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
if (result.count === 0) {
|
|
96
|
+
return response.status(404).send({
|
|
97
|
+
message: 'Account with the given credentials not found.',
|
|
98
|
+
errors: [
|
|
99
|
+
{
|
|
100
|
+
code: 'InvalidCurrentPassword',
|
|
101
|
+
message: 'Account with the given credentials not found.',
|
|
102
|
+
} as InvalidCurrentPasswordError,
|
|
103
|
+
],
|
|
104
|
+
})
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const newCustomer: Customer = {
|
|
108
|
+
...result.results[0],
|
|
109
|
+
password: hashPassword(newPassword),
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
this.repository.saveNew(getRepositoryContext(request), newCustomer)
|
|
113
|
+
|
|
114
|
+
return response.status(200).send(newCustomer)
|
|
115
|
+
}
|
|
116
|
+
|
|
82
117
|
signIn(request: Request, response: Response) {
|
|
83
118
|
const { email, password } = request.body
|
|
84
119
|
const encodedPassword = hashPassword(password)
|