├── .gitignore ├── config.sample.json ├── package.json ├── LICENSE ├── README.md └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | package-lock.json 3 | config.json 4 | export.csv 5 | export.json 6 | -------------------------------------------------------------------------------- /config.sample.json: -------------------------------------------------------------------------------- 1 | { 2 | "protocol": "https", 3 | "host": "rocketchat.domain.com", 4 | "port": "443", 5 | "username": "admin", 6 | "password": "password" 7 | } 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rocketchat-export-channel-messages", 3 | "version": "1.0.0", 4 | "description": "Simple Node CLI tool to export all messages of a given Rocket.Chat channel", 5 | "main": "index.js", 6 | "dependencies": { 7 | "commander": "^2.19.0", 8 | "json-2-csv": "^3.2.0", 9 | "rocketchat": "git://github.com/frdmn/rocketchat-node.git" 10 | }, 11 | "devDependencies": {}, 12 | "scripts": { 13 | "start": "node index.js", 14 | "test": "echo \"Error: no test specified\" && exit 1" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/frdmn/rocketchat-export-channel-messages.git" 19 | }, 20 | "keywords": [ 21 | "rocket.chat" 22 | ], 23 | "author": "Jonas Friedmann ", 24 | "license": "MIT", 25 | "bugs": { 26 | "url": "https://github.com/frdmn/rocketchat-export-channel-messages/issues" 27 | }, 28 | "homepage": "https://github.com/frdmn/rocketchat-export-channel-messages#readme" 29 | } 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 Jonas Friedmann 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rocketchat-export-channel-messages 2 | 3 | ![](https://up.frd.mn/WTPKyFpRUM.png) 4 | 5 | Simple Node CLI tool to export all messages of a given [Rocket.Chat](https://rocket.chat/) channel or private group. 6 | 7 | ## Installation 8 | 9 | 1. Make sure you've installed all requirements 10 | 2. Clone this repository and enter it: 11 | 12 | ```shell 13 | git clone https://github.com/frdmn/rocketchat-export-channel-messages 14 | cd rocketchat-export-channel-messages 15 | ``` 16 | 17 | 3. Copy and adjust configuration file from sample (On Windows you can open the config.json file with e.g. notepad and edit it manually, if you don't have bash or vi installed.): 18 | 19 | ```shell 20 | cp config.sample.json config.json 21 | vi config.json 22 | ``` 23 | 24 | Make sure it contains proper user (with administration access) credentials 25 | 26 | 3. Install the project dependencies: 27 | 28 | ```shell 29 | npm install 30 | ``` 31 | 32 | ## Usage 33 | 34 | Here's a short explanation how to use `rocketchat-export-channel-messages`: 35 | 36 | To export as CSV (default), run: 37 | 38 | ```shell 39 | node index.js --room 40 | ``` 41 | 42 | If you rather have a JSON export, pass the `--json` argument: 43 | 44 | ```shell 45 | node index.js --room --json 46 | ``` 47 | 48 | ## Contributing 49 | 50 | 1. Fork it 51 | 2. Create your feature branch: 52 | 53 | ```shell 54 | git checkout -b feature/my-new-feature 55 | ``` 56 | 57 | 3. Commit your changes: 58 | 59 | ```shell 60 | git commit -am 'Add some feature' 61 | ``` 62 | 63 | 4. Push to the branch: 64 | 65 | ```shell 66 | git push origin feature/my-new-feature 67 | ``` 68 | 69 | 5. Submit a pull request 70 | 71 | ## Requirements / Dependencies 72 | 73 | * NodeJS 74 | 75 | ## Version 76 | 77 | 1.0.0 78 | 79 | ## License 80 | 81 | [MIT](LICENSE) 82 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'), 2 | converter = require('json-2-csv'), 3 | program = require('commander'), 4 | RocketChatClient = require('rocketchat').RocketChatClient; 5 | 6 | /** 7 | * Function to write error message to console and also exit the process 8 | * with error code 1 9 | * @param {String|Object} err - Object that holds the error message 10 | * @param {Integer} code - Optional status code to exit with (defaults to 1) 11 | * @return {Object} process - End process with exit code 12 | */ 13 | function error(err, code = 1){ 14 | console.log("error: ", err); 15 | return process.exit(code); 16 | } 17 | 18 | /** 19 | * Write (success) messages to console and exit the process with 20 | * error code 0 21 | * @param {String} message - String that holds the message to print 22 | * @return {Object} - Return with error code 0 23 | */ 24 | function success(message){ 25 | console.log(message); 26 | return process.exit(1); 27 | } 28 | 29 | /** 30 | * Functio to check if a given roomName is actually 31 | * a public room or a private group 32 | * @param {String} roomName room ID to test 33 | * @param {Callback} callback 34 | */ 35 | function testIfChannelOrGroup(roomName, callback){ 36 | rocketChatClient.channels.info({roomName}, function (err, body) { 37 | if (!err && body.success) { 38 | return callback({type:'channels'}); 39 | } else { 40 | rocketChatClient.groups.info({roomName}, function (err, body) { 41 | if (!err && body.success) { 42 | return callback({type:'groups'}); 43 | } else { 44 | return callback(false); 45 | } 46 | }); 47 | } 48 | }); 49 | } 50 | 51 | /** 52 | * Function to repeatedly send rocketChatClient.channels.messages() 53 | * to iterate over result pagination until final page is received 54 | * @param {String} roomType - Required roomType ('channels' or 'groups') 55 | * @param {String} roomName - Required roomName 56 | * @param {Integer} offset - Optional offset can be passed 57 | * @param {Object} callback - {data, totalCollected, roomType, roomName} 58 | */ 59 | function getHistoryOfChannelOrGroup(roomType, roomName, offset = 0, callback){ 60 | var count = 100; 61 | rocketChatClient[roomType].messages({roomName: roomName, offset: offset, count: count}, function (err, body) { 62 | if (err) error(err); 63 | 64 | // Merge new messages from API response to existing messageArray 65 | messageArray = messageArray.concat(body.messages); 66 | 67 | var totalCollected = messageArray.length; 68 | console.log('Found ' + count + ' messages... Looking for more (total: ' + totalCollected + ')...') 69 | 70 | // Check if current response still has ${count} messages, if so call self again with new offset 71 | if (body.messages.length === count){ 72 | getHistoryOfChannelOrGroup(roomType, roomName, totalCollected, callback); 73 | } else { 74 | return callback({data: messageArray, total: totalCollected, roomType: roomType.replace(/s$/, ''), roomName: roomName}); 75 | } 76 | }); 77 | } 78 | 79 | /** 80 | * Convert passed data to CSV and write to file 81 | * @param {Array} data - Data array that holds all user objects 82 | * @param {Function()} cb - Callback function 83 | */ 84 | function convertToCsvAndWriteToFile(data, cb) { 85 | // Convert to CSV 86 | converter.json2csv(data,function(err, csv){ 87 | if(err) { 88 | return cb(err); 89 | } 90 | 91 | fs.writeFile("export.csv", csv, function(err) { 92 | if(err) { 93 | return cb(err); 94 | } 95 | 96 | return cb(true); 97 | }); 98 | }, { 99 | // Do not check for key differences in each user object 100 | checkSchemaDifferences: false, 101 | // Make sure to wrap CSV values in double quotes 102 | delimiter: { 103 | wrap: '"' 104 | } 105 | }); 106 | } 107 | 108 | /** 109 | * Convert passed data to JSON and write to file 110 | * @param {Array} data - Data array that holds all user objects 111 | * @param {Function()} callback - Callback function 112 | */ 113 | function convertToJsonAndWriteToFile(data, callback) { 114 | fs.writeFile("export.json", JSON.stringify(data,null,'\t'), function(err) { 115 | if(err) { 116 | return callback(err); 117 | } 118 | 119 | return callback(true); 120 | }); 121 | } 122 | 123 | var packagejson = require('./package.json'); 124 | 125 | program 126 | .version(packagejson.version) 127 | .description(packagejson.description) 128 | .option('-r, --room [roomName]', 'roomName of channel or group to export messages from') 129 | .option('-j, --json', 'Export as JSON file rather than CSV') 130 | .parse(process.argv); 131 | 132 | // Load configuration object for RocketChat API from JSON 133 | var config = require('./config.json'); 134 | 135 | // Check for mandantory "-r" flag 136 | if (!program.room) { 137 | program.outputHelp(() => program.help()); 138 | } 139 | 140 | // Create API client 141 | var rocketChatClient = new RocketChatClient(config); 142 | 143 | // Empty array that will hold the message objects 144 | var messageArray = []; 145 | 146 | // Authenticate using admin credentials stored in config object 147 | rocketChatClient.authentication.login(config.username, config.password, function(err, body) { 148 | if (err) error(err); 149 | 150 | console.log('Trying to figure out room type of "#' + program.room + '"...'); 151 | testIfChannelOrGroup(program.room, function(result){ 152 | console.log('Looks like a ' + result.type.replace(/s$/, '') + '. Searching for messages ...'); 153 | getHistoryOfChannelOrGroup(result.type, program.room, undefined, function(data){ 154 | if (program.json){ 155 | convertToJsonAndWriteToFile(data, function(data){ 156 | success("Completed JSON export, successfully written to \"export.json\"."); 157 | }); 158 | } else { 159 | convertToCsvAndWriteToFile(data.data, function(){ 160 | success("Completed CSV export, successfully written to \"export.csv\"."); 161 | }); 162 | } 163 | }); 164 | }); 165 | }) 166 | --------------------------------------------------------------------------------