Add endpoint for full-text search (#6)
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone Build is passing

This commit is contained in:
Garrett Mills 2020-10-12 21:46:50 -05:00
parent 273460b126
commit e55720e3bb
Signed by: garrettmills
GPG Key ID: D2BF5FBA8298F246
7 changed files with 100 additions and 7 deletions

View File

@ -5,7 +5,7 @@ const path = require('path')
class IonicUnit extends Unit { class IonicUnit extends Unit {
static get services() { static get services() {
return [...super.services, 'configs', 'express', 'canon', 'utility'] return [...super.services, 'configs', 'express', 'canon', 'utility', 'scaffold']
} }
constructor(...args) { constructor(...args) {
@ -33,6 +33,16 @@ class IonicUnit extends Unit {
}, },
Express.static(this.directory), Express.static(this.directory),
]) ])
// Create the full-text search indices
const pages = this.scaffold.collection('api_Page')
await pages.createIndex({ Name: 'text' })
const nodes = this.scaffold.collection('api_Node')
await nodes.createIndex({ 'Value.Value': 'text' })
const databases = this.scaffold.collection('api_db_Database')
await databases.createIndex({ Name: 'text' })
} }
} }

View File

@ -20,6 +20,57 @@ class Misc extends Controller {
return res.api(token.token) return res.api(token.token)
} }
async get_search(req, res, next) {
if ( !req.query.query ) {
return res.status(400)
.message('Missing query.')
.api()
}
const query = String(req.query.query)
const Page = this.models.get('api:Page')
const Node = this.models.get('api:Node')
const all_user_page_ids = (await req.user.get_accessible_pages()).map(x => x.UUID)
const results = []
const matching_pages = await Page.find({
UUID: { $in: all_user_page_ids },
Active: true,
$text: { $search: query },
})
for ( const page of matching_pages ) {
results.push({
title: page.Name,
type: 'page',
id: page.UUID,
})
}
const matching_nodes = await Node.find({
PageId: { $in: all_user_page_ids },
'Value.Mode': 'norm',
$text: { $search: query }
})
for ( const node of matching_nodes ) {
const page = await node.page
results.push({
title: node.Value.Value,
type: 'node',
id: node.UUID,
associated: {
title: page.Name,
type: 'page',
id: page.UUID,
}
})
}
return res.api({results})
}
} }
module.exports = exports = Misc module.exports = exports = Misc

View File

@ -31,7 +31,7 @@ class Node extends Model {
// Static and instance methods can go here // Static and instance methods can go here
get page() { get page() {
const Page = this.models.get('api:Page') const Page = this.models.get('api:Page')
return this.belongs_to_one(Page, "PageId", "_id") return this.belongs_to_one(Page, "PageId", "UUID")
} }
to_html() { to_html() {

View File

@ -21,6 +21,36 @@ class User extends AuthUser {
return Page.findOne({OrgUserId: this._id, ParentId: '0'}) return Page.findOne({OrgUserId: this._id, ParentId: '0'})
} }
async get_accessible_pages() {
const Page = this.models.get('api:Page')
const user_page = await this.get_root_page()
const user_pages = await user_page.visible_flat_children(this)
let view_pages = await Page.find({ shared_users_view: this._id })
for ( const page of view_pages ) {
view_pages = [...view_pages, ...(await page.visible_flat_children(this))]
}
let update_pages = await Page.find({ shared_users_update: this._id })
for ( const page of update_pages ) {
update_pages = [...update_pages, ...(await page.visible_flat_children(this))]
}
let manage_pages = await Page.find({ shared_users_manage: this._id })
for ( const page of manage_pages ) {
manage_pages = [...manage_pages, ...(await page.visible_flat_children(this))]
}
const all_pages = [...user_pages, ...view_pages, ...update_pages, ...manage_pages].filter(x => !x.virtual)
const uniq_page_obj = {}
for ( const page of all_pages ) {
uniq_page_obj[page.UUID] = page
}
return Object.values(uniq_page_obj)
}
// Other members and methods here // Other members and methods here
} }

View File

@ -45,6 +45,8 @@ const index = {
// Export the entire personal tree as HTML // Export the entire personal tree as HTML
'/data/export/html': ['controller::Export.html_export'], '/data/export/html': ['controller::Export.html_export'],
'/search': ['controller::api:v1:Misc.get_search'],
}, },
post: { post: {

View File

@ -25,6 +25,6 @@
"flitter-orm": "^0.4.0", "flitter-orm": "^0.4.0",
"flitter-upload": "^0.8.1", "flitter-upload": "^0.8.1",
"jsonwebtoken": "^8.5.1", "jsonwebtoken": "^8.5.1",
"libflitter": "^0.54.0" "libflitter": "^0.54.1"
} }
} }

View File

@ -2443,10 +2443,10 @@ leven@^1.0.2:
resolved "https://registry.yarnpkg.com/leven/-/leven-1.0.2.tgz#9144b6eebca5f1d0680169f1a6770dcea60b75c3" resolved "https://registry.yarnpkg.com/leven/-/leven-1.0.2.tgz#9144b6eebca5f1d0680169f1a6770dcea60b75c3"
integrity sha1-kUS27ryl8dBoAWnxpncNzqYLdcM= integrity sha1-kUS27ryl8dBoAWnxpncNzqYLdcM=
libflitter@^0.54.0: libflitter@^0.54.1:
version "0.54.0" version "0.54.1"
resolved "https://registry.yarnpkg.com/libflitter/-/libflitter-0.54.0.tgz#5758fd0069de0ed75a80385c66809078b8210c36" resolved "https://registry.yarnpkg.com/libflitter/-/libflitter-0.54.1.tgz#e866677dd1fec1717876e1700b6d95bc2db51e0e"
integrity sha512-/pRgUD5dXdpEPxR6B3Do5BZQTGLrTYj3u0ZxYr7GViB4NysLePkR8Vg3gBzuNYUkEznzWxDR8VcmtuIiEowhFw== integrity sha512-vPFJenYWhePboGBhU5Dc6UkxxNOFzlxnfppjGpp3JSPDJ5b7M7wykLL1k5pi8RVTT859Js9CIqI1NoqH+cTdaw==
dependencies: dependencies:
colors "^1.3.3" colors "^1.3.3"
connect-mongodb-session "^2.2.0" connect-mongodb-session "^2.2.0"