214 lines
4.6 KiB
TypeScript
214 lines
4.6 KiB
TypeScript
|
import { CONFIG } from '../initializers/constants'
|
||
|
import { VideoChannel } from '@shared/models'
|
||
|
import { buildIndex, buildSort, elasticSearch, extractQueryResult, indexDocuments } from '../helpers/elastic-search'
|
||
|
import { logger } from '../helpers/logger'
|
||
|
import { DBChannel, IndexableChannel } from '../types/channel.model'
|
||
|
import { ChannelsSearchQuery } from '../types/channel-search.model'
|
||
|
import { buildAvatarMapping, formatAvatarForAPI, formatAvatarForDB } from './elastic-search-avatar'
|
||
|
|
||
|
function initChannelsIndex () {
|
||
|
return buildIndex(CONFIG.ELASTIC_SEARCH.INDEXES.CHANNELS, buildChannelsMapping())
|
||
|
}
|
||
|
|
||
|
async function indexChannels (channels: IndexableChannel[], replace = false) {
|
||
|
return indexDocuments({
|
||
|
objects: channels,
|
||
|
formatter: c => formatChannelForDB(c),
|
||
|
replace,
|
||
|
index: CONFIG.ELASTIC_SEARCH.INDEXES.CHANNELS
|
||
|
})
|
||
|
}
|
||
|
|
||
|
function refreshChannelsIndex () {
|
||
|
return elasticSearch.indices.refresh({ index: CONFIG.ELASTIC_SEARCH.INDEXES.CHANNELS })
|
||
|
}
|
||
|
|
||
|
async function queryChannels (search: ChannelsSearchQuery) {
|
||
|
const bool: any = {}
|
||
|
|
||
|
if (search.search) {
|
||
|
Object.assign(bool, {
|
||
|
must: [
|
||
|
{
|
||
|
multi_match: {
|
||
|
query: search.search,
|
||
|
fields: [ 'name', 'displayName', 'description' ],
|
||
|
fuzziness: 'AUTO'
|
||
|
}
|
||
|
}
|
||
|
]
|
||
|
})
|
||
|
}
|
||
|
|
||
|
const body = {
|
||
|
from: search.start,
|
||
|
size: search.count,
|
||
|
sort: buildSort(search.sort),
|
||
|
query: { bool }
|
||
|
}
|
||
|
|
||
|
logger.debug('Will query Elastic Search for channels.', { body })
|
||
|
|
||
|
const res = await elasticSearch.search({
|
||
|
index: CONFIG.ELASTIC_SEARCH.INDEXES.CHANNELS,
|
||
|
body
|
||
|
})
|
||
|
|
||
|
return extractQueryResult(res)
|
||
|
}
|
||
|
|
||
|
export {
|
||
|
initChannelsIndex,
|
||
|
indexChannels,
|
||
|
refreshChannelsIndex,
|
||
|
formatChannelForAPI,
|
||
|
queryChannels
|
||
|
}
|
||
|
|
||
|
// ############################################################################
|
||
|
|
||
|
function formatChannelForDB (c: IndexableChannel): DBChannel {
|
||
|
return {
|
||
|
id: c.id,
|
||
|
|
||
|
url: c.url,
|
||
|
name: c.name,
|
||
|
host: c.host,
|
||
|
|
||
|
avatar: formatAvatarForDB(c),
|
||
|
|
||
|
displayName: c.displayName,
|
||
|
|
||
|
indexedAt: new Date(),
|
||
|
|
||
|
followingCount: c.followingCount,
|
||
|
followersCount: c.followersCount,
|
||
|
createdAt: c.createdAt,
|
||
|
updatedAt: c.updatedAt,
|
||
|
|
||
|
description: c.description,
|
||
|
support: c.support,
|
||
|
|
||
|
ownerAccount: {
|
||
|
id: c.ownerAccount.id,
|
||
|
url: c.ownerAccount.url,
|
||
|
|
||
|
displayName: c.ownerAccount.displayName,
|
||
|
description: c.ownerAccount.description,
|
||
|
name: c.ownerAccount.name,
|
||
|
host: c.ownerAccount.host,
|
||
|
followingCount: c.ownerAccount.followingCount,
|
||
|
followersCount: c.ownerAccount.followersCount,
|
||
|
createdAt: c.ownerAccount.createdAt,
|
||
|
updatedAt: c.ownerAccount.updatedAt,
|
||
|
|
||
|
avatar: formatAvatarForDB(c.ownerAccount)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function formatChannelForAPI (c: DBChannel, fromHost?: string): VideoChannel {
|
||
|
return {
|
||
|
id: c.id,
|
||
|
|
||
|
url: c.url,
|
||
|
name: c.name,
|
||
|
host: c.host,
|
||
|
followingCount: c.followingCount,
|
||
|
followersCount: c.followersCount,
|
||
|
createdAt: c.createdAt,
|
||
|
updatedAt: c.updatedAt,
|
||
|
avatar: formatAvatarForAPI(c),
|
||
|
|
||
|
displayName: c.displayName,
|
||
|
description: c.description,
|
||
|
support: c.support,
|
||
|
isLocal: fromHost === c.host,
|
||
|
|
||
|
ownerAccount: {
|
||
|
id: c.ownerAccount.id,
|
||
|
url: c.ownerAccount.url,
|
||
|
|
||
|
displayName: c.ownerAccount.displayName,
|
||
|
description: c.ownerAccount.description,
|
||
|
name: c.ownerAccount.name,
|
||
|
host: c.ownerAccount.host,
|
||
|
followingCount: c.ownerAccount.followingCount,
|
||
|
followersCount: c.ownerAccount.followersCount,
|
||
|
createdAt: c.ownerAccount.createdAt,
|
||
|
updatedAt: c.ownerAccount.updatedAt,
|
||
|
|
||
|
avatar: formatAvatarForAPI(c.ownerAccount)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function buildChannelOrAccountCommonMapping () {
|
||
|
return {
|
||
|
id: {
|
||
|
type: 'long'
|
||
|
},
|
||
|
|
||
|
url: {
|
||
|
type: 'keyword'
|
||
|
},
|
||
|
|
||
|
name: {
|
||
|
type: 'text',
|
||
|
fields: {
|
||
|
raw: {
|
||
|
type: 'keyword'
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
host: {
|
||
|
type: 'keyword'
|
||
|
},
|
||
|
|
||
|
displayName: {
|
||
|
type: 'text'
|
||
|
},
|
||
|
|
||
|
avatar: {
|
||
|
properties: buildAvatarMapping()
|
||
|
},
|
||
|
|
||
|
followingCount: {
|
||
|
type: 'long'
|
||
|
},
|
||
|
followersCount: {
|
||
|
type: 'long'
|
||
|
},
|
||
|
|
||
|
createdAt: {
|
||
|
type: 'date',
|
||
|
format: 'date_optional_time'
|
||
|
},
|
||
|
updatedAt: {
|
||
|
type: 'date',
|
||
|
format: 'date_optional_time'
|
||
|
},
|
||
|
|
||
|
description: {
|
||
|
type: 'text'
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function buildChannelsMapping () {
|
||
|
const base = buildChannelOrAccountCommonMapping()
|
||
|
|
||
|
Object.assign(base, {
|
||
|
support: {
|
||
|
type: 'keyword'
|
||
|
},
|
||
|
|
||
|
ownerAccount: {
|
||
|
properties: buildChannelOrAccountCommonMapping()
|
||
|
}
|
||
|
})
|
||
|
|
||
|
return base
|
||
|
}
|