Initial commit
This commit is contained in:
@@ -0,0 +1,282 @@
|
||||
const fs = require('fs')
|
||||
const xmlFlow = require('xml-flow')
|
||||
const xss = require('xss')
|
||||
const debug = require('debug')('termPortal:models/helpers/dictionary')
|
||||
const db = require('../../db')
|
||||
const { intoDbArray } = require('..')
|
||||
|
||||
const JOBS_MAX = 50
|
||||
const JOBS_MIN = 15
|
||||
|
||||
// Import given file into given dictionary.
|
||||
exports.readFileIntoDb = (
|
||||
userId,
|
||||
dictionaryId,
|
||||
importFilePath,
|
||||
entryStatus,
|
||||
dbClient
|
||||
) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const progress = {
|
||||
jobCount: 0,
|
||||
totalCount: 0,
|
||||
validCount: 0,
|
||||
isWholeFileRead: false,
|
||||
importError: null
|
||||
}
|
||||
entryStatus = entryStatus === 'complete' ? 'complete' : 'in_edit'
|
||||
const importFileReader = fs.createReadStream(importFilePath)
|
||||
const xmlStream = xmlFlow(importFileReader, {
|
||||
strict: true,
|
||||
trim: false,
|
||||
preserveMarkup: xmlFlow.ALWAYS,
|
||||
simplifyNodes: false,
|
||||
useArrays: xmlFlow.ALWAYS
|
||||
})
|
||||
const handleError = handleImportError(xmlStream, progress, reject)
|
||||
const handleEntry = handleEntryXml(
|
||||
userId,
|
||||
dictionaryId,
|
||||
entryStatus,
|
||||
progress,
|
||||
dbClient,
|
||||
resolve,
|
||||
handleError
|
||||
)
|
||||
|
||||
xmlStream
|
||||
.on('error', () => {})
|
||||
.once('error', handleError)
|
||||
.on('end', () => (progress.isWholeFileRead = true))
|
||||
.on('tag:entry', handleEntry)
|
||||
})
|
||||
}
|
||||
|
||||
function handleImportError(xmlStream, progress, reject) {
|
||||
return function handleError(error) {
|
||||
if (progress.importError) return
|
||||
|
||||
progress.importError = error
|
||||
xmlStream.removeAllListeners('tag:entry')
|
||||
reject(error)
|
||||
}
|
||||
}
|
||||
|
||||
function handleEntryXml(
|
||||
userId,
|
||||
dictionaryId,
|
||||
entryStatus,
|
||||
progress,
|
||||
dbClient,
|
||||
resolve,
|
||||
handleError
|
||||
) {
|
||||
return async function handleEntry(entry) {
|
||||
if (progress.importError) return
|
||||
|
||||
try {
|
||||
if (++progress.jobCount > JOBS_MAX) this.pause()
|
||||
|
||||
const term = toMixedBasic(
|
||||
entry.$markup.find(el => el.$name === 'term')?.$markup
|
||||
)
|
||||
const hwGrp = entry.$markup.find(el => el.$name === 'hwGrp')
|
||||
const wordforms = hwGrp?.$attrs.wfs
|
||||
const accent = hwGrp?.$attrs.acc
|
||||
const pronunciation = hwGrp?.$attrs.pron
|
||||
const domainLabels = entry.$markup
|
||||
.find(el => el.$name === 'domainLabels')
|
||||
?.$markup.filter(childEl => childEl.$name === 'domainLabel')
|
||||
.map(domainLabel => toText(domainLabel.$markup))
|
||||
const label = toMixedExtended(
|
||||
entry.$markup.find(el => el.$name === 'label')?.$markup
|
||||
)
|
||||
const definition = toMixedExtended(
|
||||
entry.$markup.find(el => el.$name === 'def')?.$markup
|
||||
)
|
||||
const synonyms = entry.$markup
|
||||
.find(el => el.$name === 'syns')
|
||||
?.$markup.filter(childEl => childEl.$name === 'syn')
|
||||
.map(synonym => toMixedBasic(synonym.$markup))
|
||||
const links = entry.$markup
|
||||
.find(el => el.$name === 'links')
|
||||
?.$markup.filter(childEl => childEl.$name === 'link')
|
||||
.map(link => ({
|
||||
link: toMixedBasic(link.$markup),
|
||||
type: link.$attrs.type
|
||||
}))
|
||||
const other = toMixedOther(
|
||||
entry.$markup.find(el => el.$name === 'other')?.$markup
|
||||
)
|
||||
let hasForeignTerms = false
|
||||
const foreignLanguageContent = entry.$markup
|
||||
.find(el => el.$name === 'fLangs')
|
||||
?.$markup.filter(childEl => childEl.$name === 'fLang')
|
||||
.map(fLang => ({
|
||||
language: fLang.$attrs.lang,
|
||||
terms: fLang.$markup
|
||||
.find(el => el.$name === 'fTerms')
|
||||
?.$markup.filter(childEl => childEl.$name === 'fTerm')
|
||||
.map(term => {
|
||||
const content = toMixedBasic(term.$markup)
|
||||
if (content.length) hasForeignTerms = true
|
||||
return content
|
||||
}),
|
||||
definition:
|
||||
toMixedExtended(
|
||||
fLang.$markup.find(el => el.$name === 'fDef')?.$markup
|
||||
) || null,
|
||||
synonyms: fLang.$markup
|
||||
.find(el => el.$name === 'fSyns')
|
||||
?.$markup.filter(childEl => childEl.$name === 'fSyn')
|
||||
.map(synonym => toMixedBasic(synonym.$markup))
|
||||
}))
|
||||
const multimedia = entry.$markup.find(el => el.$name === 'mm')?.$markup
|
||||
const images = []
|
||||
const audio = []
|
||||
const videos = []
|
||||
multimedia?.forEach(mm => {
|
||||
switch (mm.$name) {
|
||||
case 'image':
|
||||
images.push(toText(mm.$markup))
|
||||
break
|
||||
case 'audio':
|
||||
audio.push(toText(mm.$markup))
|
||||
break
|
||||
case 'video':
|
||||
videos.push(toText(mm.$markup))
|
||||
}
|
||||
})
|
||||
|
||||
const isValid = !!term && (!!definition || hasForeignTerms)
|
||||
|
||||
if (!entry.$markup.length) return
|
||||
|
||||
const values = [
|
||||
dictionaryId,
|
||||
isValid,
|
||||
entryStatus,
|
||||
term || null,
|
||||
userId,
|
||||
null,
|
||||
wordforms,
|
||||
accent,
|
||||
pronunciation,
|
||||
intoDbArray(domainLabels, 'always'),
|
||||
label || null,
|
||||
definition || null,
|
||||
intoDbArray(synonyms),
|
||||
intoDbArray(links, 'always'),
|
||||
other || null,
|
||||
intoDbArray(foreignLanguageContent, 'always'),
|
||||
images.length ? images : null,
|
||||
audio.length ? audio : null,
|
||||
videos.length ? videos : null
|
||||
]
|
||||
const text = `SELECT entry_new (${db.genParamStr(values)})`
|
||||
|
||||
await dbClient.query(text, values)
|
||||
|
||||
progress.totalCount++
|
||||
if (isValid) progress.validCount++
|
||||
} catch (error) {
|
||||
handleError(error)
|
||||
} finally {
|
||||
progress.jobCount--
|
||||
|
||||
if (progress.jobCount < JOBS_MIN) this.resume()
|
||||
|
||||
if (
|
||||
!progress.jobCount &&
|
||||
progress.isWholeFileRead &&
|
||||
!progress.importError
|
||||
) {
|
||||
debug(`TOTAL ENTRIES: ${progress.totalCount}`)
|
||||
debug(`VALID ENTRIES: ${progress.validCount}`)
|
||||
resolve()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const markupFilter = {
|
||||
noMixed: new xss.FilterXSS({
|
||||
whiteList: {},
|
||||
stripIgnoreTag: true,
|
||||
stripIgnoreTagBody: ['script', 'style']
|
||||
}),
|
||||
|
||||
mixedBasic: new xss.FilterXSS({
|
||||
whiteList: {
|
||||
sup: [],
|
||||
sub: []
|
||||
},
|
||||
stripIgnoreTag: true,
|
||||
stripIgnoreTagBody: ['script', 'style']
|
||||
}),
|
||||
|
||||
mixedExtended: new xss.FilterXSS({
|
||||
whiteList: {
|
||||
sup: [],
|
||||
sub: [],
|
||||
b: [],
|
||||
i: [],
|
||||
a: ['href']
|
||||
},
|
||||
stripIgnoreTag: true,
|
||||
stripIgnoreTagBody: ['script', 'style'],
|
||||
onTag: customTagHandler
|
||||
}),
|
||||
|
||||
mixedOther: new xss.FilterXSS({
|
||||
whiteList: {
|
||||
sup: [],
|
||||
sub: [],
|
||||
b: [],
|
||||
i: [],
|
||||
a: ['href'],
|
||||
br: []
|
||||
},
|
||||
stripIgnoreTag: true,
|
||||
stripIgnoreTagBody: ['script', 'style'],
|
||||
onTag: customTagHandler
|
||||
})
|
||||
}
|
||||
|
||||
function customTagHandler(tag, html, { isWhite, isClosing }) {
|
||||
// Special treatment only for whitelisted opening anchor tags.
|
||||
if (tag !== 'a' || !isWhite || isClosing) return
|
||||
|
||||
const matchUrl = html.match(/href="?(?<url>https?:\/\/.*?)"?[\s>]/)
|
||||
const url = matchUrl ? xss.escapeAttrValue(matchUrl.groups.url) : undefined
|
||||
|
||||
return `<a href${url ? `="${url}" target="_blank"` : ''}>`
|
||||
}
|
||||
|
||||
function toText(markupObj) {
|
||||
return markupFilter.noMixed
|
||||
.process(xmlFlow.toXml(markupObj))
|
||||
.replace(/\s+/g, ' ')
|
||||
.trim()
|
||||
}
|
||||
|
||||
function toMixedBasic(markupObj) {
|
||||
return markupFilter.mixedBasic
|
||||
.process(xmlFlow.toXml(markupObj))
|
||||
.replace(/\s+/g, ' ')
|
||||
.trim()
|
||||
}
|
||||
|
||||
function toMixedExtended(markupObj) {
|
||||
return markupFilter.mixedExtended
|
||||
.process(xmlFlow.toXml(markupObj))
|
||||
.replace(/\s+/g, ' ')
|
||||
.trim()
|
||||
}
|
||||
|
||||
function toMixedOther(markupObj) {
|
||||
return markupFilter.mixedOther
|
||||
.process(xmlFlow.toXml(markupObj))
|
||||
.replace(/\s+/g, ' ')
|
||||
.trim()
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
const { removeHtmlTags } = require('../../helpers')
|
||||
const { searchEngineClient, ENTRY_INDEX } = require('../../search-engine')
|
||||
|
||||
exports.deserialize = {
|
||||
primaryDomain(domain) {
|
||||
const deserializedDomain = {
|
||||
id: domain.id,
|
||||
nameSl: domain.name_sl,
|
||||
nameEn: domain.name_en
|
||||
}
|
||||
|
||||
return deserializedDomain
|
||||
},
|
||||
|
||||
secondaryDomain(domain) {
|
||||
const deserializedDomain = {
|
||||
id: domain.id,
|
||||
isApproved: domain.approved,
|
||||
nameSl: domain.name_sl,
|
||||
nameEn: domain.name_en
|
||||
}
|
||||
|
||||
return deserializedDomain
|
||||
},
|
||||
|
||||
approvedSecondaryDomain(domain) {
|
||||
const deserializedDomain = {
|
||||
id: domain.id,
|
||||
nameSl: domain.name_sl,
|
||||
nameEn: domain.name_en
|
||||
}
|
||||
|
||||
return deserializedDomain
|
||||
},
|
||||
|
||||
language(language) {
|
||||
const deserializedLanguage = {
|
||||
id: language.id,
|
||||
code: language.code,
|
||||
nameSl: language.name_sl,
|
||||
nameEn: language.name_en
|
||||
}
|
||||
|
||||
return deserializedLanguage
|
||||
},
|
||||
|
||||
editDescription(dictionary) {
|
||||
const deserializedDictionary = {
|
||||
id: dictionary.id,
|
||||
nameSl: dictionary.name_sl,
|
||||
nameEn: dictionary.name_en,
|
||||
nameSlShort: dictionary.name_sl_short,
|
||||
author: dictionary.author,
|
||||
domainPrimary: dictionary.domain_primary_id,
|
||||
description: dictionary.description,
|
||||
issn: dictionary.issn
|
||||
}
|
||||
|
||||
return deserializedDictionary
|
||||
},
|
||||
|
||||
editUsers(dictionary) {
|
||||
const deserializedDictionary = {
|
||||
id: dictionary.id,
|
||||
nameSl: dictionary.name_sl,
|
||||
terminologyReviewFlag: dictionary.entries_have_terminology_review_flag,
|
||||
languageReviewFlag: dictionary.entries_have_language_review_flag,
|
||||
status: dictionary.status
|
||||
}
|
||||
|
||||
return deserializedDictionary
|
||||
},
|
||||
|
||||
editStructure(dictionary) {
|
||||
const deserializedDictionary = {
|
||||
id: dictionary.id,
|
||||
nameSl: dictionary.name_sl,
|
||||
hasDomainLabels: dictionary.entries_have_domain_labels,
|
||||
hasLabel: dictionary.entries_have_label,
|
||||
hasDefinition: dictionary.entries_have_definition,
|
||||
hasSynonyms: dictionary.entries_have_synonyms,
|
||||
hasLinks: dictionary.entries_have_links,
|
||||
hasOther: dictionary.entries_have_other,
|
||||
hasForeignLanguages: dictionary.entries_have_foreign_languages,
|
||||
hasForeignDefinitions: dictionary.entries_have_foreign_definitions,
|
||||
hasForeignSynonyms: dictionary.entries_have_foreign_synonyms,
|
||||
hasImages: dictionary.entries_have_images,
|
||||
hasAudio: dictionary.entries_have_audio,
|
||||
hasVideo: dictionary.entries_have_videos
|
||||
}
|
||||
|
||||
return deserializedDictionary
|
||||
},
|
||||
|
||||
editDomainLabels(domainLabel) {
|
||||
const deserializedDomainLabel = {
|
||||
id: domainLabel.id,
|
||||
name: domainLabel.name,
|
||||
isVisible: domainLabel.is_visible
|
||||
}
|
||||
|
||||
return deserializedDomainLabel
|
||||
},
|
||||
|
||||
imports(oneImport) {
|
||||
const deserializedImports = {
|
||||
timeStarted: oneImport.time_started,
|
||||
status: oneImport.status,
|
||||
deleteExisting: oneImport.delete_existing_entries,
|
||||
fileFormat: oneImport.file_format,
|
||||
countValidEntries: oneImport.count_valid_entries
|
||||
}
|
||||
|
||||
return deserializedImports
|
||||
}
|
||||
}
|
||||
|
||||
exports.bulkIndex = async (entries, primaryDomain, dictionary, source) => {
|
||||
const entriesCount = entries.length
|
||||
if (!entries.length) return
|
||||
|
||||
// Construct request body.
|
||||
const bulkBody = new Array(entriesCount * 2)
|
||||
for (let i = 0; i < entriesCount; i++) {
|
||||
let entry = prepareEntryForIndexing(entries[i])
|
||||
bulkBody[i * 2] = { index: { _index: ENTRY_INDEX, _id: entry.id } }
|
||||
|
||||
entry.primaryDomain = primaryDomain
|
||||
entry.dictionary = dictionary
|
||||
entry.source = source
|
||||
entry = removeHtmlTags(JSON.stringify(entry))
|
||||
bulkBody[i * 2 + 1] = entry
|
||||
}
|
||||
|
||||
// Send the request.
|
||||
const bulkResponse = await searchEngineClient.bulk({ body: bulkBody })
|
||||
|
||||
// Log possible errors.
|
||||
if (bulkResponse.errors) {
|
||||
const erroredDocuments = []
|
||||
bulkResponse.items.forEach((action, i) => {
|
||||
const operation = Object.keys(action)[0]
|
||||
if (action[operation].error) {
|
||||
erroredDocuments.push({
|
||||
// If the status is 429 it means that you can retry the document,
|
||||
// otherwise it's very likely a mapping error, and you should
|
||||
// fix the document before to try it again.
|
||||
status: action[operation].status,
|
||||
error: action[operation].error,
|
||||
operation: action[operation].body[i * 2],
|
||||
document: action[operation].body[i * 2 + 1]
|
||||
})
|
||||
}
|
||||
})
|
||||
console.log('Errors indexing documents:') // eslint-disable-line no-console
|
||||
console.log(erroredDocuments) // eslint-disable-line no-console
|
||||
}
|
||||
}
|
||||
|
||||
function prepareEntryForIndexing(entry) {
|
||||
// Snake case property names into camel case.
|
||||
entry.isValid = entry.is_valid
|
||||
delete entry.is_valid
|
||||
|
||||
entry.isPublished = entry.is_published
|
||||
delete entry.is_published
|
||||
|
||||
entry.isTerminologyReviewed = entry.is_terminology_reviewed
|
||||
delete entry.is_terminology_reviewed
|
||||
|
||||
entry.isLanguageReviewed = entry.is_language_reviewed
|
||||
delete entry.is_language_reviewed
|
||||
|
||||
entry.homonymSort = entry.homonym_sort
|
||||
delete entry.homonym_sort
|
||||
|
||||
entry.timeMostRecentComment = entry.time_most_recent_comment
|
||||
delete entry.time_most_recent_comment
|
||||
|
||||
entry.domainLabels = entry.domain_labels
|
||||
delete entry.domain_labels
|
||||
|
||||
entry.foreignEntries = entry.foreign_entries
|
||||
delete entry.foreign_entries
|
||||
|
||||
// Remove (top-level) properies with null or empty array values.
|
||||
entry = Object.fromEntries(
|
||||
Object.entries(entry).filter(
|
||||
([_, v]) => v !== null && (!Array.isArray(v) || v.length)
|
||||
)
|
||||
)
|
||||
|
||||
return entry
|
||||
}
|
||||
|
||||
exports.prepareEntryForIndexing = prepareEntryForIndexing
|
||||
@@ -0,0 +1,62 @@
|
||||
const { readdir, stat } = require('fs/promises')
|
||||
const { partial } = require('filesize')
|
||||
const { DATA_FILES_PATH } = require('../../config/settings')
|
||||
|
||||
const formatFileSize = partial({ separator: ',' })
|
||||
|
||||
exports.deserialize = {
|
||||
extraction(extraction) {
|
||||
const deserializedExtraction = {
|
||||
id: extraction.id,
|
||||
name: extraction.name,
|
||||
status: extraction.status,
|
||||
corpusId: extraction.corpus_id,
|
||||
timeStarted: extraction.time_started,
|
||||
timeFinished: extraction.time_finished,
|
||||
ossParams: extraction.oss_params
|
||||
}
|
||||
|
||||
return deserializedExtraction
|
||||
}
|
||||
}
|
||||
|
||||
exports.getExtractionFilesPath = getExtractionFilesPath
|
||||
|
||||
exports.getDocumentsPath = extractionId => {
|
||||
return `${getExtractionFilesPath(extractionId)}/documents`
|
||||
}
|
||||
|
||||
exports.getStopTermsPath = extractionId => {
|
||||
return `${getExtractionFilesPath(extractionId)}/stop_terms`
|
||||
}
|
||||
|
||||
exports.getConllusPath = extractionId => {
|
||||
return `${getExtractionFilesPath(extractionId)}/conllu`
|
||||
}
|
||||
|
||||
exports.getTermCandidatesPath = extractionId => {
|
||||
return `${getExtractionFilesPath(extractionId)}/term_candidates.json`
|
||||
}
|
||||
|
||||
exports.getFileNamesInFolder = async folderPath => {
|
||||
const filenames = await readdir(folderPath)
|
||||
return filenames
|
||||
}
|
||||
|
||||
exports.getFileStatsInFolder = async folderPath => {
|
||||
const filenames = await readdir(folderPath)
|
||||
const fileStats = await Promise.all(
|
||||
filenames.map(async filename => {
|
||||
const filePath = `${folderPath}/${filename}`
|
||||
const { mtimeMs: timeModified, size } = await stat(filePath)
|
||||
const sizeHumanReadable = formatFileSize(size)
|
||||
const fileStats = { filename, size: sizeHumanReadable, timeModified }
|
||||
return fileStats
|
||||
})
|
||||
)
|
||||
return fileStats
|
||||
}
|
||||
|
||||
function getExtractionFilesPath(extractionId) {
|
||||
return `${DATA_FILES_PATH}/extraction/${extractionId}`
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
const xss = require('xss')
|
||||
const cache = require('../cache')
|
||||
const Portal = require('../portal')
|
||||
|
||||
const INSTANCE_SETTING_NAMESPACE = 'instance-setting'
|
||||
const INSTANCE_SETTING_CACHE_EXPIRE_TIME = 60 * 60 // 1 hour.
|
||||
const SLOVENIAN_LANGUAGE_ID_CACHE_EXPIRE_TIME = 60 * 60 // 1 hour.
|
||||
|
||||
exports.intoDbArray = (inputData, mode) => {
|
||||
if (Array.isArray(inputData)) {
|
||||
return inputData
|
||||
} else if (inputData === undefined || inputData === '') {
|
||||
if (mode === 'always') return []
|
||||
if (mode === 'undefined') return undefined
|
||||
else return null
|
||||
// return mode === 'always' ? [] : null
|
||||
}
|
||||
return [inputData]
|
||||
}
|
||||
|
||||
exports.removeHtmlTags = text => {
|
||||
return tagFilter.process(text)
|
||||
}
|
||||
|
||||
// Returns setting value by its name from table instance_settings.
|
||||
exports.getInstanceSetting = async settingName => {
|
||||
const settingCacheName = `${INSTANCE_SETTING_NAMESPACE}:${settingName}`
|
||||
let settingValue = await cache.get(settingCacheName)
|
||||
|
||||
if (!settingValue) {
|
||||
settingValue = await Portal.getInstanceSettingValue(settingName)
|
||||
await cache.set(
|
||||
settingCacheName,
|
||||
settingValue,
|
||||
'EX',
|
||||
INSTANCE_SETTING_CACHE_EXPIRE_TIME
|
||||
)
|
||||
}
|
||||
|
||||
return settingValue
|
||||
}
|
||||
|
||||
// Deletes cached instance settings.
|
||||
exports.clearCachedInstanceSettings = async () => {
|
||||
const settingNames = await Portal.fetchAllInstanceSettingNames()
|
||||
const settingCacheNames = settingNames.map(
|
||||
settingName => `${INSTANCE_SETTING_NAMESPACE}:${settingName}`
|
||||
)
|
||||
await cache.unlink(...settingCacheNames)
|
||||
}
|
||||
|
||||
// Returns slovenian language id and keeps it cached.
|
||||
exports.getSlovenianLanguageId = async () => {
|
||||
const settingCacheName = 'slovenian-language-id'
|
||||
let id = await cache.get(settingCacheName)
|
||||
|
||||
if (!id) {
|
||||
id = (await Portal.getSlovenianLanguageId()).toString()
|
||||
await cache.set(
|
||||
settingCacheName,
|
||||
id,
|
||||
'EX',
|
||||
SLOVENIAN_LANGUAGE_ID_CACHE_EXPIRE_TIME
|
||||
)
|
||||
}
|
||||
|
||||
return id
|
||||
}
|
||||
|
||||
const tagFilter = new xss.FilterXSS({
|
||||
whiteList: {},
|
||||
stripIgnoreTag: true
|
||||
})
|
||||
@@ -0,0 +1,67 @@
|
||||
exports.aggregateSettings = settings => {
|
||||
const deserializedSettings = settings.reduce((agg, setting) => {
|
||||
agg[setting.name] = setting.value
|
||||
return agg
|
||||
}, {})
|
||||
return deserializedSettings
|
||||
}
|
||||
|
||||
exports.deserialize = {
|
||||
settings(settings) {
|
||||
const deserializedSettings = {
|
||||
name: settings.portal_name,
|
||||
description: settings.portal_description,
|
||||
code: settings.portal_code,
|
||||
isExtractionEnabled: settings.is_extraction_enabled,
|
||||
isDictionariesEnabled: settings.is_dictionaries_enabled,
|
||||
isConsultancyEnabled: settings.is_consultancy_enabled
|
||||
}
|
||||
|
||||
return deserializedSettings
|
||||
},
|
||||
dictSettings(settings) {
|
||||
const deserializedSettings = {
|
||||
minEntriesPerDictionary: settings.min_entries_per_dictionary,
|
||||
dictionaryPublishApproval: settings.dictionary_publish_approval,
|
||||
// keepNumOfExportsPerDict: settings.keep_num_of_exports_per_dictionary,
|
||||
// dictionaryAutoSaveFrequency: settings.dictionary_auto_save_frequency,
|
||||
numOfHistoryEntriesPerEntry: settings.num_of_history_entires_per_entry,
|
||||
canPublishEntriesInEdit: settings.can_publish_entries_in_edit
|
||||
}
|
||||
|
||||
return deserializedSettings
|
||||
},
|
||||
consultSettings(settings) {
|
||||
const deserializedSettings = {
|
||||
consultancyType: settings.consultancy_type,
|
||||
zrcEmail: settings.zrc_email,
|
||||
zrcURL: settings.zrc_url
|
||||
}
|
||||
|
||||
return deserializedSettings
|
||||
},
|
||||
connections(connection) {
|
||||
const deserializedConnections = {
|
||||
id: connection.id,
|
||||
name: connection.name,
|
||||
indexURL: connection.url_index,
|
||||
code: connection.code,
|
||||
isEnabled: connection.is_enabled,
|
||||
synced: connection.time_last_synced,
|
||||
isLinked: connection.is_linked,
|
||||
URLupdate: connection.url_update
|
||||
}
|
||||
|
||||
return deserializedConnections
|
||||
},
|
||||
dictionaries(dictionary) {
|
||||
const deserializeDictionaries = {
|
||||
id: dictionary.id,
|
||||
name: dictionary.name,
|
||||
code: dictionary.code,
|
||||
isEnabled: dictionary.is_enabled
|
||||
}
|
||||
|
||||
return deserializeDictionaries
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// TODO Consider alternative paging when hits exceed 10000.
|
||||
|
||||
module.exports = function (filters, hitsPerPage, page) {
|
||||
const queryDsl = {
|
||||
from: hitsPerPage * (page - 1),
|
||||
size: hitsPerPage,
|
||||
query: {
|
||||
bool: {
|
||||
filter: []
|
||||
}
|
||||
},
|
||||
sort: ['_score', 'timeCreated']
|
||||
}
|
||||
|
||||
if (filters.status) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
term: {
|
||||
status: filters.status
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (filters.assignedConsultant) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
term: {
|
||||
'assignedConsultants.id': filters.assignedConsultant
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (filters.primaryDomain) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
term: {
|
||||
'primaryDomain.id': filters.primaryDomain
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return queryDsl
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
// TODO Consider alternative paging when hits exceed 10000.
|
||||
|
||||
module.exports = function (searchString, filters, hitsPerPage, page) {
|
||||
const queryDsl = {
|
||||
from: hitsPerPage * (page - 1),
|
||||
size: hitsPerPage,
|
||||
query: {
|
||||
bool: {
|
||||
must: {
|
||||
dis_max: {
|
||||
queries: [
|
||||
{
|
||||
constant_score: {
|
||||
filter: {
|
||||
match_phrase: {
|
||||
title: searchString
|
||||
}
|
||||
},
|
||||
boost: 3
|
||||
}
|
||||
},
|
||||
{
|
||||
constant_score: {
|
||||
filter: {
|
||||
match_phrase: {
|
||||
question: searchString
|
||||
}
|
||||
},
|
||||
boost: 2
|
||||
}
|
||||
},
|
||||
{
|
||||
constant_score: {
|
||||
filter: {
|
||||
match_phrase: {
|
||||
answer: searchString
|
||||
}
|
||||
},
|
||||
boost: 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
filter: []
|
||||
}
|
||||
},
|
||||
sort: ['_score', 'timeCreated']
|
||||
}
|
||||
|
||||
if (filters.status) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
term: {
|
||||
status: filters.status
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (filters.assignedConsultant) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
term: {
|
||||
'assignedConsultants.id': filters.assignedConsultant
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (filters.primaryDomain) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
term: {
|
||||
'primaryDomain.id': filters.primaryDomain
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return queryDsl
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
const { queryForField } = require('../..')
|
||||
|
||||
const whitespace = /\s+/
|
||||
|
||||
// TODO Consider alternative paging when hits exceed 10000.
|
||||
|
||||
module.exports = function (searchString, filters, hitsPerPage, page) {
|
||||
const searchTokens = searchString.split(whitespace)
|
||||
|
||||
const queryDsl = {
|
||||
from: hitsPerPage * (page - 1),
|
||||
size: hitsPerPage,
|
||||
query: {
|
||||
bool: {
|
||||
must: {
|
||||
dis_max: {
|
||||
queries: [
|
||||
{
|
||||
constant_score: {
|
||||
filter: queryForField('title', searchTokens),
|
||||
boost: 3
|
||||
}
|
||||
},
|
||||
{
|
||||
constant_score: {
|
||||
filter: queryForField('question', searchTokens),
|
||||
boost: 2
|
||||
}
|
||||
},
|
||||
{
|
||||
constant_score: {
|
||||
filter: queryForField('answer', searchTokens),
|
||||
boost: 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
filter: []
|
||||
}
|
||||
},
|
||||
sort: ['_score', 'timeCreated']
|
||||
}
|
||||
|
||||
if (filters.status) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
term: {
|
||||
status: filters.status
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (filters.assignedConsultant) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
term: {
|
||||
'assignedConsultants.id': filters.assignedConsultant
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (filters.primaryDomain) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
term: {
|
||||
'primaryDomain.id': filters.primaryDomain
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return queryDsl
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
// TODO Consider alternative paging when hits exceed 10000.
|
||||
|
||||
module.exports = function (searchString, filters, hitsPerPage, page) {
|
||||
const queryDsl = {
|
||||
from: hitsPerPage * (page - 1),
|
||||
size: hitsPerPage,
|
||||
query: {
|
||||
bool: {
|
||||
must: {
|
||||
dis_max: {
|
||||
queries: [
|
||||
{
|
||||
constant_score: {
|
||||
filter: {
|
||||
match: {
|
||||
title: {
|
||||
query: searchString,
|
||||
operator: 'and'
|
||||
}
|
||||
}
|
||||
},
|
||||
boost: 3
|
||||
}
|
||||
},
|
||||
{
|
||||
constant_score: {
|
||||
filter: {
|
||||
match: {
|
||||
question: {
|
||||
query: searchString,
|
||||
operator: 'and'
|
||||
}
|
||||
}
|
||||
},
|
||||
boost: 2
|
||||
}
|
||||
},
|
||||
{
|
||||
constant_score: {
|
||||
filter: {
|
||||
match: {
|
||||
answer: {
|
||||
query: searchString,
|
||||
operator: 'and'
|
||||
}
|
||||
}
|
||||
},
|
||||
boost: 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
filter: []
|
||||
}
|
||||
},
|
||||
sort: ['_score', 'timeCreated']
|
||||
}
|
||||
|
||||
if (filters.status) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
term: {
|
||||
status: filters.status
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (filters.assignedConsultant) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
term: {
|
||||
'assignedConsultants.id': filters.assignedConsultant
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (filters.primaryDomain) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
term: {
|
||||
'primaryDomain.id': filters.primaryDomain
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return queryDsl
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
const { EDITOR_MAX_HITS } = require('../../../../../config/settings')
|
||||
|
||||
module.exports = function (dictionaryId, filters, searchFieldFilters) {
|
||||
const queryDsl = {
|
||||
_source: ['id', 'isValid', 'isPublished', 'term'],
|
||||
fields: ['foreignEntries.terms'],
|
||||
script_fields: {
|
||||
commentActivityIndicator: {
|
||||
script: {
|
||||
source: `
|
||||
if (!doc.containsKey('timeMostRecentComment') || doc['timeMostRecentComment'].empty) return "";
|
||||
|
||||
ZonedDateTime mostRecentCommentTime = doc['timeMostRecentComment'].value;
|
||||
|
||||
long nowMilli = params['now'];
|
||||
Instant nowInstant = Instant.ofEpochMilli(nowMilli);
|
||||
ZonedDateTime now = ZonedDateTime.ofInstant(nowInstant, ZoneId.of('Z'));
|
||||
|
||||
long ageInDays = ChronoUnit.DAYS.between(mostRecentCommentTime, now);
|
||||
|
||||
if (ageInDays < 7) {
|
||||
return "T"
|
||||
} else if (ageInDays < 30) {
|
||||
return "M"
|
||||
} else if (ageInDays < 365) {
|
||||
return "L"
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
`,
|
||||
params: {
|
||||
now: Date.now()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
size: EDITOR_MAX_HITS,
|
||||
query: {
|
||||
bool: {
|
||||
filter: [
|
||||
{
|
||||
term: {
|
||||
'dictionary.id': dictionaryId
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
sort: ['term.sort', 'homonymSort']
|
||||
}
|
||||
|
||||
if (searchFieldFilters) queryDsl.query.bool.filter.push(searchFieldFilters)
|
||||
|
||||
if (filters) {
|
||||
if (filters.isValid !== undefined) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
term: {
|
||||
isValid: filters.isValid
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (filters.isPublished !== undefined) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
term: {
|
||||
isPublished: filters.isPublished
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (filters.hasComments !== undefined) {
|
||||
if (filters.hasComments === true) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
exists: {
|
||||
field: 'timeMostRecentComment'
|
||||
}
|
||||
})
|
||||
} else {
|
||||
queryDsl.query.bool.filter.push({
|
||||
bool: {
|
||||
must_not: {
|
||||
exists: {
|
||||
field: 'timeMostRecentComment'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (filters.isComplete !== undefined) {
|
||||
if (filters.isComplete === true) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
term: {
|
||||
status: 'complete'
|
||||
}
|
||||
})
|
||||
} else {
|
||||
queryDsl.query.bool.filter.push({
|
||||
bool: {
|
||||
must_not: {
|
||||
term: {
|
||||
status: 'complete'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (filters.isTerminologyReviewed !== undefined) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
term: {
|
||||
isTerminologyReviewed: filters.isTerminologyReviewed
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (filters.isLanguageReviewed !== undefined) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
term: {
|
||||
isLanguageReviewed: filters.isLanguageReviewed
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return queryDsl
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
const { fieldMap } = require('../..')
|
||||
const generateQuery = require('./all')
|
||||
|
||||
module.exports = function (dictionaryId, searchField, filters) {
|
||||
const searchFieldFilters = generateSearchFieldFilters(searchField)
|
||||
|
||||
const queryDsl = generateQuery(dictionaryId, filters, searchFieldFilters)
|
||||
|
||||
return queryDsl
|
||||
}
|
||||
|
||||
function generateSearchFieldFilters(searchField) {
|
||||
const mappedName = fieldMap[searchField]
|
||||
|
||||
if (mappedName) {
|
||||
if (mappedName.startsWith('foreignEntries')) {
|
||||
return {
|
||||
nested: {
|
||||
path: 'foreignEntries',
|
||||
query: {
|
||||
exists: {
|
||||
field: mappedName
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
exists: {
|
||||
field: mappedName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
dis_max: {
|
||||
queries: [
|
||||
{
|
||||
exists: {
|
||||
field: 'term'
|
||||
}
|
||||
},
|
||||
{
|
||||
exists: {
|
||||
field: 'synonyms'
|
||||
}
|
||||
},
|
||||
{
|
||||
exists: {
|
||||
field: 'label'
|
||||
}
|
||||
},
|
||||
{
|
||||
exists: {
|
||||
field: 'definition'
|
||||
}
|
||||
},
|
||||
{
|
||||
exists: {
|
||||
field: 'other'
|
||||
}
|
||||
},
|
||||
{
|
||||
exists: {
|
||||
field: 'domainLabels'
|
||||
}
|
||||
},
|
||||
{
|
||||
exists: {
|
||||
field: 'links'
|
||||
}
|
||||
},
|
||||
{
|
||||
nested: {
|
||||
path: 'foreignEntries',
|
||||
query: {
|
||||
dis_max: {
|
||||
queries: [
|
||||
{
|
||||
exists: {
|
||||
field: 'foreignEntries.terms'
|
||||
}
|
||||
},
|
||||
{
|
||||
exists: {
|
||||
field: 'foreignEntries.synonyms'
|
||||
}
|
||||
},
|
||||
{
|
||||
exists: {
|
||||
field: 'foreignEntries.definition'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
const { fieldMap } = require('../..')
|
||||
const generateQuery = require('./all')
|
||||
|
||||
module.exports = function (dictionaryId, searchField, searchString, filters) {
|
||||
const searchFieldFilters = generateSearchFieldFilters(
|
||||
searchField,
|
||||
searchString
|
||||
)
|
||||
|
||||
const queryDsl = generateQuery(dictionaryId, filters, searchFieldFilters)
|
||||
|
||||
return queryDsl
|
||||
}
|
||||
|
||||
function generateSearchFieldFilters(searchField, searchString) {
|
||||
const mappedName = fieldMap[searchField]
|
||||
|
||||
if (mappedName) {
|
||||
if (mappedName.startsWith('foreignEntries')) {
|
||||
return {
|
||||
nested: {
|
||||
path: 'foreignEntries',
|
||||
query: {
|
||||
match_phrase: {
|
||||
[mappedName]: searchString
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
match_phrase: {
|
||||
[mappedName]: searchString
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
dis_max: {
|
||||
queries: [
|
||||
{
|
||||
multi_match: {
|
||||
query: searchString,
|
||||
type: 'phrase',
|
||||
fields: [
|
||||
'term',
|
||||
'synonyms',
|
||||
'label',
|
||||
'definition',
|
||||
'other',
|
||||
'domainLabels',
|
||||
'links'
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
nested: {
|
||||
path: 'foreignEntries',
|
||||
query: {
|
||||
multi_match: {
|
||||
query: searchString,
|
||||
type: 'phrase',
|
||||
fields: [
|
||||
'foreignEntries.terms',
|
||||
'foreignEntries.synonyms',
|
||||
'foreignEntries.definition'
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
const { fieldMap, queryForField } = require('../..')
|
||||
const generateQuery = require('./all')
|
||||
|
||||
const whitespace = /\s+/
|
||||
|
||||
module.exports = function (dictionaryId, searchField, searchString, filters) {
|
||||
const searchFieldFilters = generateSearchFieldFilters(
|
||||
searchField,
|
||||
searchString
|
||||
)
|
||||
|
||||
const queryDsl = generateQuery(dictionaryId, filters, searchFieldFilters)
|
||||
|
||||
return queryDsl
|
||||
}
|
||||
|
||||
function generateSearchFieldFilters(searchField, searchString) {
|
||||
const searchTokens = searchString.split(whitespace)
|
||||
|
||||
const mappedName = fieldMap[searchField]
|
||||
|
||||
if (mappedName) {
|
||||
if (mappedName.startsWith('foreignEntries')) {
|
||||
return {
|
||||
nested: {
|
||||
path: 'foreignEntries',
|
||||
query: queryForField(mappedName, searchTokens)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return queryForField(mappedName, searchTokens)
|
||||
}
|
||||
|
||||
return {
|
||||
dis_max: {
|
||||
queries: [
|
||||
queryForField('term', searchTokens),
|
||||
queryForField('synonyms', searchTokens),
|
||||
queryForField('label', searchTokens),
|
||||
queryForField('definition', searchTokens),
|
||||
queryForField('other', searchTokens),
|
||||
queryForField('domainLabels', searchTokens),
|
||||
queryForField('links', searchTokens),
|
||||
{
|
||||
nested: {
|
||||
path: 'foreignEntries',
|
||||
query: {
|
||||
dis_max: {
|
||||
queries: [
|
||||
queryForField('foreignEntries.terms', searchTokens),
|
||||
queryForField('foreignEntries.synonyms', searchTokens),
|
||||
queryForField('foreignEntries.definition', searchTokens)
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
const { fieldMap } = require('../..')
|
||||
const generateQuery = require('./all')
|
||||
|
||||
module.exports = function (dictionaryId, searchField, searchString, filters) {
|
||||
const searchFieldFilters = generateSearchFieldFilters(
|
||||
searchField,
|
||||
searchString
|
||||
)
|
||||
|
||||
const queryDsl = generateQuery(dictionaryId, filters, searchFieldFilters)
|
||||
|
||||
return queryDsl
|
||||
}
|
||||
|
||||
function generateSearchFieldFilters(searchField, searchString) {
|
||||
const mappedName = fieldMap[searchField]
|
||||
|
||||
if (mappedName) {
|
||||
if (mappedName.startsWith('foreignEntries')) {
|
||||
return {
|
||||
nested: {
|
||||
path: 'foreignEntries',
|
||||
query: {
|
||||
match: {
|
||||
[mappedName]: {
|
||||
query: searchString,
|
||||
operator: 'and'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
match: {
|
||||
[mappedName]: {
|
||||
query: searchString,
|
||||
operator: 'and'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
dis_max: {
|
||||
queries: [
|
||||
{
|
||||
multi_match: {
|
||||
query: searchString,
|
||||
operator: 'and',
|
||||
fields: [
|
||||
'term',
|
||||
'synonyms',
|
||||
'label',
|
||||
'definition',
|
||||
'other',
|
||||
'domainLabels',
|
||||
'links'
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
nested: {
|
||||
path: 'foreignEntries',
|
||||
query: {
|
||||
multi_match: {
|
||||
query: searchString,
|
||||
operator: 'and',
|
||||
fields: [
|
||||
'foreignEntries.terms',
|
||||
'foreignEntries.synonyms',
|
||||
'foreignEntries.definition'
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
const debug = require('debug')('termPortal:generate-query')
|
||||
const genAllHitQuery = require('./main/all')
|
||||
const genAllAggQuery = require('./main/aggregate-all')
|
||||
const genPhraseHitQuery = require('./main/phrase')
|
||||
const genPhraseAggQuery = require('./main/aggregate-phrase')
|
||||
const genWildcardHitQuery = require('./main/wildcard')
|
||||
const genWildcardAggQuery = require('./main/aggregate-wildcard')
|
||||
const genMultiWordHitQuery = require('./main/word-multi')
|
||||
const genWordAggQuery = require('./main/aggregate-word')
|
||||
const genSingleWordHitQuery = require('./main/word-single')
|
||||
const genEditorAllQuery = require('./editor/all')
|
||||
const genEditorExistsQuery = require('./editor/exists')
|
||||
const genEditorPhraseQuery = require('./editor/phrase')
|
||||
const genEditorWildcardQuery = require('./editor/wildcard')
|
||||
const genEditorWordsQuery = require('./editor/words')
|
||||
const genConsultancyAllQuery = require('./consultancy/all')
|
||||
const genConsultancyPhraseQuery = require('./consultancy/phrase')
|
||||
const genConsultancyWildcardQuery = require('./consultancy/wildcard')
|
||||
const genConsultancyWordsQuery = require('./consultancy/words')
|
||||
|
||||
const notOnlyAsterisks = /[^*"\s]/
|
||||
const hasWildcards = /[*?]/
|
||||
const hasWhitespace = /\s/
|
||||
|
||||
// Determines query type, constructs and returns appropriate search engine query(es).
|
||||
exports.main = async (
|
||||
searchString,
|
||||
filters,
|
||||
hitsPerPage,
|
||||
page,
|
||||
withAggregation
|
||||
) => {
|
||||
let hitsQuery
|
||||
let aggregateQuery
|
||||
|
||||
const firstChar = searchString[0]
|
||||
const lastChar = searchString[searchString.length - 1]
|
||||
|
||||
// TODO Aditional sanitization/transformation?
|
||||
|
||||
if (!notOnlyAsterisks.test(searchString)) {
|
||||
debug('query type: all')
|
||||
hitsQuery = genAllHitQuery(filters, hitsPerPage, page)
|
||||
if (withAggregation) {
|
||||
aggregateQuery = genAllAggQuery(hitsQuery)
|
||||
}
|
||||
} else if (firstChar === '"' && lastChar === '"') {
|
||||
debug('query type: phrase')
|
||||
searchString = searchString.slice(1, -1)
|
||||
hitsQuery = await genPhraseHitQuery(
|
||||
searchString,
|
||||
filters,
|
||||
hitsPerPage,
|
||||
page
|
||||
)
|
||||
if (withAggregation) {
|
||||
aggregateQuery = genPhraseAggQuery(searchString, hitsQuery)
|
||||
}
|
||||
} else if (hasWildcards.test(searchString)) {
|
||||
debug('query type: wildcard')
|
||||
let slovenianFieldQueries, foreignFieldQueries
|
||||
;[hitsQuery, slovenianFieldQueries, foreignFieldQueries] =
|
||||
await genWildcardHitQuery(searchString, filters, hitsPerPage, page)
|
||||
if (withAggregation) {
|
||||
aggregateQuery = genWildcardAggQuery(
|
||||
hitsQuery,
|
||||
slovenianFieldQueries,
|
||||
foreignFieldQueries
|
||||
)
|
||||
}
|
||||
} else if (hasWhitespace.test(searchString)) {
|
||||
debug('query type: multi word')
|
||||
hitsQuery = await genMultiWordHitQuery(
|
||||
searchString,
|
||||
filters,
|
||||
hitsPerPage,
|
||||
page
|
||||
)
|
||||
if (withAggregation) {
|
||||
aggregateQuery = genWordAggQuery(searchString, hitsQuery)
|
||||
}
|
||||
} else {
|
||||
debug('query type: single word')
|
||||
hitsQuery = await genSingleWordHitQuery(
|
||||
searchString,
|
||||
filters,
|
||||
hitsPerPage,
|
||||
page
|
||||
)
|
||||
if (withAggregation) {
|
||||
aggregateQuery = genWordAggQuery(searchString, hitsQuery)
|
||||
}
|
||||
}
|
||||
|
||||
return withAggregation ? [hitsQuery, aggregateQuery] : hitsQuery
|
||||
}
|
||||
|
||||
// Determines query type, constructs and returns appropriate search engine query for editor.
|
||||
exports.editor = (dictionaryId, searchField, searchString, filters) => {
|
||||
let hitsQuery
|
||||
|
||||
const firstChar = searchString[0]
|
||||
const lastChar = searchString[searchString.length - 1]
|
||||
|
||||
// TODO Aditional sanitization/transformation?
|
||||
|
||||
if (!searchString) {
|
||||
debug('query type: all')
|
||||
hitsQuery = genEditorAllQuery(dictionaryId, filters)
|
||||
} else if (!notOnlyAsterisks.test(searchString)) {
|
||||
debug('query type: exists')
|
||||
hitsQuery = genEditorExistsQuery(dictionaryId, searchField, filters)
|
||||
} else if (firstChar === '"' && lastChar === '"') {
|
||||
debug('query type: phrase')
|
||||
searchString = searchString.slice(1, -1)
|
||||
hitsQuery = genEditorPhraseQuery(
|
||||
dictionaryId,
|
||||
searchField,
|
||||
searchString,
|
||||
filters
|
||||
)
|
||||
} else if (hasWildcards.test(searchString)) {
|
||||
debug('query type: wildcard')
|
||||
hitsQuery = genEditorWildcardQuery(
|
||||
dictionaryId,
|
||||
searchField,
|
||||
searchString,
|
||||
filters
|
||||
)
|
||||
} else {
|
||||
debug('query type: words')
|
||||
hitsQuery = genEditorWordsQuery(
|
||||
dictionaryId,
|
||||
searchField,
|
||||
searchString,
|
||||
filters
|
||||
)
|
||||
}
|
||||
|
||||
return hitsQuery
|
||||
}
|
||||
|
||||
// Determines query type, constructs and returns appropriate search engine query for consultancy.
|
||||
exports.consultancy = (searchString, filters, hitsPerPage, page) => {
|
||||
let hitsQuery
|
||||
|
||||
const firstChar = searchString[0]
|
||||
const lastChar = searchString[searchString.length - 1]
|
||||
|
||||
// TODO Aditional sanitization/transformation?
|
||||
|
||||
if (!notOnlyAsterisks.test(searchString)) {
|
||||
debug('query type: all')
|
||||
hitsQuery = genConsultancyAllQuery(filters, hitsPerPage, page)
|
||||
} else if (firstChar === '"' && lastChar === '"') {
|
||||
debug('query type: phrase')
|
||||
searchString = searchString.slice(1, -1)
|
||||
hitsQuery = genConsultancyPhraseQuery(
|
||||
searchString,
|
||||
filters,
|
||||
hitsPerPage,
|
||||
page
|
||||
)
|
||||
} else if (hasWildcards.test(searchString)) {
|
||||
debug('query type: wildcard')
|
||||
hitsQuery = genConsultancyWildcardQuery(
|
||||
searchString,
|
||||
filters,
|
||||
hitsPerPage,
|
||||
page
|
||||
)
|
||||
} else {
|
||||
debug('query type: words')
|
||||
hitsQuery = genConsultancyWordsQuery(
|
||||
searchString,
|
||||
filters,
|
||||
hitsPerPage,
|
||||
page
|
||||
)
|
||||
}
|
||||
|
||||
return hitsQuery
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
module.exports = function (hitsQuery) {
|
||||
// A shallow copy will prevent hitsQuery from being modified.
|
||||
const queryDsl = { ...hitsQuery }
|
||||
|
||||
queryDsl.from = 0
|
||||
queryDsl.size = 0
|
||||
|
||||
queryDsl.aggs = {
|
||||
primaryDomains: {
|
||||
terms: {
|
||||
field: 'primaryDomain.id',
|
||||
size: 100
|
||||
}
|
||||
},
|
||||
dictionaries: {
|
||||
terms: {
|
||||
field: 'dictionary.id',
|
||||
size: 200
|
||||
}
|
||||
},
|
||||
sources: {
|
||||
terms: {
|
||||
field: 'source.code'
|
||||
}
|
||||
},
|
||||
foreign: {
|
||||
nested: {
|
||||
path: 'foreignEntries'
|
||||
},
|
||||
aggs: {
|
||||
targetLanguages: {
|
||||
terms: {
|
||||
field: 'foreignEntries.lang.id',
|
||||
size: 50
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return queryDsl
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
module.exports = function (searchString, hitsQuery) {
|
||||
// A shallow copy will prevent hitsQuery from being modified.
|
||||
const queryDsl = { ...hitsQuery }
|
||||
|
||||
queryDsl.from = 0
|
||||
queryDsl.size = 0
|
||||
|
||||
queryDsl.aggs = {
|
||||
primaryDomains: {
|
||||
terms: {
|
||||
field: 'primaryDomain.id',
|
||||
size: 100
|
||||
}
|
||||
},
|
||||
dictionaries: {
|
||||
terms: {
|
||||
field: 'dictionary.id',
|
||||
size: 200
|
||||
}
|
||||
},
|
||||
sources: {
|
||||
terms: {
|
||||
field: 'source.code'
|
||||
}
|
||||
},
|
||||
slovenianHits: {
|
||||
filter: {
|
||||
multi_match: {
|
||||
query: searchString,
|
||||
type: 'phrase',
|
||||
fields: [
|
||||
'term',
|
||||
'synonyms',
|
||||
'label',
|
||||
'definition',
|
||||
'other',
|
||||
'domainLabels',
|
||||
'links'
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
foreign: {
|
||||
nested: {
|
||||
path: 'foreignEntries'
|
||||
},
|
||||
aggs: {
|
||||
targetLanguages: {
|
||||
terms: {
|
||||
field: 'foreignEntries.lang.id',
|
||||
size: 50
|
||||
}
|
||||
},
|
||||
foreignHits: {
|
||||
filter: {
|
||||
multi_match: {
|
||||
query: searchString,
|
||||
type: 'phrase',
|
||||
fields: [
|
||||
'foreignEntries.terms',
|
||||
'foreignEntries.synonyms',
|
||||
'foreignEntries.definition'
|
||||
]
|
||||
}
|
||||
},
|
||||
aggs: {
|
||||
sourceLanguages: {
|
||||
terms: {
|
||||
field: 'foreignEntries.lang.id',
|
||||
size: 50
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return queryDsl
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
module.exports = function (
|
||||
hitsQuery,
|
||||
slovenianFieldQueries,
|
||||
foreignFieldQueries
|
||||
) {
|
||||
// A shallow copy will prevent hitsQuery from being modified.
|
||||
const queryDsl = { ...hitsQuery }
|
||||
|
||||
queryDsl.from = 0
|
||||
queryDsl.size = 0
|
||||
|
||||
queryDsl.aggs = {
|
||||
primaryDomains: {
|
||||
terms: {
|
||||
field: 'primaryDomain.id',
|
||||
size: 100
|
||||
}
|
||||
},
|
||||
dictionaries: {
|
||||
terms: {
|
||||
field: 'dictionary.id',
|
||||
size: 200
|
||||
}
|
||||
},
|
||||
sources: {
|
||||
terms: {
|
||||
field: 'source.code'
|
||||
}
|
||||
},
|
||||
slovenianHits: {
|
||||
filter: {
|
||||
dis_max: {
|
||||
queries: slovenianFieldQueries
|
||||
}
|
||||
}
|
||||
},
|
||||
foreign: {
|
||||
nested: {
|
||||
path: 'foreignEntries'
|
||||
},
|
||||
aggs: {
|
||||
targetLanguages: {
|
||||
terms: {
|
||||
field: 'foreignEntries.lang.id',
|
||||
size: 50
|
||||
}
|
||||
},
|
||||
foreignHits: {
|
||||
filter: {
|
||||
dis_max: {
|
||||
queries: foreignFieldQueries
|
||||
}
|
||||
},
|
||||
aggs: {
|
||||
sourceLanguages: {
|
||||
terms: {
|
||||
field: 'foreignEntries.lang.id',
|
||||
size: 50
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return queryDsl
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
module.exports = function (searchString, hitsQuery) {
|
||||
// A shallow copy will prevent hitsQuery from being modified.
|
||||
const queryDsl = { ...hitsQuery }
|
||||
|
||||
queryDsl.from = 0
|
||||
queryDsl.size = 0
|
||||
|
||||
queryDsl.aggs = {
|
||||
primaryDomains: {
|
||||
terms: {
|
||||
field: 'primaryDomain.id',
|
||||
size: 100
|
||||
}
|
||||
},
|
||||
dictionaries: {
|
||||
terms: {
|
||||
field: 'dictionary.id',
|
||||
size: 200
|
||||
}
|
||||
},
|
||||
sources: {
|
||||
terms: {
|
||||
field: 'source.code'
|
||||
}
|
||||
},
|
||||
slovenianHits: {
|
||||
filter: {
|
||||
multi_match: {
|
||||
query: searchString,
|
||||
operator: 'and',
|
||||
fields: [
|
||||
'term',
|
||||
'synonyms',
|
||||
'label',
|
||||
'definition',
|
||||
'other',
|
||||
'domainLabels',
|
||||
'links'
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
foreign: {
|
||||
nested: {
|
||||
path: 'foreignEntries'
|
||||
},
|
||||
aggs: {
|
||||
targetLanguages: {
|
||||
terms: {
|
||||
field: 'foreignEntries.lang.id',
|
||||
size: 50
|
||||
}
|
||||
},
|
||||
foreignHits: {
|
||||
filter: {
|
||||
multi_match: {
|
||||
query: searchString,
|
||||
operator: 'and',
|
||||
fields: [
|
||||
'foreignEntries.terms',
|
||||
'foreignEntries.synonyms',
|
||||
'foreignEntries.definition'
|
||||
]
|
||||
}
|
||||
},
|
||||
aggs: {
|
||||
sourceLanguages: {
|
||||
terms: {
|
||||
field: 'foreignEntries.lang.id',
|
||||
size: 50
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return queryDsl
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
// TODO Consider alternative paging when hits exceed 10000.
|
||||
|
||||
module.exports = function (filters, hitsPerPage, page) {
|
||||
const queryDsl = {
|
||||
from: hitsPerPage * (page - 1),
|
||||
size: hitsPerPage,
|
||||
query: {
|
||||
bool: {
|
||||
filter: [
|
||||
{
|
||||
term: {
|
||||
isPublished: true
|
||||
}
|
||||
},
|
||||
{
|
||||
term: {
|
||||
'dictionary.status': 'published'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
sort: ['_score', 'term.sort', 'homonymSort']
|
||||
}
|
||||
|
||||
if (filters.primaryDomains.length) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
terms: {
|
||||
'primaryDomain.id': filters.primaryDomains
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (filters.dictionaries.length) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
terms: {
|
||||
'dictionary.id': filters.dictionaries
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (filters.sources.length) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
terms: {
|
||||
'source.code': filters.sources
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (filters.targetLanguages.length) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
nested: {
|
||||
path: 'foreignEntries',
|
||||
query: {
|
||||
terms: {
|
||||
'foreignEntries.lang.id': filters.targetLanguages
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return queryDsl
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
const { separateSlovenianLanguage } = require('../..')
|
||||
|
||||
// TODO Consider alternative paging when hits exceed 10000.
|
||||
|
||||
module.exports = async function (searchString, filters, hitsPerPage, page) {
|
||||
const queryDsl = {
|
||||
from: hitsPerPage * (page - 1),
|
||||
size: hitsPerPage,
|
||||
query: {
|
||||
bool: {
|
||||
must: {
|
||||
dis_max: {
|
||||
queries: [
|
||||
{
|
||||
constant_score: {
|
||||
filter: {
|
||||
term: {
|
||||
'term.keyword': {
|
||||
value: searchString
|
||||
}
|
||||
}
|
||||
},
|
||||
boost: 6
|
||||
}
|
||||
},
|
||||
{
|
||||
constant_score: {
|
||||
filter: {
|
||||
match_phrase: {
|
||||
term: searchString
|
||||
}
|
||||
},
|
||||
boost: 5
|
||||
}
|
||||
},
|
||||
{
|
||||
constant_score: {
|
||||
filter: {
|
||||
nested: {
|
||||
path: 'foreignEntries',
|
||||
query: {
|
||||
term: {
|
||||
'foreignEntries.terms.keyword': {
|
||||
value: searchString
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
boost: 4
|
||||
}
|
||||
},
|
||||
{
|
||||
constant_score: {
|
||||
filter: {
|
||||
nested: {
|
||||
path: 'foreignEntries',
|
||||
query: {
|
||||
match_phrase: {
|
||||
'foreignEntries.terms': searchString
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
boost: 3
|
||||
}
|
||||
},
|
||||
{
|
||||
constant_score: {
|
||||
filter: {
|
||||
dis_max: {
|
||||
queries: [
|
||||
{
|
||||
match_phrase: {
|
||||
synonyms: searchString
|
||||
}
|
||||
},
|
||||
{
|
||||
nested: {
|
||||
path: 'foreignEntries',
|
||||
query: {
|
||||
match_phrase: {
|
||||
'foreignEntries.synonyms': searchString
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
boost: 2
|
||||
}
|
||||
},
|
||||
{
|
||||
constant_score: {
|
||||
filter: {
|
||||
dis_max: {
|
||||
queries: [
|
||||
{
|
||||
multi_match: {
|
||||
query: searchString,
|
||||
type: 'phrase',
|
||||
fields: [
|
||||
'label',
|
||||
'definition',
|
||||
'other',
|
||||
'domainLabels',
|
||||
'links'
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
nested: {
|
||||
path: 'foreignEntries',
|
||||
query: {
|
||||
match_phrase: {
|
||||
'foreignEntries.definition': searchString
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
boost: 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
filter: [
|
||||
{
|
||||
term: {
|
||||
isPublished: true
|
||||
}
|
||||
},
|
||||
{
|
||||
term: {
|
||||
'dictionary.status': 'published'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
sort: ['_score', 'term.sort', 'homonymSort']
|
||||
}
|
||||
|
||||
if (filters.primaryDomains.length) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
terms: {
|
||||
'primaryDomain.id': filters.primaryDomains
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (filters.dictionaries.length) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
terms: {
|
||||
'dictionary.id': filters.dictionaries
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (filters.sources.length) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
terms: {
|
||||
'source.code': filters.sources
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (filters.targetLanguages.length) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
nested: {
|
||||
path: 'foreignEntries',
|
||||
query: {
|
||||
terms: {
|
||||
'foreignEntries.lang.id': filters.targetLanguages
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (filters.sourceLanguages.length) {
|
||||
const [foreignLanguages, isSlovenianSource] =
|
||||
await separateSlovenianLanguage(filters.sourceLanguages)
|
||||
|
||||
const sourceLanguageFilter = {
|
||||
dis_max: {
|
||||
queries: []
|
||||
}
|
||||
}
|
||||
|
||||
if (isSlovenianSource) {
|
||||
sourceLanguageFilter.dis_max.queries.push({
|
||||
multi_match: {
|
||||
query: searchString,
|
||||
type: 'phrase',
|
||||
fields: [
|
||||
'term',
|
||||
'synonyms',
|
||||
'label',
|
||||
'definition',
|
||||
'other',
|
||||
'domainLabels',
|
||||
'links'
|
||||
]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (foreignLanguages.length) {
|
||||
sourceLanguageFilter.dis_max.queries.push({
|
||||
nested: {
|
||||
path: 'foreignEntries',
|
||||
query: {
|
||||
bool: {
|
||||
must: [
|
||||
{
|
||||
terms: {
|
||||
'foreignEntries.lang.id': foreignLanguages
|
||||
}
|
||||
},
|
||||
{
|
||||
multi_match: {
|
||||
query: searchString,
|
||||
type: 'phrase',
|
||||
fields: [
|
||||
'foreignEntries.terms',
|
||||
'foreignEntries.synonyms',
|
||||
'foreignEntries.definition'
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
queryDsl.query.bool.filter.push(sourceLanguageFilter)
|
||||
}
|
||||
|
||||
return queryDsl
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
const { separateSlovenianLanguage, queryForField } = require('../..')
|
||||
|
||||
const whitespace = /\s+/
|
||||
|
||||
// TODO Consider alternative paging when hits exceed 10000.
|
||||
|
||||
module.exports = async function (searchString, filters, hitsPerPage, page) {
|
||||
const searchTokens = searchString.split(whitespace)
|
||||
|
||||
const termQuery = queryForField('term', searchTokens)
|
||||
const foreignTermQuery = queryForField('foreignEntries.terms', searchTokens)
|
||||
const synonymsQuery = queryForField('synonyms', searchTokens)
|
||||
const foreignSynonymsQuery = queryForField(
|
||||
'foreignEntries.synonyms',
|
||||
searchTokens
|
||||
)
|
||||
const labelQuery = queryForField('label', searchTokens)
|
||||
const definitionQuery = queryForField('definition', searchTokens)
|
||||
const otherQuery = queryForField('other', searchTokens)
|
||||
const domainLabelsQuery = queryForField('domainLabels', searchTokens)
|
||||
const linksQuery = queryForField('links', searchTokens)
|
||||
const foreignDefinitionQuery = queryForField(
|
||||
'foreignEntries.definition',
|
||||
searchTokens
|
||||
)
|
||||
|
||||
const slovenianFieldQueries = [
|
||||
termQuery,
|
||||
synonymsQuery,
|
||||
labelQuery,
|
||||
definitionQuery,
|
||||
otherQuery,
|
||||
domainLabelsQuery,
|
||||
linksQuery
|
||||
]
|
||||
|
||||
const foreignFieldQueries = [
|
||||
foreignTermQuery,
|
||||
foreignSynonymsQuery,
|
||||
foreignDefinitionQuery
|
||||
]
|
||||
|
||||
const queryDsl = {
|
||||
from: hitsPerPage * (page - 1),
|
||||
size: hitsPerPage,
|
||||
query: {
|
||||
bool: {
|
||||
must: {
|
||||
dis_max: {
|
||||
queries: [
|
||||
{
|
||||
constant_score: {
|
||||
filter: termQuery,
|
||||
boost: 5
|
||||
}
|
||||
},
|
||||
{
|
||||
constant_score: {
|
||||
filter: {
|
||||
nested: {
|
||||
path: 'foreignEntries',
|
||||
query: foreignTermQuery
|
||||
}
|
||||
},
|
||||
boost: 3
|
||||
}
|
||||
},
|
||||
{
|
||||
constant_score: {
|
||||
filter: {
|
||||
dis_max: {
|
||||
queries: [
|
||||
synonymsQuery,
|
||||
{
|
||||
nested: {
|
||||
path: 'foreignEntries',
|
||||
query: foreignSynonymsQuery
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
boost: 2
|
||||
}
|
||||
},
|
||||
{
|
||||
constant_score: {
|
||||
filter: {
|
||||
dis_max: {
|
||||
queries: [
|
||||
labelQuery,
|
||||
definitionQuery,
|
||||
otherQuery,
|
||||
domainLabelsQuery,
|
||||
linksQuery,
|
||||
{
|
||||
nested: {
|
||||
path: 'foreignEntries',
|
||||
query: foreignDefinitionQuery
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
boost: 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
filter: [
|
||||
{
|
||||
term: {
|
||||
isPublished: true
|
||||
}
|
||||
},
|
||||
{
|
||||
term: {
|
||||
'dictionary.status': 'published'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
sort: ['_score', 'term.sort', 'homonymSort']
|
||||
}
|
||||
|
||||
if (filters.primaryDomains.length) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
terms: {
|
||||
'primaryDomain.id': filters.primaryDomains
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (filters.dictionaries.length) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
terms: {
|
||||
'dictionary.id': filters.dictionaries
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (filters.sources.length) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
terms: {
|
||||
'source.code': filters.sources
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (filters.targetLanguages.length) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
nested: {
|
||||
path: 'foreignEntries',
|
||||
query: {
|
||||
terms: {
|
||||
'foreignEntries.lang.id': filters.targetLanguages
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (filters.sourceLanguages.length) {
|
||||
const [foreignLanguages, isSlovenianSource] =
|
||||
await separateSlovenianLanguage(filters.sourceLanguages)
|
||||
|
||||
const sourceLanguageFilter = {
|
||||
dis_max: {
|
||||
queries: []
|
||||
}
|
||||
}
|
||||
|
||||
if (isSlovenianSource) {
|
||||
sourceLanguageFilter.dis_max.queries.push(...slovenianFieldQueries)
|
||||
}
|
||||
|
||||
if (foreignLanguages.length) {
|
||||
sourceLanguageFilter.dis_max.queries.push({
|
||||
nested: {
|
||||
path: 'foreignEntries',
|
||||
query: {
|
||||
bool: {
|
||||
must: [
|
||||
{
|
||||
terms: {
|
||||
'foreignEntries.lang.id': foreignLanguages
|
||||
}
|
||||
},
|
||||
{
|
||||
dis_max: {
|
||||
queries: foreignFieldQueries
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
queryDsl.query.bool.filter.push(sourceLanguageFilter)
|
||||
}
|
||||
|
||||
return [queryDsl, slovenianFieldQueries, foreignFieldQueries]
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
const { separateSlovenianLanguage } = require('../..')
|
||||
|
||||
// TODO Consider alternative paging when hits exceed 10000.
|
||||
|
||||
module.exports = async function (searchString, filters, hitsPerPage, page) {
|
||||
const queryDsl = {
|
||||
from: hitsPerPage * (page - 1),
|
||||
size: hitsPerPage,
|
||||
query: {
|
||||
bool: {
|
||||
must: {
|
||||
dis_max: {
|
||||
queries: [
|
||||
{
|
||||
constant_score: {
|
||||
filter: {
|
||||
match: {
|
||||
term: {
|
||||
query: searchString,
|
||||
operator: 'and'
|
||||
}
|
||||
}
|
||||
},
|
||||
boost: 5
|
||||
}
|
||||
},
|
||||
{
|
||||
constant_score: {
|
||||
filter: {
|
||||
nested: {
|
||||
path: 'foreignEntries',
|
||||
query: {
|
||||
match: {
|
||||
'foreignEntries.terms': {
|
||||
query: searchString,
|
||||
operator: 'and'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
boost: 3
|
||||
}
|
||||
},
|
||||
{
|
||||
constant_score: {
|
||||
filter: {
|
||||
dis_max: {
|
||||
queries: [
|
||||
{
|
||||
match: {
|
||||
synonyms: {
|
||||
query: searchString,
|
||||
operator: 'and'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
nested: {
|
||||
path: 'foreignEntries',
|
||||
query: {
|
||||
match: {
|
||||
'foreignEntries.synonyms': {
|
||||
query: searchString,
|
||||
operator: 'and'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
boost: 2
|
||||
}
|
||||
},
|
||||
{
|
||||
constant_score: {
|
||||
filter: {
|
||||
dis_max: {
|
||||
queries: [
|
||||
{
|
||||
multi_match: {
|
||||
query: searchString,
|
||||
operator: 'and',
|
||||
fields: [
|
||||
'label',
|
||||
'definition',
|
||||
'other',
|
||||
'domainLabels',
|
||||
'links'
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
nested: {
|
||||
path: 'foreignEntries',
|
||||
query: {
|
||||
match: {
|
||||
'foreignEntries.definition': {
|
||||
query: searchString,
|
||||
operator: 'and'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
boost: 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
filter: [
|
||||
{
|
||||
term: {
|
||||
isPublished: true
|
||||
}
|
||||
},
|
||||
{
|
||||
term: {
|
||||
'dictionary.status': 'published'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
sort: ['_score', 'term.sort', 'homonymSort']
|
||||
}
|
||||
|
||||
if (filters.primaryDomains.length) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
terms: {
|
||||
'primaryDomain.id': filters.primaryDomains
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (filters.dictionaries.length) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
terms: {
|
||||
'dictionary.id': filters.dictionaries
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (filters.sources.length) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
terms: {
|
||||
'source.code': filters.sources
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (filters.targetLanguages.length) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
nested: {
|
||||
path: 'foreignEntries',
|
||||
query: {
|
||||
terms: {
|
||||
'foreignEntries.lang.id': filters.targetLanguages
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (filters.sourceLanguages.length) {
|
||||
const [foreignLanguages, isSlovenianSource] =
|
||||
await separateSlovenianLanguage(filters.sourceLanguages)
|
||||
|
||||
const sourceLanguageFilter = {
|
||||
dis_max: {
|
||||
queries: []
|
||||
}
|
||||
}
|
||||
|
||||
if (isSlovenianSource) {
|
||||
sourceLanguageFilter.dis_max.queries.push({
|
||||
multi_match: {
|
||||
query: searchString,
|
||||
operator: 'and',
|
||||
fields: [
|
||||
'term',
|
||||
'synonyms',
|
||||
'label',
|
||||
'definition',
|
||||
'other',
|
||||
'domainLabels',
|
||||
'links'
|
||||
]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (foreignLanguages.length) {
|
||||
sourceLanguageFilter.dis_max.queries.push({
|
||||
nested: {
|
||||
path: 'foreignEntries',
|
||||
query: {
|
||||
bool: {
|
||||
must: [
|
||||
{
|
||||
terms: {
|
||||
'foreignEntries.lang.id': foreignLanguages
|
||||
}
|
||||
},
|
||||
{
|
||||
multi_match: {
|
||||
query: searchString,
|
||||
operator: 'and',
|
||||
fields: [
|
||||
'foreignEntries.terms',
|
||||
'foreignEntries.synonyms',
|
||||
'foreignEntries.definition'
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
queryDsl.query.bool.filter.push(sourceLanguageFilter)
|
||||
}
|
||||
|
||||
return queryDsl
|
||||
}
|
||||
@@ -0,0 +1,262 @@
|
||||
const { separateSlovenianLanguage } = require('../..')
|
||||
|
||||
// TODO Consider alternative paging when hits exceed 10000.
|
||||
|
||||
module.exports = async function (searchString, filters, hitsPerPage, page) {
|
||||
const queryDsl = {
|
||||
from: hitsPerPage * (page - 1),
|
||||
size: hitsPerPage,
|
||||
query: {
|
||||
bool: {
|
||||
must: {
|
||||
dis_max: {
|
||||
queries: [
|
||||
{
|
||||
constant_score: {
|
||||
filter: {
|
||||
term: {
|
||||
'term.keyword': {
|
||||
value: searchString
|
||||
}
|
||||
}
|
||||
},
|
||||
boost: 6
|
||||
}
|
||||
},
|
||||
{
|
||||
constant_score: {
|
||||
filter: {
|
||||
match: {
|
||||
term: {
|
||||
query: searchString,
|
||||
operator: 'and'
|
||||
}
|
||||
}
|
||||
},
|
||||
boost: 5
|
||||
}
|
||||
},
|
||||
{
|
||||
constant_score: {
|
||||
filter: {
|
||||
nested: {
|
||||
path: 'foreignEntries',
|
||||
query: {
|
||||
term: {
|
||||
'foreignEntries.terms.keyword': {
|
||||
value: searchString
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
boost: 4
|
||||
}
|
||||
},
|
||||
{
|
||||
constant_score: {
|
||||
filter: {
|
||||
nested: {
|
||||
path: 'foreignEntries',
|
||||
query: {
|
||||
match: {
|
||||
'foreignEntries.terms': {
|
||||
query: searchString,
|
||||
operator: 'and'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
boost: 3
|
||||
}
|
||||
},
|
||||
{
|
||||
constant_score: {
|
||||
filter: {
|
||||
dis_max: {
|
||||
queries: [
|
||||
{
|
||||
match: {
|
||||
synonyms: {
|
||||
query: searchString,
|
||||
operator: 'and'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
nested: {
|
||||
path: 'foreignEntries',
|
||||
query: {
|
||||
match: {
|
||||
'foreignEntries.synonyms': {
|
||||
query: searchString,
|
||||
operator: 'and'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
boost: 2
|
||||
}
|
||||
},
|
||||
{
|
||||
constant_score: {
|
||||
filter: {
|
||||
dis_max: {
|
||||
queries: [
|
||||
{
|
||||
multi_match: {
|
||||
query: searchString,
|
||||
operator: 'and',
|
||||
fields: [
|
||||
'label',
|
||||
'definition',
|
||||
'other',
|
||||
'domainLabels',
|
||||
'links'
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
nested: {
|
||||
path: 'foreignEntries',
|
||||
query: {
|
||||
match: {
|
||||
'foreignEntries.definition': {
|
||||
query: searchString,
|
||||
operator: 'and'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
boost: 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
filter: [
|
||||
{
|
||||
term: {
|
||||
isPublished: true
|
||||
}
|
||||
},
|
||||
{
|
||||
term: {
|
||||
'dictionary.status': 'published'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
sort: ['_score', 'term.sort', 'homonymSort']
|
||||
}
|
||||
|
||||
if (filters.primaryDomains.length) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
terms: {
|
||||
'primaryDomain.id': filters.primaryDomains
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (filters.dictionaries.length) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
terms: {
|
||||
'dictionary.id': filters.dictionaries
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (filters.sources.length) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
terms: {
|
||||
'source.code': filters.sources
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (filters.targetLanguages.length) {
|
||||
queryDsl.query.bool.filter.push({
|
||||
nested: {
|
||||
path: 'foreignEntries',
|
||||
query: {
|
||||
terms: {
|
||||
'foreignEntries.lang.id': filters.targetLanguages
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (filters.sourceLanguages.length) {
|
||||
const [foreignLanguages, isSlovenianSource] =
|
||||
await separateSlovenianLanguage(filters.sourceLanguages)
|
||||
|
||||
const sourceLanguageFilter = {
|
||||
dis_max: {
|
||||
queries: []
|
||||
}
|
||||
}
|
||||
|
||||
if (isSlovenianSource) {
|
||||
sourceLanguageFilter.dis_max.queries.push({
|
||||
multi_match: {
|
||||
query: searchString,
|
||||
operator: 'and',
|
||||
fields: [
|
||||
'term',
|
||||
'synonyms',
|
||||
'label',
|
||||
'definition',
|
||||
'other',
|
||||
'domainLabels',
|
||||
'links'
|
||||
]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (foreignLanguages.length) {
|
||||
sourceLanguageFilter.dis_max.queries.push({
|
||||
nested: {
|
||||
path: 'foreignEntries',
|
||||
query: {
|
||||
bool: {
|
||||
must: [
|
||||
{
|
||||
terms: {
|
||||
'foreignEntries.lang.id': foreignLanguages
|
||||
}
|
||||
},
|
||||
{
|
||||
multi_match: {
|
||||
query: searchString,
|
||||
operator: 'and',
|
||||
fields: [
|
||||
'foreignEntries.terms',
|
||||
'foreignEntries.synonyms',
|
||||
'foreignEntries.definition'
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
queryDsl.query.bool.filter.push(sourceLanguageFilter)
|
||||
}
|
||||
|
||||
return queryDsl
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
const Portal = require('../../portal')
|
||||
const { getSlovenianLanguageId } = require('..')
|
||||
|
||||
const slCollator = new Intl.Collator('sl', { sensitivity: 'base' })
|
||||
|
||||
// Return a new array, with slovenian language removed and isSlovenianSource set to true if present.
|
||||
exports.separateSlovenianLanguage = async languages => {
|
||||
const slovenianLanguageId = await getSlovenianLanguageId()
|
||||
let isSlovenianSource = false
|
||||
|
||||
const foreignLanguages = languages.filter(language => {
|
||||
if (language !== slovenianLanguageId) return true
|
||||
|
||||
isSlovenianSource = true
|
||||
return false
|
||||
})
|
||||
|
||||
return [foreignLanguages, isSlovenianSource]
|
||||
}
|
||||
|
||||
// Simplify and enhance search engine's hits output into useful entries object.
|
||||
exports.prepareEntries = hits => {
|
||||
const entriesByCategory = hits.body.hits.hits.reduce(
|
||||
(agg, hit) => {
|
||||
const entry = hit._source
|
||||
|
||||
switch (hit._score) {
|
||||
case 6:
|
||||
case 5:
|
||||
agg.byTerm.push(entry)
|
||||
break
|
||||
case 4:
|
||||
case 3:
|
||||
agg.byForeignTerm.push(entry)
|
||||
break
|
||||
case 2:
|
||||
case 1:
|
||||
agg.byOther.push(entry)
|
||||
break
|
||||
default:
|
||||
agg.uncategorized.push(entry)
|
||||
}
|
||||
|
||||
return agg
|
||||
},
|
||||
{ byTerm: [], byForeignTerm: [], byOther: [], uncategorized: [] }
|
||||
)
|
||||
|
||||
return entriesByCategory
|
||||
}
|
||||
|
||||
// Transform search engine's aggregation raw output into correct and friendly format.
|
||||
exports.prepareAggregation = async aggregationRaw => {
|
||||
const { aggregations, hits } = aggregationRaw.body
|
||||
|
||||
const hitsCount = hits.total.value
|
||||
if (!hitsCount) return
|
||||
|
||||
const primaryDomainIds = aggregations.primaryDomains.buckets.map(
|
||||
bucket => bucket.key
|
||||
)
|
||||
|
||||
const dictionaryIds = aggregations.dictionaries.buckets.map(
|
||||
bucket => bucket.key
|
||||
)
|
||||
|
||||
const languageIdSet = new Set()
|
||||
const refinedSourceLanguageBuckets = []
|
||||
|
||||
aggregations.foreign.targetLanguages.buckets.forEach(bucket =>
|
||||
languageIdSet.add(bucket.key)
|
||||
)
|
||||
|
||||
const slovenianHitCount = aggregations.slovenianHits?.doc_count
|
||||
// "Match all" aggregation returns no slovenian hits and source languages.
|
||||
if (slovenianHitCount) {
|
||||
const slovenianLanguageId = await getSlovenianLanguageId()
|
||||
const slovenianBucket = {
|
||||
key: slovenianLanguageId,
|
||||
doc_count: slovenianHitCount
|
||||
}
|
||||
let wasSlovenianBucketInserted = false
|
||||
|
||||
aggregations.foreign.foreignHits.sourceLanguages.buckets.forEach(bucket => {
|
||||
if (!wasSlovenianBucketInserted && bucket.doc_count < slovenianHitCount) {
|
||||
languageIdSet.add(slovenianLanguageId)
|
||||
refinedSourceLanguageBuckets.push(slovenianBucket)
|
||||
wasSlovenianBucketInserted = true
|
||||
}
|
||||
languageIdSet.add(bucket.key)
|
||||
refinedSourceLanguageBuckets.push(bucket)
|
||||
})
|
||||
|
||||
if (!wasSlovenianBucketInserted) {
|
||||
languageIdSet.add(slovenianLanguageId)
|
||||
refinedSourceLanguageBuckets.push(slovenianBucket)
|
||||
}
|
||||
} else if (slovenianHitCount === 0) {
|
||||
aggregations.foreign.foreignHits.sourceLanguages.buckets.forEach(bucket => {
|
||||
languageIdSet.add(bucket.key)
|
||||
refinedSourceLanguageBuckets.push(bucket)
|
||||
})
|
||||
}
|
||||
|
||||
const languageIds = [...languageIdSet]
|
||||
|
||||
const names = await Portal.getSearchAggregateNames(
|
||||
primaryDomainIds,
|
||||
dictionaryIds,
|
||||
languageIds
|
||||
)
|
||||
|
||||
const aggregation = {
|
||||
sourceLanguages: refinedSourceLanguageBuckets.map(
|
||||
({ key: id, doc_count: hits }) => {
|
||||
return { id, name: names.languages[id], hits }
|
||||
}
|
||||
),
|
||||
targetLanguages: aggregations.foreign.targetLanguages.buckets.map(
|
||||
({ key: id, doc_count: hits }) => {
|
||||
return { id, name: names.languages[id], hits }
|
||||
}
|
||||
),
|
||||
primaryDomains: aggregations.primaryDomains.buckets.map(
|
||||
({ key: id, doc_count: hits }) => {
|
||||
return { id, name: names.primaryDomains[id], hits }
|
||||
}
|
||||
),
|
||||
dictionaries: aggregations.dictionaries.buckets.map(
|
||||
({ key: id, doc_count: hits }) => {
|
||||
return { id, name: names.dictionaries[id], hits }
|
||||
}
|
||||
),
|
||||
sources: aggregations.sources.buckets.map(
|
||||
({ key: id, doc_count: hits }) => {
|
||||
return { id, name: id, hits }
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
sortAggregation(aggregation)
|
||||
|
||||
return aggregation
|
||||
}
|
||||
|
||||
// Enhance aggregation for display in search filters.
|
||||
exports.prepareSeachFilterData = (aggregation, filters) => {
|
||||
const enhancedAggregation = {}
|
||||
|
||||
if (aggregation) {
|
||||
for (const category of Object.keys(aggregation)) {
|
||||
const enhancedCategoryMembers = aggregation[category].map(member => {
|
||||
if (filters[category].includes(member.id)) member.checked = true
|
||||
return member
|
||||
})
|
||||
|
||||
enhancedAggregation[category] = enhancedCategoryMembers
|
||||
}
|
||||
}
|
||||
|
||||
return enhancedAggregation
|
||||
}
|
||||
|
||||
// Maps editor search api field names into search engine ones.
|
||||
exports.fieldMap = {
|
||||
term: 'term',
|
||||
synonyms: 'synonyms',
|
||||
label: 'label',
|
||||
definition: 'definition',
|
||||
other: 'other',
|
||||
domainLabels: 'domainLabels',
|
||||
links: 'links',
|
||||
foreignTerms: 'foreignEntries.terms',
|
||||
foreignSynonyms: 'foreignEntries.synonyms',
|
||||
foreignDefinition: 'foreignEntries.definition'
|
||||
}
|
||||
|
||||
// Generate search engine DSL wildcard query fragment for a single field.
|
||||
exports.queryForField = (field, searchTokens) => {
|
||||
return {
|
||||
bool: {
|
||||
filter: searchTokens.map(token => {
|
||||
return {
|
||||
wildcard: {
|
||||
[field]: {
|
||||
value: token
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Simplify and enhance search engine's editor hits output into useful entries list.
|
||||
exports.prepareEditorEntries = hits => {
|
||||
const entries = hits.body.hits.hits.map(hit => {
|
||||
const entry = hit._source
|
||||
|
||||
entry.foreignTerm = hit.fields['foreignEntries.terms']?.[0]
|
||||
entry.commentActivityIndicator = hit.fields.commentActivityIndicator[0]
|
||||
|
||||
return entry
|
||||
})
|
||||
|
||||
return entries
|
||||
}
|
||||
|
||||
function sortAggregation(aggregation) {
|
||||
for (const categoryBuckets of Object.values(aggregation)) {
|
||||
categoryBuckets.sort(bucketCompareFn)
|
||||
}
|
||||
}
|
||||
|
||||
function bucketCompareFn(bucketA, bucketB) {
|
||||
if (bucketA.hits !== bucketB.hits) return 0
|
||||
return slCollator.compare(bucketA.name, bucketB.name)
|
||||
}
|
||||
|
||||
// Simplify search engine's consultancy hits output into useful entries list.
|
||||
exports.prepareConsultancyEntries = hits => {
|
||||
const entries = hits.body.hits.hits.map(hit => hit._source)
|
||||
|
||||
return entries
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
exports.deserialize = {
|
||||
userById(user) {
|
||||
const deserializedUser = {
|
||||
id: user.id,
|
||||
userName: user.username,
|
||||
firstName: user.first_name,
|
||||
lastName: user.last_name,
|
||||
email: user.email,
|
||||
hitsPerPage: user.hits_per_page,
|
||||
userRoles: user.user_roles,
|
||||
assignedConsultancyEntries: user.assigned_consultancy_entries
|
||||
}
|
||||
|
||||
return deserializedUser
|
||||
},
|
||||
|
||||
user(userData) {
|
||||
const deserializedData = {
|
||||
id: userData.id,
|
||||
userName: userData.username,
|
||||
firstName: userData.first_name,
|
||||
lastName: userData.last_name,
|
||||
email: userData.email,
|
||||
password: userData.password
|
||||
}
|
||||
|
||||
return deserializedData
|
||||
},
|
||||
|
||||
userRights(userData) {
|
||||
const deserializedRights = {
|
||||
id: userData.id,
|
||||
userName: userData.username,
|
||||
email: userData.email,
|
||||
hasAdministration: userData.administration,
|
||||
hasEditing: userData.editing,
|
||||
hasTerminologyReview: userData.terminology_review,
|
||||
hasLanguageReview: userData.language_review
|
||||
}
|
||||
return deserializedRights
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user