@ -1,11 +1,11 @@
'use strict' ;
const _ = require ( 'lodash' ) ;
const path = require ( 'path' ) ;
const fs = require ( 'fs' ) ;
const winston = require ( 'winston' ) ;
const converter = require ( 'json - 2- csv') ;
const json2csvAsync = require ( 'json 2csv') . parseAsync ;
const archiver = require ( 'archiver' ) ;
const util = require ( 'util' ) ;
const db = require ( '../database' ) ;
const user = require ( '../user' ) ;
@ -85,10 +85,6 @@ userController.getUserDataByUID = async function (callerUid, uid) {
return userData ;
} ;
const json2csv = util . promisify ( function ( payload , options , callback ) {
converter . json2csv ( payload , callback , options ) ;
} ) ;
userController . exportPosts = async function ( req , res ) {
var payload = [ ] ;
await batch . processSortedSet ( 'uid:' + res . locals . uid + ':posts' , async function ( pids ) {
@ -103,10 +99,9 @@ userController.exportPosts = async function (req, res) {
batch : 500 ,
} ) ;
const csv = await json2csv ( payload , {
checkSchemaDifferences : false ,
emptyFieldValue : '' ,
} ) ;
const fields = payload . length ? Object . keys ( payload [ 0 ] ) : [ ] ;
const opts = { fields } ;
const csv = await json2csvAsync ( payload , opts ) ;
res . set ( 'Content-Type' , 'text/csv' ) . set ( 'Content-Disposition' , 'attachment; filename="' + res . locals . uid + '_posts.csv"' ) . send ( csv ) ;
} ;
@ -192,15 +187,67 @@ userController.exportUploads = function (req, res, next) {
} ;
userController . exportProfile = async function ( req , res ) {
const targetUid = res . locals . uid ;
const objects = await db . getObjects ( [ 'user:' + targetUid , 'user:' + targetUid + ':settings' ] ) ;
Object . assign ( objects [ 0 ] , objects [ 1 ] ) ;
delete objects [ 0 ] . password ;
const csv = await json2csv ( objects [ 0 ] , { } ) ;
res . set ( 'Content-Type' , 'text/csv' ) . set ( 'Content-Disposition' , 'attachment; filename="' + targetUid + '_profile.csv"' ) . send ( csv ) ;
const targetUid = parseInt ( res . locals . uid , 10 ) ;
const [ userData , userSettings , ips , sessions , usernames , emails , bookmarks , watchedTopics , upvoted , downvoted , following ] = await Promise . all ( [
db . getObject ( 'user:' + targetUid ) ,
db . getObject ( 'user:' + targetUid + ':settings' ) ,
user . getIPs ( targetUid , 9 ) ,
user . auth . getSessions ( targetUid , req . sessionID ) ,
user . getHistory ( 'user:' + targetUid + ':usernames' ) ,
user . getHistory ( 'user:' + targetUid + ':emails' ) ,
getSetData ( 'uid:' + targetUid + ':bookmarks' , 'post:' ) ,
getSetData ( 'uid:' + targetUid + ':followed_tids' , 'topic:' ) ,
getSetData ( 'uid:' + targetUid + ':upvote' , 'post:' ) ,
getSetData ( 'uid:' + targetUid + ':downvote' , 'post:' ) ,
getSetData ( 'following:' + targetUid , 'user:' ) ,
] ) ;
delete userData . password ;
const followingData = following . map ( u => ( { username : u . username , uid : u . uid } ) ) ;
let chatData = [ ] ;
await batch . processSortedSet ( 'uid:' + targetUid + ':chat:rooms' , async ( roomIds ) => {
var result = await Promise . all ( roomIds . map ( roomId => getRoomMessages ( targetUid , roomId ) ) ) ;
chatData = chatData . concat ( _ . flatten ( result ) ) ;
} , { batch : 100 } ) ;
res . set ( 'Content-Type' , 'application/json' )
. set ( 'Content-Disposition' , 'attachment; filename="' + targetUid + '_profile.json"' )
. send ( {
user : userData ,
settings : userSettings ,
ips : ips ,
sessions : sessions ,
usernames : usernames ,
emails : emails ,
messages : chatData ,
bookmarks : bookmarks ,
watchedTopics : watchedTopics ,
upvoted : upvoted ,
downvoted : downvoted ,
following : followingData ,
} ) ;
} ;
async function getRoomMessages ( uid , roomId ) {
let data = [ ] ;
await batch . processSortedSet ( 'uid:' + uid + ':chat:room:' + roomId + ':mids' , async ( mids ) => {
const messageData = await db . getObjects ( mids . map ( mid => 'message:' + mid ) ) ;
data = data . concat ( messageData . filter ( m => m && m . fromuid === uid && ! m . system )
. map ( m => ( { content : m . content , timestamp : m . timestamp } ) )
) ;
} , { batch : 500 } ) ;
return data ;
}
async function getSetData ( set , keyPrefix ) {
let data = [ ] ;
await batch . processSortedSet ( set , async ( ids ) => {
data = data . concat ( await db . getObjects ( ids . map ( mid => keyPrefix + mid ) ) ) ;
} , { batch : 500 } ) ;
return data ;
}
require ( '../promisify' ) ( userController , [
'getCurrentUser' , 'getUserByUID' , 'getUserByUsername' , 'getUserByEmail' ,
'exportPosts' , 'exportUploads' , 'exportProfile' ,