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

Commit abf8043

Browse files
committed
Merge remote-tracking branch 'upstream/develop' into HEAD
2 parents cbe25db + 7a97ad4 commit abf8043

File tree

7 files changed

+139
-2
lines changed

7 files changed

+139
-2
lines changed

CHANGELOG.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,18 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7-
## [1.11.0] - unreleased
7+
8+
## [1.12.0-rc1] - UNRELEASED
9+
10+
### Added
11+
- Add url module - @gibkigonzo (#3942)
12+
13+
### Fixed
14+
15+
### Changed / Improved
16+
17+
18+
## [1.11.0] - 2019.12.20
819

920
### Fixed
1021

config/default.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,5 +282,12 @@
282282
"description": 1,
283283
"sku": 1,
284284
"configurable_children.sku": 1
285+
},
286+
"urlModule": {
287+
"map": {
288+
"includeFields": ["url_path", "identifier", "id", "slug", "sku", "type_id"],
289+
"searchedFields": ["url_path", "identifier"],
290+
"searchedEntities": ["product", "category", "cms_page"]
291+
}
285292
}
286293
}

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
"private": true,
55
"description": "vue-storefront API and data services",
66
"main": "dist",
7+
"engines": {
8+
"node": ">=10.x"
9+
},
710
"scripts": {
811
"dev": "nodemon",
912
"dev:inspect": "nodemon --exec \"node --inspect -r ts-node/register src\"",

src/api/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import review from './review';
88
import cart from './cart';
99
import product from './product';
1010
import sync from './sync';
11+
import url from './url';
1112

1213
export default ({ config, db }) => {
1314
let api = Router();
@@ -36,6 +37,9 @@ export default ({ config, db }) => {
3637
// mount the sync resource
3738
api.use('/sync', sync({ config, db }))
3839

40+
// mount the url resource
41+
api.use('/url', url({ config, db }))
42+
3943
// perhaps expose some API metadata at the root
4044
api.get('/', (req, res) => {
4145
res.json({ version });

src/api/url/index.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { Router } from 'express';
2+
import createMapRoute from './map';
3+
4+
module.exports = ({ config }) => {
5+
const router = Router()
6+
7+
router.use('/map', createMapRoute({ config }))
8+
9+
return router
10+
}

src/api/url/map.js

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import { Router } from 'express';
2+
import { apiStatus } from '../../lib/util';
3+
import { buildMultiEntityUrl } from '../../lib/elastic';
4+
import request from 'request';
5+
import get from 'lodash/get';
6+
7+
/**
8+
* Builds ES query based on config
9+
*/
10+
const buildQuery = ({ value, config }) => {
11+
const searchedFields = get(config, 'urlModule.map.searchedFields', [])
12+
.map((field) => ({ match_phrase: { [field]: { query: value } } }))
13+
const searchedEntities = get(config, 'urlModule.map.searchedEntities', [])
14+
.map((entity) => ({ type: { value: entity } }))
15+
16+
return {
17+
query: {
18+
bool: {
19+
filter: {
20+
bool: {
21+
should: searchedFields,
22+
filter: {
23+
bool: {
24+
should: searchedEntities
25+
}
26+
}
27+
}
28+
}
29+
}
30+
},
31+
size: 1 // we need only one record
32+
}
33+
}
34+
35+
/**
36+
* checks result equality because ES can return record even if searched value is not EXACLY what we want (check `match_phrase` in ES docs)
37+
*/
38+
const checkFieldValueEquality = ({ config, response, value }) => {
39+
const isEqualValue = get(config, 'urlModule.map.searchedFields', [])
40+
.find((field) => response._source[field] === value)
41+
42+
return Boolean(isEqualValue)
43+
}
44+
45+
module.exports = ({ config }) => {
46+
const router = Router()
47+
router.post('/:index', (req, res) => {
48+
const { url, excludeFields, includeFields } = req.body
49+
if (!url) {
50+
return apiStatus(res, 'Missing url', 500);
51+
}
52+
53+
const esUrl = buildMultiEntityUrl({
54+
config,
55+
includeFields: includeFields ? includeFields.concat(get(config, 'urlModule.map.includeFields', [])) : [],
56+
excludeFields
57+
})
58+
const query = buildQuery({ value: url, config })
59+
60+
// Only pass auth if configured
61+
let auth = null;
62+
if (config.elasticsearch.user || config.elasticsearch.password) {
63+
auth = {
64+
user: config.elasticsearch.user,
65+
pass: config.elasticsearch.password
66+
}
67+
}
68+
69+
// make simple ES search
70+
request({
71+
uri: esUrl,
72+
method: 'POST',
73+
body: query,
74+
json: true,
75+
auth: auth
76+
}, (_err, _res, _resBody) => {
77+
if (_err) {
78+
console.log(_err)
79+
return apiStatus(res, new Error('ES search error'), 500);
80+
}
81+
const responseRecord = _resBody.hits.hits[0]
82+
if (responseRecord && checkFieldValueEquality({ config, response: responseRecord, value: req.body.url })) {
83+
return res.json(responseRecord)
84+
}
85+
res.json()
86+
})
87+
})
88+
89+
return router
90+
}

src/lib/elastic.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,17 @@ function adjustBackendProxyUrl (req, indexName, entityType, config) {
5151
return url
5252
}
5353

54+
/**
55+
* similar to `adjustBackendProxyUrl`, builds multi-entity query url
56+
*/
57+
function buildMultiEntityUrl ({ config, includeFields = [], excludeFields = [] }) {
58+
let url = `${config.elasticsearch.host}:${config.elasticsearch.port}/_search?_source_include=${includeFields.join(',')}&_source_exclude=${excludeFields.join(',')}`
59+
if (!url.startsWith('http')) {
60+
url = config.elasticsearch.protocol + '://' + url
61+
}
62+
return url
63+
}
64+
5465
function adjustQuery (esQuery, entityType, config) {
5566
if (parseInt(config.elasticsearch.apiVersion) < 6) {
5667
esQuery.type = entityType
@@ -261,5 +272,6 @@ module.exports = {
261272
getClient,
262273
getHits,
263274
adjustIndexName,
264-
putMappings
275+
putMappings,
276+
buildMultiEntityUrl
265277
}

0 commit comments

Comments
 (0)