UNPKG

7.33 kBJavaScriptView Raw
1#! /usr/bin/env node
2// vim:set sw=2 ts=2 sts=2 ft=javascript expandtab:
3'use strict';
4
5// Dependencies
6var program = require('commander'),
7 fs = require('fs'),
8 path = require('path');
9
10var _cliProgress = require('cli-progress');
11
12var ueberDB = require('ueberdb2'),
13 jsonminify = require('jsonminify'),
14 eachSeries = require('async/eachSeries'),
15 eachOfSeries = require('async/eachOfSeries');
16
17// Arguments handling
18program
19 .version('0.1.0')
20 .option('-s, --settings <file>', '[MANDATORY] the path to your Etherpad\'s settings.json file')
21 .option('-n, --dryrun', '(optional) just count the number of pads that would have been normally deleted')
22 .parse(process.argv);
23
24// Check that we have the mandatory arguments
25if (!program.settings) {
26 console.log('');
27 console.log('=====================================================================');
28 console.log(' You must provide the path to your Etherpad\'s settings.json file!');
29 console.log('=====================================================================');
30 program.help();
31}
32
33// Try to parse the settings
34var settingsFilename = path.resolve(program.settings);
35var settingsStr = fs.readFileSync(settingsFilename).toString();
36var settings;
37try {
38 if(settingsStr) {
39 settingsStr = jsonminify(settingsStr).replace(',]',']').replace(',}','}');
40 settings = JSON.parse(settingsStr);
41 }
42} catch(e) {
43 console.error('There was an error processing your settings.json file: '+e.message);
44 process.exit(1);
45}
46
47// Open the database
48var db = new ueberDB.database(settings.dbType, settings.dbSettings);
49
50/*
51 * Functions
52 */
53function exitIfErr(err) {
54 console.log('=====================');
55 console.error(err);
56 return db.doShutdown(function() { process.exit(1); });
57}
58
59// Remove record from DB
60function removeRecord(key, callback) {
61 db.remove(key, function(err) {
62 if (err) { return exitIfErr(err); }
63 callback();
64 });
65}
66
67/*
68 * Start searching
69 */
70db.init(function(err) {
71 if (err) { return exitIfErr(err); }
72
73 db.get('mypads:conf:allowEtherPads', function(err, val) {
74 if (err) { return exitIfErr(err); }
75
76 // Yeah, we don't want to remove anonymous pads
77 if (val !== false) {
78 console.log(' _______________');
79 console.log('|===============|');
80 console.log('|: .---------. :|');
81 console.log('|: | HAL-9000| :|');
82 console.log('|: \'---------\' :|');
83 console.log('|: :| ________________________________________');
84 console.log('|: :| / I\'m sorry, Dave, I\'m afraid I can\'t do \\');
85 console.log('|: :| \\ that. /');
86 console.log('|: :| ----------------------------------------');
87 console.log('|: _ :| /');
88 console.log('|: ,` `. :| __/');
89 console.log('|: : (o) : :|');
90 console.log('|: `. _ ,` :|');
91 console.log('|: :|');
92 console.log('|:_____________:|');
93 console.log('|:=============:|');
94 console.log('|:*%*%*%*%*%*%*:|');
95 console.log('|:%*%*%*%*%*%*%:|');
96 console.log('|:*%*%*%*%*%*%*:|');
97 console.log('|:%*%*%*%*%*%*%:|');
98 console.log('\'===============\'');
99 console.log('');
100 console.log('================================================');
101 console.log('It seems that you allow anonymous pads.');
102 console.log('This script would delete all the anonymous pads.');
103 console.log('Exiting');
104 console.log('================================================');
105 return db.doShutdown(function() { process.exit(1); });
106 }
107
108 // readonly2pad:* records are leftovers of deleted pads before #197 was solved
109 db.findKeys('readonly2pad:*', null, function(err, keys) {
110 if (err) { return exitIfErr(err); }
111
112 var candidatesForDeletion = 0;
113
114 if (keys.length === 0) {
115 console.log('No pads to check.');
116 return db.doShutdown(function() { process.exit(0); });
117 }
118
119 console.log(keys.length+' pad(s) to check.');
120
121 // I love progress bars, it's cool
122 var bar = new _cliProgress.Bar({
123 format: '[{bar}] {percentage}% | ETA: {eta}s | {val}/{tot}',
124 stopOnComplete: true,
125 hideCursor: true,
126 barsize: 60,
127 fps: 60
128 }, _cliProgress.Presets.shades_grey);
129 bar.start(2 * keys.length, 0, { val: 0, tot: keys.length });
130
131 // For each readonly2pad record, do pad existence check
132 eachOfSeries(keys, function(readonly2pad, index, next) {
133 bar.increment(1, { val: index + 1 });
134
135 // First, get the padId
136 db.get(readonly2pad, function(err, padId) {
137 if (err) { return exitIfErr(err); }
138
139 // Then, check if the pad exists in MyPads
140 db.get('mypads:pad:'+padId, function(err, val) {
141 if (err) { return exitIfErr(err); }
142
143 // Launch a delete process if the pad doesn't exist
144 if (val === null) {
145 if (program.dryrun) {
146 bar.increment();
147 candidatesForDeletion++;
148 return next();
149 }
150 // Cascade deletion process
151 // 1. Delete the readonly2pad record
152 db.remove(readonly2pad, function(err) {
153 if (err) { return exitIfErr(err); }
154
155 // 2. Delete the pad2readonly:padId record
156 db.remove('pad2readonly:'+padId, function(err) {
157 if (err) { return exitIfErr(err); }
158
159 // 3. Delete the pad:padId record
160 db.remove('pad:'+padId, function(err) {
161 if (err) { return exitIfErr(err); }
162
163 // 4. Check for revs records
164 db.findKeys('pad:'+padId+':revs:*', null, function(err, keys) {
165 if (err) { return exitIfErr(err); }
166
167 // 5. Delete the revs records
168 eachSeries(keys, removeRecord, function(err) {
169 if (err) { return exitIfErr(err); }
170 // 6. Check for chat records
171 db.findKeys('pad:'+padId+':chat:*', null, function(err, keys) {
172 if (err) { return exitIfErr(err); }
173
174 // 7. Delete the chat records
175 eachSeries(keys, removeRecord, function(err){
176 if (err) { return exitIfErr(err); }
177 bar.increment();
178 return next();
179 });
180 });
181 });
182 });
183 });
184 });
185 });
186 } else {
187 // No deletion needed
188 bar.increment();
189 return next();
190 }
191 });
192 });
193 }, function(err) {
194 if (err) { return exitIfErr(err); }
195
196 // Give time for progress bar to update before exiting
197 setTimeout(function() {
198 console.log(keys.length+' pad(s) checked.');
199
200 if (program.dryrun) {
201 console.log(candidatesForDeletion+' pad(s) would have been deleted.');
202 }
203
204 return db.doShutdown(function() { process.exit(0); });
205 }, 100);
206 });
207 });
208 });
209});