Skip to content
This repository was archived by the owner on May 28, 2023. It is now read-only.

Commit 153fb63

Browse files
author
tkostuch
committed
Merge remote-tracking branch 'github/develop'
2 parents 0846b5a + 4bde19c commit 153fb63

File tree

12 files changed

+261
-89
lines changed

12 files changed

+261
-89
lines changed

.eslintignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules

CHANGELOG.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1616
- Endpoint for reset password with reset token. Only for Magento 2 - @Fifciu
1717
- Varnish Cache with autoinvalidation by Cache tags as addon - @Fifciu
1818
- Add `resetPasswordUsingResetToken` to `magento1` platform - @cewald (#415)
19+
- Update to `storefront-query-builder` version `1.0.0` - @cewald (#429)
20+
- Add `composeError` in './magento2/o2m.js' - @flancer64 (#422)
21+
- Explicit data extraction from 'Error' objects - @flancer64 (#424)
1922

2023
### Fixed
2124
- add es7 support for map url module and fixed default index for es config - @gibkigonzo
2225
- Add correct paths for production build - @cewald (#407)
2326
- Fix MSI default stock id value
27+
- Add outputFormatter to response from cache - @gibkigonzo (#428)
28+
29+
30+
## [1.11.1] - 2020.03.17
31+
32+
### Added
33+
- Add save address on place order - @lucasqm (#394)
34+
- Add ElasticSearch client support for HTTP authentication - @cewald (#397)
35+
- Add error handling for catalog and add header 'X-VS-Cache-Tags' to response - @gibkigonzo
36+
37+
### Fixed
38+
- Add fallback for `sourcePriceInclTax` and `finalPriceInclTax` in `magento1` platform - @cewald (#398)
39+
- Add default ES index to config and update `getStockList` - @gibkigonzo (#405)
40+
- Makes elastic-stock extension compatible with both ES5 and ES7. Allows for stock fetch of configurable children that is set as "Not Visible Individually" - @didkan (#410)
41+
2442

2543
## [1.11.0] - 2019.12.20
2644

config/default.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@
246246
"cms-data",
247247
"mail-service",
248248
"example-processor",
249+
"example-custom-filter",
249250
"elastic-stock"
250251
],
251252
"extensions": {
@@ -270,6 +271,9 @@
270271
"resultProcessors": {
271272
"product": "my-product-processor"
272273
}
274+
},
275+
"example-custom-filter": {
276+
"catalogFilter": [ "SampleFilter" ]
273277
}
274278
},
275279
"magento2": {

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "vue-storefront-api",
3-
"version": "1.11.0",
3+
"version": "1.11.1",
44
"private": true,
55
"description": "vue-storefront API and data services",
66
"main": "dist",
@@ -60,7 +60,7 @@
6060
"ajv": "^6.4.0",
6161
"ajv-keywords": "^3.4.0",
6262
"body-parser": "^1.18.2",
63-
"bodybuilder": "2.2.13",
63+
"bodybuilder": "2.2.21",
6464
"commander": "^2.19.0",
6565
"compression": "^1.7.2",
6666
"config": "^1.30.0",
@@ -96,7 +96,7 @@
9696
"resource-router-middleware": "^0.6.0",
9797
"sharp": "^0.23.4",
9898
"soap": "^0.25.0",
99-
"storefront-query-builder": "^0.0.9",
99+
"storefront-query-builder": "^1.0.0",
100100
"syswide-cas": "latest",
101101
"winston": "^2.4.2"
102102
},

src/api/catalog.ts

Lines changed: 53 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import cache from '../lib/cache-instance'
66
import { sha3_224 } from 'js-sha3'
77
import AttributeService from './attribute/service'
88
import bodybuilder from 'bodybuilder'
9+
import loadCustomFilters from '../helpers/loadCustomFilters'
910
import { elasticsearch, SearchQuery } from 'storefront-query-builder'
11+
import { apiError } from '../lib/util'
1012

1113
function _cacheStorageHandler (config, result, hash, tags) {
1214
if (config.server.useOutputCache && cache) {
@@ -54,7 +56,8 @@ export default ({config, db}) => async function (req, res, body) {
5456
}
5557

5658
if (req.query.request_format === 'search-query') { // search query and not Elastic DSL - we need to translate it
57-
requestBody = await elasticsearch.buildQueryBodyFromSearchQuery({ config, queryChain: bodybuilder(), searchQuery: new SearchQuery(requestBody) })
59+
const customFilters = await loadCustomFilters(config)
60+
requestBody = await elasticsearch.buildQueryBodyFromSearchQuery({ config, queryChain: bodybuilder(), searchQuery: new SearchQuery(requestBody), customFilters })
5861
}
5962
if (req.query.response_format) responseFormat = req.query.response_format
6063

@@ -109,64 +112,55 @@ export default ({config, db}) => async function (req, res, body) {
109112
body: requestBody,
110113
json: true,
111114
auth: auth
112-
}, (_err, _res, _resBody) => { // TODO: add caching layer to speed up SSR? How to invalidate products (checksum on the response BEFORE processing it)
113-
if (_resBody && _resBody.hits && _resBody.hits.hits) { // we're signing up all objects returned to the client to be able to validate them when (for example order)
114-
const factory = new ProcessorFactory(config)
115-
const tagsArray = []
116-
if (config.server.useOutputCache && cache) {
117-
const tagPrefix = entityType[0].toUpperCase() // first letter of entity name: P, T, A ...
118-
tagsArray.push(entityType)
119-
_resBody.hits.hits.map(item => {
120-
if (item._source.id) { // has common identifier
121-
tagsArray.push(`${tagPrefix}${item._source.id}`)
122-
}
123-
})
124-
}
125-
126-
let resultProcessor = factory.getAdapter(entityType, indexName, req, res)
127-
128-
if (!resultProcessor) { resultProcessor = factory.getAdapter('default', indexName, req, res) } // get the default processor
129-
if (entityType === 'product') {
130-
resultProcessor.process(_resBody.hits.hits, groupId).then(async (result) => {
131-
_resBody.hits.hits = result
132-
if (config.get('varnish.enabled')) {
133-
// Add tags to cache, so we can display them in response headers then
134-
_cacheStorageHandler(config, {
135-
..._resBody,
136-
tags: tagsArray
137-
}, reqHash, tagsArray)
138-
} else {
139-
_cacheStorageHandler(config, _resBody, reqHash, tagsArray)
140-
}
141-
if (_resBody.aggregations && config.entities.attribute.loadByAttributeMetadata) {
142-
const attributeListParam = AttributeService.transformAggsToAttributeListParam(_resBody.aggregations)
143-
// find attribute list
144-
const attributeList = await AttributeService.list(attributeListParam, config, indexName)
145-
_resBody.attribute_metadata = attributeList.map(AttributeService.transformToMetadata)
146-
}
147-
res.json(_outputFormatter(_resBody, responseFormat));
148-
}).catch((err) => {
149-
console.error(err)
150-
})
151-
} else {
152-
resultProcessor.process(_resBody.hits.hits).then((result) => {
153-
_resBody.hits.hits = result
154-
if (config.get('varnish.enabled')) {
155-
// Add tags to cache, so we can display them in response headers then
156-
_cacheStorageHandler(config, {
157-
..._resBody,
158-
tags: tagsArray
159-
}, reqHash, tagsArray)
160-
} else {
161-
_cacheStorageHandler(config, _resBody, reqHash, tagsArray)
162-
}
163-
res.json(_outputFormatter(_resBody, responseFormat));
164-
}).catch((err) => {
165-
console.error(err)
166-
})
115+
}, async (_err, _res, _resBody) => { // TODO: add caching layer to speed up SSR? How to invalidate products (checksum on the response BEFORE processing it)
116+
if (_err || _resBody.error) {
117+
apiError(res, _err || _resBody.error);
118+
return
119+
}
120+
try {
121+
if (_resBody && _resBody.hits && _resBody.hits.hits) { // we're signing up all objects returned to the client to be able to validate them when (for example order)
122+
const factory = new ProcessorFactory(config)
123+
const tagsArray = []
124+
if (config.server.useOutputCache && cache) {
125+
const tagPrefix = entityType[0].toUpperCase() // first letter of entity name: P, T, A ...
126+
tagsArray.push(entityType)
127+
_resBody.hits.hits.map(item => {
128+
if (item._source.id) { // has common identifier
129+
tagsArray.push(`${tagPrefix}${item._source.id}`)
130+
}
131+
})
132+
const cacheTags = tagsArray.join(' ')
133+
res.setHeader('X-VS-Cache-Tags', cacheTags)
134+
}
135+
136+
let resultProcessor = factory.getAdapter(entityType, indexName, req, res)
137+
138+
if (!resultProcessor) { resultProcessor = factory.getAdapter('default', indexName, req, res) } // get the default processor
139+
140+
const productGroupId = entityType === 'product' ? groupId : undefined
141+
const result = await resultProcessor.process(_resBody.hits.hits, productGroupId)
142+
_resBody.hits.hits = result
143+
if (entityType === 'product' && _resBody.aggregations && config.entities.attribute.loadByAttributeMetadata) {
144+
const attributeListParam = AttributeService.transformAggsToAttributeListParam(_resBody.aggregations)
145+
// find attribute list
146+
const attributeList = await AttributeService.list(attributeListParam, config, indexName)
147+
_resBody.attribute_metadata = attributeList.map(AttributeService.transformToMetadata)
148+
}
149+
if (config.get('varnish.enabled')) {
150+
// Add tags to cache, so we can display them in response headers then
151+
_cacheStorageHandler(config, {
152+
..._resBody,
153+
tags: tagsArray
154+
}, reqHash, tagsArray)
155+
} else {
156+
_cacheStorageHandler(config, _resBody, reqHash, tagsArray)
157+
}
158+
res.json(_outputFormatter(_resBody, responseFormat));
159+
} else { // no cache storage if no results from Elastic
160+
res.json(_resBody);
167161
}
168-
} else { // no cache storage if no results from Elastic
169-
res.json(_resBody);
162+
} catch (err) {
163+
apiError(res, err);
170164
}
171165
});
172166
}
@@ -182,7 +176,7 @@ export default ({config, db}) => async function (req, res, body) {
182176
res.setHeader('X-VS-Cache-Tag', tagsHeader)
183177
delete output.tags
184178
}
185-
res.json(output)
179+
res.json(_outputFormatter(output, responseFormat));
186180
console.log(`cache hit [${req.url}], cached request: ${Date.now() - s}ms`)
187181
} else {
188182
res.setHeader('X-VS-Cache', 'Miss')
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { FilterInterface } from 'storefront-query-builder'
2+
3+
const filter: FilterInterface = {
4+
priority: 1,
5+
check: ({ operator, value, attribute, queryChain }) => attribute === 'custom-filter-name',
6+
filter ({ value, attribute, operator, queryChain }) {
7+
// Do you custom filter logic like: queryChain.filter('terms', attribute, value)
8+
return queryChain
9+
},
10+
mutator: (value) => typeof value !== 'object' ? { 'in': [value] } : value
11+
}
12+
13+
export default filter
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { Router } from 'express'
2+
3+
module.exports = () => {
4+
let exampleFilter = Router()
5+
return exampleFilter
6+
}

src/helpers/loadCustomFilters.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import path from 'path'
2+
3+
export default async function loadModuleCustomFilters (config: Record<string, any>, type: string = 'catalog'): Promise<any> {
4+
let filters: any = {}
5+
let filterPromises: Promise<any>[] = []
6+
7+
for (const mod of config.registeredExtensions) {
8+
if (config.extensions.hasOwnProperty(mod) && config.extensions[mod].hasOwnProperty(type + 'Filter') && Array.isArray(config.extensions[mod][type + 'Filter'])) {
9+
const moduleFilter = config.extensions[mod][type + 'Filter']
10+
const dirPath = [__dirname, '../api/extensions/' + mod + '/filter/', type]
11+
for (const filterName of moduleFilter) {
12+
const filePath = path.resolve(...dirPath, filterName)
13+
filterPromises.push(
14+
import(filePath)
15+
.then(module => {
16+
filters[filterName] = module.default
17+
})
18+
.catch(e => {
19+
console.log(e)
20+
})
21+
)
22+
}
23+
}
24+
}
25+
26+
return Promise.all(filterPromises).then((e) => filters)
27+
}

src/lib/util.js

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -78,15 +78,22 @@ export function apiStatus (res, result = 'OK', code = 200, meta = null) {
7878
return result;
7979
}
8080

81-
/** Creates a api error status Express Response object.
82-
* @param {express.Response} res Express HTTP Response
83-
* @param {number} [code=200] Status code to send on success
84-
* @param {json} [result='OK'] Text message or result information object
81+
/**
82+
* Creates an error for API status of Express Response object.
83+
*
84+
* @param {express.Response} res Express HTTP Response
85+
* @param {object|string} error Error object or error message
86+
* @return {json} [result='OK'] Text message or result information object
8587
*/
86-
export function apiError (res, errorObj, code = 500) {
87-
const result = errorObj.message ? errorObj.message : (errorObj.errorMessage ? errorObj.errorMessage : errorObj);
88-
const resultCode = errorObj.code ? errorObj.code : code;
89-
return apiStatus(res, result, resultCode)
88+
export function apiError (res, error) {
89+
let errorCode = error.code || error.status || 500;
90+
let errorMessage = error.errorMessage || error;
91+
if (error instanceof Error) {
92+
// Class 'Error' is not serializable with JSON.stringify, extract data explicitly.
93+
errorCode = error.code || errorCode;
94+
errorMessage = error.message;
95+
}
96+
return apiStatus(res, errorMessage, errorCode);
9097
}
9198

9299
export function encryptToken (textToken, secret) {

src/models/order.schema.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ exports.default = {
142142
type: 'number'
143143
},
144144
save_address: {
145-
type: 'number'
145+
type: 'number'
146146
}
147147
}
148148
},
@@ -208,7 +208,7 @@ exports.default = {
208208
type: 'number'
209209
},
210210
save_address: {
211-
type: 'number'
211+
type: 'number'
212212
}
213213
}
214214
}

0 commit comments

Comments
 (0)