hexo-azuresearch
Advanced tools
Comparing version 1.0.0 to 1.1.0
'use strict'; | ||
var azuresearch = require('./lib/azuresearch'); | ||
const AzureSearch = require('./lib/azuresearch'); | ||
hexo.extend.console.register('azuresearch', 'Index posts on Azure Search', { | ||
options: [] | ||
}, azuresearch); | ||
}, (options, callback) => { | ||
AzureSearch(hexo, options, callback); | ||
}); |
@@ -0,18 +1,128 @@ | ||
const HexoUtil = require('hexo-util'); | ||
const Axios = require('axios'); | ||
/** | ||
* Index Hexo posts and upload to Azure Search | ||
* Based on hexo-algoliasearch (https://github.com/LouisBarranqueiro/hexo-algoliasearch) | ||
* @param args {Object} | ||
* @param callback {Function} | ||
* Extract a list type metadata from an Hexo post. | ||
* @param {object} post a hexo post object | ||
* @param {prop} prop property name e.g. tags | ||
*/ | ||
function AzureSearch(args, callback) { | ||
var _ = require('lodash'); | ||
var hexoUtil = require('hexo-util'); | ||
var async = require('async'); | ||
var request = require('request'); | ||
var Q = require('q'); | ||
const transformListProp = (post, prop) => { | ||
const items = []; | ||
Object.keys(post[prop].data).forEach(item => { | ||
if (item.name) { | ||
items.push(item.name); | ||
} | ||
}); | ||
return items; | ||
} | ||
var hexo = this; | ||
var config = hexo.config.AzureSearch; | ||
var log = hexo.log; | ||
var fields = [ | ||
/** | ||
* Trnasform a Hexo post to an AzureSearch document. | ||
* @param {object} post a hexo post object | ||
* @prarm {object} config azure search config | ||
* @return post | ||
*/ | ||
const transformPost = (post, config) => { | ||
return { | ||
postId: post.slug, | ||
permalink: post.permalink, | ||
path: post.path, | ||
title: post.title, | ||
date: post.date.format('YYYY-MM-DDTHH:mm:ss.SSSZ'), | ||
excerpt: post.excerpt || HexoUtil.truncate(HexoUtil.stripHTML(post.content), { | ||
length: config.excerptLimit || 200, | ||
omission: '...', | ||
separator: '' | ||
}), | ||
tags: transformListProp(post, 'tags'), | ||
categories: transformListProp(post, 'categories'), | ||
'@search.action': 'mergeOrUpload' | ||
}; | ||
object.tags = getProperty(post, 'tags'); | ||
object.categories = getProperty(post, 'categories'); | ||
return object; | ||
} | ||
/** | ||
* Create or update an AzureSearch index. | ||
* @param hexo | ||
* @param indexFields | ||
* @param config | ||
* @returns {Promise<*>} | ||
*/ | ||
const putIndex = async (hexo, indexFields, config) => { | ||
const { serviceURL, serviceUrl, indexName, apiVersion, adminKey } = config; | ||
const url = `${serviceURL || serviceUrl}/indexes/${indexName}?api-version=${apiVersion}`; | ||
const headers = { | ||
'api-key': config.adminKey, | ||
'Content-Type': 'application/json' | ||
}; | ||
try { | ||
const response = await Axios({ | ||
method: 'put', | ||
url, | ||
headers, | ||
data: { | ||
name: indexName, | ||
fields: indexFields, | ||
corsOptions: { | ||
allowedOrigins: ['*'], | ||
maxAgeInSeconds: 300 | ||
} | ||
}, | ||
}); | ||
hexo.log.info('AzureSearch created index.'); | ||
if (config.verbose) { | ||
hexo.log.info(JSON.stringify(response.data)); | ||
} | ||
return Promise.resolve(response); | ||
} catch (e) { | ||
hexo.log.error('AzureSearch failed to put index.'); | ||
hexo.log.error(e); | ||
hexo.log.error(JSON.stringify(e.response.data)); | ||
return Promise.reject(e); | ||
} | ||
}; | ||
/** | ||
* Index a post to AzureSearch. | ||
* @param hexo | ||
* @param posts | ||
* @param config | ||
* @returns {Promise<void|any>} | ||
*/ | ||
const indexDocuments = async (hexo, posts, config) => { | ||
const { serviceURL, serviceUrl, indexName, apiVersion, adminKey } = config; | ||
const url = `${serviceURL || serviceUrl}/indexes/${indexName}/docs/index?api-version=${apiVersion}`; | ||
const headers = { | ||
'api-key': config.adminKey, | ||
'Content-Type': 'application/json' | ||
}; | ||
try { | ||
const response = await Axios({ | ||
method: 'post', | ||
url, | ||
headers, | ||
data: { | ||
value: posts | ||
}, | ||
}); | ||
hexo.log.info('AzureSearch indexed documents.'); | ||
if (config.verbose) { | ||
hexo.log.info(JSON.stringify(response.data)); | ||
} | ||
return Promise.resolve(response); | ||
} catch (e) { | ||
hexo.log.error('AzureSearch failed to index documents.'); | ||
hexo.log.error(JSON.stringify(e.response.data)); | ||
return Promise.reject(e); | ||
} | ||
}; | ||
const AzureSearch = async (hexo, args, callback) => { | ||
const config = { | ||
...hexo.config.AzureSearch, | ||
apiVersion: '2019-05-06' | ||
}; | ||
const fields = [ | ||
{ | ||
@@ -103,172 +213,39 @@ "name": "postId", | ||
]; | ||
var fieldList = ['title', 'date', 'excerpt', 'permalink', 'path', 'tags', 'categories']; | ||
var posts = []; | ||
config.apiVersion = "2015-02-28"; | ||
const fieldNames = fields.map(field => field.name); | ||
const posts = []; | ||
/** | ||
* Process a post | ||
* @param post {Object} a hexo post object | ||
* @return post {Object} a post extracted object for algolia | ||
*/ | ||
function processPost(post) { | ||
var key = null; | ||
var object = {}; | ||
hexo.extend.filter.register('after_post_render', function(post) { | ||
if (post.published) { | ||
posts.push(transformPost(post, config)); | ||
} | ||
return post; | ||
}); | ||
object = _.pick(post, fieldList); | ||
object['@search.action'] = 'mergeOrUpload'; | ||
object.postId = post.slug; | ||
object.tags = getProperty(post, 'tags'); | ||
object.categories = getProperty(post, 'categories'); | ||
object.date = post.date.format('YYYY-MM-DDTHH:mm:ss.SSSZ'); | ||
object.excerpt = hexoUtil.truncate(hexoUtil.stripHTML(post.content), { | ||
length: config.excerptLimit || 200, | ||
omission: "...", | ||
separator: "" | ||
}); | ||
return object; | ||
} | ||
const log = hexo.log; | ||
/** | ||
* Extract a given property from an hexo post object | ||
* @param post {Object} a hexo post object | ||
* @param property {String} a property name of hexo post objects | ||
*/ | ||
function getProperty(post, property) { | ||
var tags = []; | ||
for (var key in post[property].data) { | ||
if (post[property].data.hasOwnProperty(key)) { | ||
if (post[property].data[key].hasOwnProperty('name')) { | ||
tags.push(post[property].data[key].name); | ||
} | ||
} | ||
log.info('AzureSearch is claning up posts...'); | ||
hexo.call('clean', (err) => { | ||
if (err) { | ||
log.info('AzureSearch failed to clean up posts : ' + err); | ||
return callback(err); | ||
} | ||
return tags; | ||
} | ||
/** | ||
* Delete the existing index on azure search | ||
* no param | ||
*/ | ||
function deleteIndex() { | ||
var deferred = Q.defer(); | ||
var url = config.serviceURL + '/indexes/' +config.indexName+ '?api-version=' +config.apiVersion; | ||
var headers = { | ||
'api-key': config.adminKey, | ||
'Content-type': 'application/json' | ||
}; | ||
var options = { | ||
url: url, | ||
headers: headers, | ||
withCredentials: false | ||
}; | ||
request.del(options, function(error, response, body) { | ||
log.info('delete index result: ' + response.statusCode); | ||
log.info(body); | ||
deferred.resolve(); | ||
}); | ||
return deferred.promise; | ||
} | ||
/** | ||
* Create a new index on azure search | ||
* no param | ||
*/ | ||
function createIndex() { | ||
var deferred = Q.defer(); | ||
var url = config.serviceURL + "/indexes/" +config.indexName+ "?api-version=" +config.apiVersion; | ||
var headers = { | ||
'api-key': config.adminKey, | ||
'Content-Type': 'application/json' | ||
}; | ||
var options = { | ||
url: url, | ||
headers: headers, | ||
body: JSON.stringify({ | ||
"name": config.indexName, | ||
"fields": fields, | ||
"scoringProfiles": [], | ||
"defaultScoringProfile": null, | ||
"corsOptions": { | ||
"allowedOrigins": ["*"], | ||
"maxAgeInSeconds": 300 | ||
}, | ||
"suggesters": [] | ||
}), | ||
withCredentials: false | ||
}; | ||
request.put(options, function(error, response, body){ | ||
log.info("create index result: " + response.statusCode); | ||
log.info(body); | ||
deferred.resolve(); | ||
}); | ||
return deferred.promise; | ||
} | ||
/** | ||
* Upload generated posts data to Azure Search | ||
* no param | ||
*/ | ||
function uploadData() { | ||
var deferred = Q.defer(); | ||
var url = config.serviceURL + '/indexes/' +config.indexName+ "/docs/index?api-version=" +config.apiVersion; | ||
var headers = { | ||
'api-key': config.adminKey, | ||
'Content-type': 'application/json' | ||
}; | ||
var options = { | ||
url: url, | ||
headers: headers, | ||
body: JSON.stringify({ | ||
"value": posts | ||
}), | ||
withCredentials: false | ||
}; | ||
request.post(options, function(error, response, body) { | ||
log.info("upload posts result: " + response.statusCode); | ||
log.info(body); | ||
if (response.statusCode === 200) { | ||
log.info("Successfully uploaded index data to Azure Search."); | ||
hexo.call('generate', {}).then(async (err) => { | ||
if (err) { | ||
log.info('AzureSearch failed to generate posts : ' + err); | ||
return callback(err); | ||
} | ||
deferred.resolve(); | ||
}); | ||
return deferred.promise; | ||
} | ||
log.info(`AzureSearch collected ${posts.length} posts.`); | ||
/** | ||
* Initialization | ||
* no param | ||
*/ | ||
function init() { | ||
hexo.extend.filter.register('after_post_render', function(post) { | ||
if (post.published) { | ||
posts.push(processPost(post)); | ||
try { | ||
await putIndex(hexo, fields, config); | ||
await indexDocuments(hexo, posts, config); | ||
} catch (e) { | ||
log.error('AzureSearch exit due to error'); | ||
} | ||
return post; | ||
}); | ||
}); | ||
}; | ||
log.info('Clearing posts ...'); | ||
hexo.call('clean', function(err) { | ||
if (err) { | ||
log.info('Failed to clear posts : ' + err); | ||
return callback(err); | ||
} | ||
hexo.call('generate', {}).then(function(err) { | ||
if (err) { | ||
log.info('Failed to generate posts : ' + err); | ||
return callback(err); | ||
} | ||
log.info(posts.length + ' posts collected.'); | ||
deleteIndex() | ||
.then(createIndex) | ||
.then(uploadData); | ||
}); | ||
}); | ||
} | ||
init(); | ||
} | ||
module.exports = AzureSearch; | ||
module.exports = AzureSearch; |
{ | ||
"name": "hexo-azuresearch", | ||
"version": "1.0.0", | ||
"version": "1.1.0", | ||
"description": "Azure search support for Hexo.", | ||
"main": "index.js", | ||
"scripts": {}, | ||
"scripts": { | ||
"release": "standard-version" | ||
}, | ||
"repository": { | ||
@@ -12,5 +14,6 @@ "type": "git", | ||
"keywords": [ | ||
"hexo", | ||
"hexo-plugin", | ||
"azure", | ||
"search", | ||
"hexo" | ||
"search" | ||
], | ||
@@ -27,8 +30,8 @@ "author": { | ||
"dependencies": { | ||
"async": "^2.0.1", | ||
"hexo-util": "^0.6.0", | ||
"lodash": "^4.15.0", | ||
"q": "^1.4.1", | ||
"request": "^2.74.0" | ||
"axios": "^0.19.2", | ||
"hexo-util": "^2.1.0" | ||
}, | ||
"devDependencies": { | ||
"standard-version": "^8.0.0" | ||
} | ||
} |
@@ -28,6 +28,6 @@ # hexo-azuresearch | ||
This command will automatically first clean then re-generate your hexo site. You DON'T need to `hexo clean` first. | ||
This command will automatically re-generate the hexo site. You don't need to `hexo clean`. | ||
```bash | ||
hexo azuresearch | ||
``` | ||
``` |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
2
33
9542
1
244
1
+ Addedaxios@^0.19.2
+ Addedaxios@0.19.2(transitive)
+ Addedcamel-case@4.1.2(transitive)
+ Addedcross-spawn@7.0.6(transitive)
+ Addeddeepmerge@4.3.1(transitive)
+ Addeddom-serializer@1.4.1(transitive)
+ Addeddomelementtype@2.3.0(transitive)
+ Addeddomhandler@4.3.1(transitive)
+ Addeddomutils@2.8.0(transitive)
+ Addedentities@2.2.03.0.1(transitive)
+ Addedfollow-redirects@1.5.10(transitive)
+ Addedhexo-util@2.7.0(transitive)
+ Addedhighlight.js@11.11.0(transitive)
+ Addedhtmlparser2@7.2.0(transitive)
+ Addedlower-case@2.0.2(transitive)
+ Addedmin-indent@1.0.1(transitive)
+ Addedno-case@3.0.4(transitive)
+ Addedpascal-case@3.1.2(transitive)
+ Addedpath-key@3.1.1(transitive)
+ Addedprismjs@1.29.0(transitive)
+ Addedshebang-command@2.0.0(transitive)
+ Addedshebang-regex@3.0.0(transitive)
+ Addedstrip-indent@3.0.0(transitive)
+ Addedtslib@2.8.1(transitive)
+ Addedwhich@2.0.2(transitive)
- Removedasync@^2.0.1
- Removedlodash@^4.15.0
- Removedq@^1.4.1
- Removedrequest@^2.74.0
- Removedajv@6.12.6(transitive)
- Removedasn1@0.2.6(transitive)
- Removedassert-plus@1.0.0(transitive)
- Removedasync@2.6.4(transitive)
- Removedasynckit@0.4.0(transitive)
- Removedaws-sign2@0.7.0(transitive)
- Removedaws4@1.13.2(transitive)
- Removedbcrypt-pbkdf@1.0.2(transitive)
- Removedcamel-case@3.0.0(transitive)
- Removedcaseless@0.12.0(transitive)
- Removedcombined-stream@1.0.8(transitive)
- Removedcore-util-is@1.0.2(transitive)
- Removedcross-spawn@4.0.2(transitive)
- Removeddashdash@1.14.1(transitive)
- Removeddelayed-stream@1.0.0(transitive)
- Removedecc-jsbn@0.1.2(transitive)
- Removedextend@3.0.2(transitive)
- Removedextsprintf@1.3.0(transitive)
- Removedfast-deep-equal@3.1.3(transitive)
- Removedfast-json-stable-stringify@2.1.0(transitive)
- Removedforever-agent@0.6.1(transitive)
- Removedform-data@2.3.3(transitive)
- Removedgetpass@0.1.7(transitive)
- Removedhar-schema@2.0.0(transitive)
- Removedhar-validator@5.1.5(transitive)
- Removedhexo-util@0.6.3(transitive)
- Removedhighlight.js@9.18.5(transitive)
- Removedhtml-entities@1.4.0(transitive)
- Removedhttp-signature@1.2.0(transitive)
- Removedis-typedarray@1.0.0(transitive)
- Removedisstream@0.1.2(transitive)
- Removedjsbn@0.1.1(transitive)
- Removedjson-schema@0.4.0(transitive)
- Removedjson-schema-traverse@0.4.1(transitive)
- Removedjson-stringify-safe@5.0.1(transitive)
- Removedjsprim@1.4.2(transitive)
- Removedlodash@4.17.21(transitive)
- Removedlower-case@1.1.4(transitive)
- Removedlru-cache@4.1.5(transitive)
- Removedmime-db@1.52.0(transitive)
- Removedmime-types@2.1.35(transitive)
- Removedno-case@2.3.2(transitive)
- Removedoauth-sign@0.9.0(transitive)
- Removedperformance-now@2.1.0(transitive)
- Removedpseudomap@1.0.2(transitive)
- Removedpsl@1.15.0(transitive)
- Removedpunycode@2.3.1(transitive)
- Removedq@1.5.1(transitive)
- Removedqs@6.5.3(transitive)
- Removedrequest@2.88.2(transitive)
- Removedsafe-buffer@5.2.1(transitive)
- Removedsafer-buffer@2.1.2(transitive)
- Removedsshpk@1.18.0(transitive)
- Removedstriptags@2.2.1(transitive)
- Removedtough-cookie@2.5.0(transitive)
- Removedtunnel-agent@0.6.0(transitive)
- Removedtweetnacl@0.14.5(transitive)
- Removedupper-case@1.1.3(transitive)
- Removeduri-js@4.4.1(transitive)
- Removeduuid@3.4.0(transitive)
- Removedverror@1.10.0(transitive)
- Removedwhich@1.3.1(transitive)
- Removedyallist@2.1.2(transitive)
Updatedhexo-util@^2.1.0