init
This commit is contained in:
55
lib/rocketchat/channels.js
Normal file
55
lib/rocketchat/channels.js
Normal file
@@ -0,0 +1,55 @@
|
||||
const _ = require('lodash')
|
||||
const Factory = require('../factory')
|
||||
const slug = require("slug");
|
||||
|
||||
//
|
||||
// Initialize the child logger for
|
||||
// the module
|
||||
//
|
||||
const log = require('../log').child({
|
||||
module: 'channels'
|
||||
})
|
||||
|
||||
module.exports = async function (context) {
|
||||
const collection = context.rocketchat.roomsCollection()
|
||||
const query = { t: { $in: ['c', 'p'] } }
|
||||
|
||||
let channels = {}
|
||||
const cursor = collection.find(query)
|
||||
const mergeDiscussions = _.get(context, 'config.define.channels.mergeDiscussionIntoParent', false)
|
||||
const discussions = {}
|
||||
while (await cursor.hasNext()) {
|
||||
const result = await cursor.next()
|
||||
if (mergeDiscussions && result.prid) {
|
||||
discussions[result._id] = result.prid
|
||||
log.info(`... skipping channel ${result._id} to merge discussion into parent ${result.prid}`)
|
||||
continue;
|
||||
}
|
||||
|
||||
// Define the channel and add it to the context
|
||||
let channel = channels[result._id] = {
|
||||
team: context.values.team.name,
|
||||
name: slug(_.toLower(result.name)),
|
||||
display_name: result.name,
|
||||
header: result.topic,
|
||||
purpose: result.description,
|
||||
type: result.t === 'p' ? 'P' : 'O'
|
||||
}
|
||||
const map = _.get(context, `config.define.channels.map.${result.name}`, false)
|
||||
if (map) {
|
||||
channel.name = map.name
|
||||
channel.display_name = map.display_name
|
||||
}
|
||||
// Write the channel data to the output
|
||||
log.info(`... writing ${channel.name} (${result.name})`)
|
||||
context.output.write(
|
||||
Factory.channel(channel)
|
||||
)
|
||||
}
|
||||
if (!context.values.discussions) {
|
||||
context.values.discussions = {}
|
||||
}
|
||||
context.values.discussions = Object.assign(context.values.discussions, discussions)
|
||||
context.values.channels = channels
|
||||
return context
|
||||
}
|
||||
60
lib/rocketchat/directChannels.js
Normal file
60
lib/rocketchat/directChannels.js
Normal file
@@ -0,0 +1,60 @@
|
||||
const Factory = require('../factory')
|
||||
const Utils = require('./utils')
|
||||
const _ = require("lodash");
|
||||
|
||||
//
|
||||
// Initialize the child logger for
|
||||
// the module
|
||||
//
|
||||
const log = require('../log').child({
|
||||
module: 'directChannels'
|
||||
})
|
||||
|
||||
module.exports = async function(context) {
|
||||
// Select all of the rooms
|
||||
const collection = context.rocketchat.roomsCollection()
|
||||
const query = { t: 'd' }
|
||||
|
||||
const directChannels = {}
|
||||
const cursor = collection.find(query)
|
||||
const mergeDiscussions = _.get(context, 'config.define.channels.mergeDiscussionIntoParent', false)
|
||||
const discussions = {}
|
||||
while (await cursor.hasNext()) {
|
||||
const result = await cursor.next()
|
||||
if (mergeDiscussions && result.prid) {
|
||||
discussions[result._id] = result.prid
|
||||
log.info(`... skipping direct channel ${result._id} to merge discussion into parent ${result.prid}`)
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
// Generate the members array for the direct channel
|
||||
let members = Utils.members(
|
||||
context.values.users,
|
||||
result.uids,
|
||||
)
|
||||
if (members.length === 1) {
|
||||
members.push(members[0])
|
||||
}
|
||||
// If there at least two members
|
||||
if (Utils.membersAreValid(members)) {
|
||||
log.info(`... writing members (${members.join(', ')})`)
|
||||
let channel = directChannels[result._id] = {
|
||||
header: result.topic,
|
||||
members
|
||||
}
|
||||
context.output.write(
|
||||
Factory.directChannel(channel)
|
||||
)
|
||||
}
|
||||
} catch (err) {
|
||||
log.error(`... ignoring directChannel members (${result.usernames.join(', ')}) on error: ${err.message}.`)
|
||||
}
|
||||
}
|
||||
if (!context.values.discussions) {
|
||||
context.values.discussions = {}
|
||||
}
|
||||
context.values.discussions = Object.assign(context.values.discussions, discussions)
|
||||
context.values.directChannels = directChannels
|
||||
return context
|
||||
}
|
||||
75
lib/rocketchat/emoji.js
Normal file
75
lib/rocketchat/emoji.js
Normal file
@@ -0,0 +1,75 @@
|
||||
const Factory = require('../factory')
|
||||
const Utils = require('./utils')
|
||||
|
||||
//
|
||||
// Initialize the child logger for
|
||||
// the module
|
||||
//
|
||||
const log = require('../log').child({
|
||||
module: 'custom emoji'
|
||||
})
|
||||
|
||||
module.exports = async function (context) {
|
||||
const collection = context.rocketchat.emojiCollection()
|
||||
const fileCollection = context.rocketchat.collection('custom_emoji')
|
||||
|
||||
const cursor = collection.find()
|
||||
while (await cursor.hasNext()) {
|
||||
const result = await cursor.next()
|
||||
|
||||
// Prepare destination file
|
||||
const filename = `${result.name}.${result.extension}`
|
||||
const dest = `${context.config.target.filesPath}/custom_emoji/${filename}`
|
||||
// Download emoji file
|
||||
if (result.store.startsWith('FileSystem:')) {
|
||||
const src = context.config.source.customEmojiPath
|
||||
const srcFilename = Utils.srcPath(src, filename)
|
||||
if (!srcFilename) {
|
||||
return new Error(`source file "${filename}" not found`)
|
||||
}
|
||||
// Copy to output dir
|
||||
Utils.copyFile(srcFilename, dest)
|
||||
} else if (result.store.startsWith('GridFS:')) {
|
||||
await Utils.downloadGridFS(context, fileCollection, filename, dest)
|
||||
} else {
|
||||
throw new Error(`file system ${file.store} is not supported. Migrate to FileSystem first, see readme.`)
|
||||
}
|
||||
|
||||
// Export custom emoji
|
||||
let emoji = {
|
||||
name: result.name,
|
||||
image: dest,
|
||||
}
|
||||
log.info(`... writing ${emoji.name}`)
|
||||
context.output.write(
|
||||
Factory.emoji(emoji)
|
||||
)
|
||||
}
|
||||
return context
|
||||
}
|
||||
|
||||
const exportFile = async function (context, collection, fileId) {
|
||||
const type = collection.collectionName
|
||||
const file = await collection.findOne({ _id: fileId })
|
||||
if (!file) {
|
||||
throw new Error(`file ${fileId} from collection ${type} is missing`)
|
||||
}
|
||||
const dest = context.config.target.filesPath
|
||||
const destFilename = utils.destPath(dest, collection.collectionName, file)
|
||||
|
||||
if (file.store.startsWith('FileSystem:')) {
|
||||
const src = context.config.source.uploadsPath
|
||||
const srcFilename = utils.srcPath(src, file._id)
|
||||
if (!srcFilename) {
|
||||
return new Error(`source file "${file._id}" not found`)
|
||||
}
|
||||
// Copy to output dir
|
||||
utils.copyFile(srcFilename, destFilename)
|
||||
} else if (file.store.startsWith('GridFS:')) {
|
||||
await utils.downloadGridFS(context, collection, file._id, destFilename)
|
||||
} else {
|
||||
throw new Error(`file system ${file.store} is not supported. Migrate to FileSystem first, see readme.`)
|
||||
}
|
||||
|
||||
return destFilename
|
||||
}
|
||||
13
lib/rocketchat/end.js
Normal file
13
lib/rocketchat/end.js
Normal file
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// Initialize the child logger for
|
||||
// the module
|
||||
//
|
||||
const log = require('../log').child({
|
||||
module: 'end'
|
||||
})
|
||||
|
||||
module.exports = function(context) {
|
||||
log.info('end')
|
||||
context.rocketchat.close()
|
||||
context.output.end()
|
||||
}
|
||||
21
lib/rocketchat/index.js
Normal file
21
lib/rocketchat/index.js
Normal file
@@ -0,0 +1,21 @@
|
||||
const start = require('./start')
|
||||
const version = require('./version')
|
||||
const emoji = require('./emoji')
|
||||
const team = require('./team')
|
||||
const channels = require('./channels')
|
||||
const users = require('./users')
|
||||
const posts = require('./posts')
|
||||
const directChannels = require('./directChannels')
|
||||
const end = require('./end')
|
||||
|
||||
module.exports = {
|
||||
start,
|
||||
version,
|
||||
emoji,
|
||||
team,
|
||||
channels,
|
||||
users,
|
||||
posts,
|
||||
directChannels,
|
||||
end
|
||||
}
|
||||
162
lib/rocketchat/posts.js
Normal file
162
lib/rocketchat/posts.js
Normal file
@@ -0,0 +1,162 @@
|
||||
const Factory = require('../factory')
|
||||
const Utils = require('./utils')
|
||||
const _ = require('lodash')
|
||||
|
||||
//
|
||||
// Initialize the child logger for
|
||||
// the module
|
||||
//
|
||||
const log = require('../log').child({
|
||||
module: 'posts'
|
||||
})
|
||||
|
||||
module.exports = async function (context) {
|
||||
const collection = context.rocketchat.messagesCollection()
|
||||
// Keep track of the number of posts written for logging
|
||||
let written = 0
|
||||
|
||||
let memReplyIds = {}
|
||||
const total = await collection.count()
|
||||
const cursor = collection.find()
|
||||
while (await cursor.hasNext()) {
|
||||
const result = await cursor.next()
|
||||
let posts = await collectPostData(context, result, memReplyIds, false)
|
||||
posts.forEach(function(post) {
|
||||
context.output.write(post.isDirect ? Factory.directPost(post) : Factory.post(post))
|
||||
})
|
||||
// Log progress periodically
|
||||
written += posts.length
|
||||
if (written % 1000 == 0) {
|
||||
log.info(`... wrote ${written} posts`)
|
||||
}
|
||||
}
|
||||
log.info(`... finished exporting ${written} posts, ignored ${total - written}`)
|
||||
return context
|
||||
}
|
||||
|
||||
async function collectPostData(context, result, memReplyIds, isReply) {
|
||||
if (memReplyIds.hasOwnProperty(result._id)) {
|
||||
return []
|
||||
}
|
||||
|
||||
try {
|
||||
// Try to get discussion channel id
|
||||
let channelId = result.rid
|
||||
const mergeDiscussions = _.get(context, 'config.define.channels.mergeDiscussionIntoParent', false)
|
||||
const parentId = _.get(context, `values.discussions.${channelId}`, false)
|
||||
if (mergeDiscussions && parentId) {
|
||||
channelId = parentId
|
||||
}
|
||||
// Check if direct message
|
||||
let isDirect = !context.values.channels[channelId] && !!context.values.directChannels[channelId]
|
||||
let post = {}
|
||||
let channelInfo = {}
|
||||
|
||||
if (isDirect) {
|
||||
let { members: channel_members } = context.values.directChannels[channelId]
|
||||
// Ensure we have at least two channel members before we can write the message
|
||||
if (Utils.membersAreValid(channel_members)) {
|
||||
channelInfo = { channel_members }
|
||||
} else {
|
||||
log.error(`... ignoring message id:${result._id} on error: directChannel ${channelId} not found.`)
|
||||
return []
|
||||
}
|
||||
} else {
|
||||
channelInfo = {
|
||||
team: context.values.team.name,
|
||||
channel: Utils.channelName(
|
||||
context.values.channels, channelId
|
||||
),
|
||||
}
|
||||
}
|
||||
if (!isReply) {
|
||||
Object.assign(post, channelInfo)
|
||||
}
|
||||
|
||||
const reactions = Object.keys(result.reactions || {}).reduce((prev, code) => {
|
||||
return result.reactions[code].usernames.map((u) => {
|
||||
return {
|
||||
user: u,
|
||||
emoji_name: _.trim(code, ':'),
|
||||
create_at: Utils.millis(result.ts),
|
||||
}
|
||||
}).concat(prev)
|
||||
}, [])
|
||||
const flagged_by = (result.starred || []).map(({ _id: uid }) => {
|
||||
try {
|
||||
return Utils.username(context.values.users, uid)
|
||||
} catch (err) {
|
||||
return undefined
|
||||
}
|
||||
}).filter(v => v)
|
||||
|
||||
Object.assign(post, {
|
||||
user: Utils.username(
|
||||
context.values.users, result.u._id
|
||||
),
|
||||
create_at: Utils.millis(result.ts),
|
||||
reactions,
|
||||
flagged_by,
|
||||
isDirect,
|
||||
})
|
||||
|
||||
// Collect data from attachments
|
||||
let attachments = Utils.processAttachments(context, result)
|
||||
let file
|
||||
let body = result.msg
|
||||
|
||||
await Promise.all(attachments.map(async (a) => {
|
||||
if (a.type === 'file') {
|
||||
file = await a.data
|
||||
} else if (a.type === 'quote') {
|
||||
body = a.data
|
||||
}
|
||||
}))
|
||||
if (file && file instanceof Error) {
|
||||
throw file
|
||||
}
|
||||
|
||||
if (file && file.description) {
|
||||
body = `File description: \n${file.description} \n\n ${body}`
|
||||
}
|
||||
const chunks = body ? Utils.body(body) : [body]
|
||||
let posts = chunks.map((chunk) => {
|
||||
return Object.assign({}, post, {
|
||||
message: chunk
|
||||
})
|
||||
})
|
||||
|
||||
if (!posts[0]) {
|
||||
throw new Error(`Post is empty`)
|
||||
}
|
||||
|
||||
if (file) {
|
||||
posts[0].attachments = [{
|
||||
path: file.path
|
||||
}]
|
||||
}
|
||||
|
||||
const replies = []
|
||||
if (!isReply) {
|
||||
const collection = context.rocketchat.messagesCollection()
|
||||
const cursor = collection.find({tmid: result._id })
|
||||
while (await cursor.hasNext()) {
|
||||
const reply = await cursor.next()
|
||||
const replyData = await collectPostData(context, reply, memReplyIds, true)
|
||||
replyData.forEach(r => replies.push(r))
|
||||
memReplyIds[reply._id] = true
|
||||
}
|
||||
}
|
||||
|
||||
Object.assign(posts[0], {
|
||||
reactions,
|
||||
flagged_by,
|
||||
replies,
|
||||
})
|
||||
|
||||
return posts
|
||||
} catch (err) {
|
||||
log.error(`... ignoring message id:${result._id} on error: ${err.message}.`)
|
||||
return []
|
||||
}
|
||||
}
|
||||
32
lib/rocketchat/start.js
Normal file
32
lib/rocketchat/start.js
Normal file
@@ -0,0 +1,32 @@
|
||||
const datafile = require('../datafile')
|
||||
const fs = require('fs');
|
||||
|
||||
//
|
||||
// Initialize the child logger for
|
||||
// the module
|
||||
//
|
||||
const log = require('../log').child({
|
||||
module: 'start'
|
||||
})
|
||||
|
||||
module.exports = async function(context) {
|
||||
log.info('preparing files paths')
|
||||
const dest = context.config.target.filesPath
|
||||
if (!dest || !fs.existsSync(dest)) {
|
||||
fs.mkdirSync(dest)
|
||||
}
|
||||
if (!fs.lstatSync(dest).isDirectory() || fs.accessSync(dest, fs.constants.W_OK)) {
|
||||
throw new Error(`Directory "${dest} is not writable"`)
|
||||
}
|
||||
|
||||
log.info('connecting to rocketchat')
|
||||
await context.rocketchat.connect(context.config)
|
||||
log.info(`creating file '${context.config.target.filename}'`)
|
||||
// Create the datafile and add it to the context
|
||||
context.output = datafile(
|
||||
context.config.target.filename,
|
||||
process.exit
|
||||
)
|
||||
|
||||
return context
|
||||
}
|
||||
29
lib/rocketchat/team.js
Normal file
29
lib/rocketchat/team.js
Normal file
@@ -0,0 +1,29 @@
|
||||
const Factory = require('../factory')
|
||||
|
||||
//
|
||||
// Initialize the child logger for
|
||||
// the module
|
||||
//
|
||||
const log = require('../log').child({
|
||||
module: 'team'
|
||||
})
|
||||
|
||||
module.exports = function(context) {
|
||||
log.info(`writing team '${context.config.define.team.name}'`)
|
||||
//
|
||||
// Store the team object for use
|
||||
// by other modules
|
||||
//
|
||||
context.values.team = context.config.define.team
|
||||
//
|
||||
// Write the team object to the
|
||||
// output
|
||||
//
|
||||
context.output.write(Factory.team(
|
||||
context.config.define.team
|
||||
))
|
||||
//
|
||||
// Return a resolved promise
|
||||
//
|
||||
return Promise.resolve(context)
|
||||
}
|
||||
105
lib/rocketchat/users.js
Normal file
105
lib/rocketchat/users.js
Normal file
@@ -0,0 +1,105 @@
|
||||
const Factory = require('../factory')
|
||||
const Utils = require('./utils')
|
||||
const { Gitlab } = require('@gitbeaker/node')
|
||||
const _ = require('lodash')
|
||||
|
||||
//
|
||||
// Initialize the child logger for
|
||||
// the module
|
||||
//
|
||||
const log = require('../log').child({
|
||||
module: 'users'
|
||||
})
|
||||
|
||||
module.exports = async function(context) {
|
||||
const collection = context.rocketchat.usersCollection()
|
||||
|
||||
let users = {}
|
||||
const cursor = collection.find({ type: 'user' })
|
||||
while (await cursor.hasNext()) {
|
||||
const result = await cursor.next()
|
||||
const id = result._id
|
||||
const [first_name, last_name] = result.name.split(' ')
|
||||
try {
|
||||
const ldapAuthService = _.get(context, 'config.define.user.ldap_auth_service', '')
|
||||
const roleMap = _.get(context, 'config.define.user.globalRoleMap', {})
|
||||
const auth_service = result.ldap ? ldapAuthService : ''
|
||||
if (result.roles.indexOf('admin') !== -1 && result.roles.indexOf('user') === -1) {
|
||||
result.roles.push('user')
|
||||
}
|
||||
const highlights = _.get(result, 'settings.preferences.highlights', [])
|
||||
let user = users[id] = {
|
||||
username: result.username,
|
||||
first_name,
|
||||
last_name,
|
||||
auth_service,
|
||||
auth_data: await getAuthData(context, result, auth_service),
|
||||
email: result.emails[0].address,
|
||||
roles: result.roles.sort().reduce((roles, role) => {
|
||||
if (roleMap.hasOwnProperty(role)) {
|
||||
roles.push(roleMap[role])
|
||||
}
|
||||
return roles
|
||||
}, []).join(' '),
|
||||
teams: [{
|
||||
name: context.values.team.name,
|
||||
channels: result.__rooms.map((id) => {
|
||||
const name = _.get(context, `values.channels.${id}.name`, false)
|
||||
return name ? { name } : undefined
|
||||
}).filter(v => v)
|
||||
}],
|
||||
notify_props: {
|
||||
mention_keys: highlights.map(s => s.replace('@', '')).join(','),
|
||||
},
|
||||
}
|
||||
if (auth_service) {
|
||||
user.auth_service = auth_service
|
||||
user.auth_data = await getAuthData(context, result, auth_service)
|
||||
}
|
||||
if (!user.roles.length) {
|
||||
delete user.roles
|
||||
}
|
||||
const avatar = await getAvatar(context, result)
|
||||
if (avatar) {
|
||||
user.profile_image = avatar
|
||||
}
|
||||
|
||||
context.output.write(
|
||||
Factory.user(user)
|
||||
)
|
||||
log.info(`... writing ${user.username}`)
|
||||
}
|
||||
catch(err) {
|
||||
log.error(`... ignoring ${result.username} on error: ${err.message}.`)
|
||||
delete users[id]
|
||||
}
|
||||
}
|
||||
context.values.users = users
|
||||
return context
|
||||
}
|
||||
|
||||
async function getAuthData(context, user, auth_service) {
|
||||
switch (auth_service) {
|
||||
case 'gitlab':
|
||||
const {host, token} = _.get(context, 'config.define.user.gitlab')
|
||||
const api = new Gitlab({ host, token });
|
||||
const gitlabUser = await api.Users.username(user.username);
|
||||
if (!gitlabUser || !gitlabUser.length) {
|
||||
throw new Error(`user ${user.username} is missing in Gitlab`)
|
||||
}
|
||||
return `${gitlabUser[0].id}`
|
||||
case 'ldap':
|
||||
return user.username.toUpperCase()
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
async function getAvatar(context, user) {
|
||||
const collection = context.rocketchat.avatarsCollection()
|
||||
const avatar = await collection.findOne({userId: user._id}, {sort: {_updatedAt: -1}})
|
||||
if (!avatar) {
|
||||
return ""
|
||||
}
|
||||
return Utils.exportFile(context, collection, avatar._id)
|
||||
}
|
||||
191
lib/rocketchat/utils.js
Normal file
191
lib/rocketchat/utils.js
Normal file
@@ -0,0 +1,191 @@
|
||||
const _ = require('lodash')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
//
|
||||
// Declare utils object
|
||||
//
|
||||
const utils = {}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
utils.chunk = function(body) {
|
||||
//
|
||||
// Use regex to create an array
|
||||
// of strings of max length
|
||||
//
|
||||
return body.match(/[\s\S]{1,4000}/g)
|
||||
}
|
||||
|
||||
//
|
||||
// Lookup values
|
||||
//
|
||||
utils.lookup = function (type, map, key) {
|
||||
var found = map[key]
|
||||
|
||||
if(!found) {
|
||||
throw new Error(`${type} ${key} not found`)
|
||||
}
|
||||
|
||||
return found
|
||||
}
|
||||
|
||||
//
|
||||
// Obtain the username from a jid
|
||||
//
|
||||
utils.username = function (users, id) {
|
||||
return utils.lookup('user', users, id).username
|
||||
}
|
||||
|
||||
//
|
||||
// Obtain the channel name from a jid
|
||||
//
|
||||
utils.channelName = function (channels, id) {
|
||||
return utils.lookup('channel', channels, id).name
|
||||
}
|
||||
|
||||
//
|
||||
// Find the message body
|
||||
//
|
||||
utils.body = function (body) {
|
||||
return utils.chunk(body)
|
||||
}
|
||||
|
||||
utils.processAttachments = function (context, message) {
|
||||
if (!message.attachments) {
|
||||
return []
|
||||
}
|
||||
return message.attachments.map((attachment) => {
|
||||
if (attachment.type && attachment.type === 'file') {
|
||||
return {
|
||||
type: 'file',
|
||||
data: utils.processFileAttachment(context, message, attachment),
|
||||
}
|
||||
}
|
||||
if (attachment.text) {
|
||||
return {
|
||||
type: 'quote',
|
||||
data: utils.processQuoteAttachment(message, attachment)
|
||||
}
|
||||
}
|
||||
return {
|
||||
type: 'unknown'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
utils.processQuoteAttachment = function (message, attachment) {
|
||||
if (!attachment.text) {
|
||||
return ''
|
||||
}
|
||||
const body = (message.msg || '').replace(/\[ \]\(.*msg=.*?\) /, '')
|
||||
// Convert quote to markdown
|
||||
return `@${attachment.author_name}:\n ${attachment.text.replace(/^/, '> ')} \n\n${body}`
|
||||
}
|
||||
|
||||
utils.processFileAttachment = async function (context, message, attachment) {
|
||||
if (!message.file) {
|
||||
return new Error(`message ${message._id} file is missing`)
|
||||
}
|
||||
const collection = context.rocketchat.uploadsCollection()
|
||||
return {
|
||||
description: attachment.description,
|
||||
path: await utils.exportFile(context, collection, message.file._id),
|
||||
}
|
||||
}
|
||||
|
||||
utils.srcPath = function (srcDir, filename) {
|
||||
const files = fs.readdirSync(srcDir).filter((fn) => fn.startsWith(filename));
|
||||
if (files.length !== 1) {
|
||||
return false
|
||||
}
|
||||
return `${srcDir}/${path.basename(files[0])}`
|
||||
}
|
||||
|
||||
utils.destPath = function (destDir, type, file) {
|
||||
let dest = `${destDir}/${type}/${file._id}/${file.name}`;
|
||||
const ext = path.extname(dest)
|
||||
if (!ext || !/^\.[A-Za-z][A-Za-z0-9]*$/.test(ext)) {
|
||||
if (file.identify && file.identify.format) {
|
||||
dest += '.' + file.identify.format
|
||||
} else {
|
||||
dest += '.' + file.type.split('/')[1]
|
||||
}
|
||||
}
|
||||
return dest
|
||||
}
|
||||
|
||||
utils.exportFile = async function (context, collection, fileId) {
|
||||
const type = collection.collectionName
|
||||
const file = await collection.findOne({ _id: fileId })
|
||||
if (!file) {
|
||||
throw new Error(`file ${fileId} from collection ${type} is missing`)
|
||||
}
|
||||
const dest = context.config.target.filesPath
|
||||
const destFilename = utils.destPath(dest, collection.collectionName, file)
|
||||
|
||||
if (file.store.startsWith('FileSystem:')) {
|
||||
const src = context.config.source.uploadsPath
|
||||
const srcFilename = utils.srcPath(src, file._id)
|
||||
if (!srcFilename) {
|
||||
return new Error(`source file "${file._id}" not found`)
|
||||
}
|
||||
// Copy to output dir
|
||||
utils.copyFile(srcFilename, destFilename)
|
||||
} else if (file.store.startsWith('GridFS:')) {
|
||||
await utils.downloadGridFS(context, collection, file._id, destFilename)
|
||||
} else {
|
||||
throw new Error(`file system ${file.store} is not supported. Migrate to FileSystem first, see readme.`)
|
||||
}
|
||||
|
||||
return destFilename
|
||||
}
|
||||
|
||||
utils.copyFile = function (src, dest) {
|
||||
if (!fs.existsSync(path.dirname(dest))) {
|
||||
fs.mkdirSync(path.dirname(dest), { recursive: true })
|
||||
}
|
||||
if (!fs.existsSync(dest)) {
|
||||
fs.copyFileSync(src, dest)
|
||||
}
|
||||
}
|
||||
|
||||
utils.downloadGridFS = async function (context, collection, id, dest) {
|
||||
if (!fs.existsSync(path.dirname(dest))) {
|
||||
fs.mkdirSync(path.dirname(dest), { recursive: true })
|
||||
}
|
||||
if (fs.existsSync(dest)) {
|
||||
fs.unlinkSync(dest)
|
||||
}
|
||||
|
||||
const bucket = context.rocketchat.gridFsBucket(collection.collectionName)
|
||||
const destStream = fs.createWriteStream(dest);
|
||||
bucket.openDownloadStream(id).pipe(destStream);
|
||||
return new Promise((resolve, reject) => {
|
||||
destStream.on('finish', resolve);
|
||||
})
|
||||
}
|
||||
|
||||
utils.members = function(users, usernames) {
|
||||
return _.uniq(_.sortBy(usernames.map((username) => utils.username(users, username))))
|
||||
}
|
||||
|
||||
//
|
||||
// Checks if the members list is valid
|
||||
//
|
||||
utils.membersAreValid = function(members) {
|
||||
return _.isArray(members) && members.length > 0
|
||||
}
|
||||
|
||||
//
|
||||
// Convert ISO to millis
|
||||
//
|
||||
utils.millis = function(date) {
|
||||
return new Date(date).getTime()
|
||||
}
|
||||
|
||||
//
|
||||
// Export the functions
|
||||
//
|
||||
module.exports = utils
|
||||
12
lib/rocketchat/version.js
Normal file
12
lib/rocketchat/version.js
Normal file
@@ -0,0 +1,12 @@
|
||||
const Factory = require('../factory')
|
||||
|
||||
module.exports = function(context) {
|
||||
//
|
||||
// Write the version object
|
||||
//
|
||||
context.output.write(Factory.version())
|
||||
//
|
||||
// Return a resolved promise
|
||||
//
|
||||
return Promise.resolve(context)
|
||||
}
|
||||
Reference in New Issue
Block a user