diff --git a/core/database.js b/core/database.js index e4a812d4..040cc1de 100644 --- a/core/database.js +++ b/core/database.js @@ -20,7 +20,7 @@ exports.getTransactionDatabase = getTransactionDatabase; exports.getModDatabasePath = getModDatabasePath; exports.loadDatabaseForMod = loadDatabaseForMod; exports.getISOTimestampString = getISOTimestampString; -exports.sanatizeString = sanatizeString; +exports.sanitizeString = sanitizeString; exports.initializeDatabases = initializeDatabases; exports.dbs = dbs; @@ -76,7 +76,7 @@ function getISOTimestampString(ts) { return ts.format('YYYY-MM-DDTHH:mm:ss.SSSZ'); } -function sanatizeString(s) { +function sanitizeString(s) { return s.replace(/[\0\x08\x09\x1a\n\r"'\\%]/g, c => { // eslint-disable-line no-control-regex switch (c) { case '\0' : return '\\0'; diff --git a/core/file_entry.js b/core/file_entry.js index 9ba1c692..4f5e47d1 100644 --- a/core/file_entry.js +++ b/core/file_entry.js @@ -5,7 +5,7 @@ const fileDb = require('./database.js').dbs.file; const Errors = require('./enig_error.js').Errors; const { getISOTimestampString, - sanatizeString + sanitizeString } = require('./database.js'); const Config = require('./config.js').get; @@ -565,14 +565,14 @@ module.exports = class FileEntry { `f.file_id IN ( SELECT rowid FROM file_fts - WHERE file_fts MATCH ":${sanatizeString(filter.terms)}" + WHERE file_fts MATCH ":${sanitizeString(filter.terms)}" )` ); } if(filter.tags && filter.tags.length > 0) { // build list of quoted tags; filter.tags comes in as a space and/or comma separated values - const tags = filter.tags.replace(/,/g, ' ').replace(/\s{2,}/g, ' ').split(' ').map( tag => `"${sanatizeString(tag)}"` ).join(','); + const tags = filter.tags.replace(/,/g, ' ').replace(/\s{2,}/g, ' ').split(' ').map( tag => `"${sanitizeString(tag)}"` ).join(','); appendWhereClause( `f.file_id IN ( diff --git a/core/message.js b/core/message.js index 34c590bb..7a30fb02 100644 --- a/core/message.js +++ b/core/message.js @@ -8,7 +8,7 @@ const createNamedUUID = require('./uuid_util.js').createNamedUUID; const Errors = require('./enig_error.js').Errors; const ANSI = require('./ansi_term.js'); const { - sanatizeString, + sanitizeString, getISOTimestampString } = require('./database.js'); const { @@ -354,7 +354,7 @@ module.exports = class Message { [ 'toUserName', 'fromUserName' ].forEach(field => { if(_.isString(filter[field]) && filter[field].length > 0) { - appendWhereClause(`m.${_.snakeCase(field)} LIKE "${sanatizeString(filter[field])}"`); + appendWhereClause(`m.${_.snakeCase(field)} LIKE "${sanitizeString(filter[field])}"`); } }); @@ -375,7 +375,7 @@ module.exports = class Message { `m.message_id IN ( SELECT rowid FROM message_fts - WHERE message_fts MATCH ":${sanatizeString(filter.terms)}" + WHERE message_fts MATCH ":${sanitizeString(filter.terms)}" )` ); } diff --git a/core/oputil/oputil_user.js b/core/oputil/oputil_user.js index 18519b06..3f169607 100644 --- a/core/oputil/oputil_user.js +++ b/core/oputil/oputil_user.js @@ -2,10 +2,13 @@ /* eslint-disable no-console */ 'use strict'; -const printUsageAndSetExitCode = require('./oputil_common.js').printUsageAndSetExitCode; -const ExitCodes = require('./oputil_common.js').ExitCodes; -const argv = require('./oputil_common.js').argv; -const initConfigAndDatabases = require('./oputil_common.js').initConfigAndDatabases; +const { + printUsageAndSetExitCode, + getAnswers, + ExitCodes, + argv, + initConfigAndDatabases +} = require('./oputil_common.js'); const getHelpFor = require('./oputil_help.js').getHelpFor; const Errors = require('../enig_error.js').Errors; const UserProps = require('../user_property.js'); @@ -111,8 +114,109 @@ function setUserPassword(user) { ); } -function removeUser() { - console.error('NOT YET IMPLEMENTED'); +function removeUserRecordsFromDbAndTable(dbName, tableName, userId, col, cb) { + const db = require('../../core/database.js').dbs[dbName]; + db.run( + `DELETE FROM ${tableName} + WHERE ${col} = ?;`, + [ userId ], + err => { + return cb(err); + } + ); +} + +function removeUser(user) { + async.series( + [ + (callback) => { + if(false === argv.prompt) { + return callback(null); + } + + console.info('About to permanently delete the following user:'); + console.info(`Username : ${user.username}`); + console.info(`Real name: ${user.properties[UserProps.RealName] || 'N/A'}`); + console.info(`User ID : ${user.userId}`); + console.info('WARNING: This cannot be undone!'); + getAnswers([ + { + name : 'proceed', + message : `Proceed in deleting ${user.username}?`, + type : 'confirm', + } + ], + answers => { + if(answers.proceed) { + return callback(null); + } + return callback(Errors.General('User canceled')); + }); + }, + (callback) => { + // op has confirmed they are wanting ready to proceed (or passed --no-prompt) + const DeleteFrom = { + message : [ 'user_message_area_last_read' ], + system : [ 'user_event_log', ], + user : [ 'user_group_member', 'user' ], + }; + + async.eachSeries(Object.keys(DeleteFrom), (dbName, nextDbName) => { + const tables = DeleteFrom[dbName]; + async.eachSeries(tables, (tableName, nextTableName) => { + const col = ('user' === dbName && 'user' === tableName) ? 'id' : 'user_id'; + removeUserRecordsFromDbAndTable(dbName, tableName, user.userId, col, err => { + return nextTableName(err); + }); + }, + err => { + return nextDbName(err); + }); + }, + err => { + return callback(err); + }); + }, + (callback) => { + // + // Clean up *private* messages *to* this user + // + const Message = require('../../core/message.js'); + const MsgDb = require('../../core/database.js').dbs.message; + + const filter = { + resultType : 'id', + privateTagUserId : user.userId, + }; + Message.findMessages(filter, (err, ids) => { + if(err) { + return callback(err); + } + + async.eachSeries(ids, (messageId, nextMessageId) => { + MsgDb.run( + `DELETE FROM message + WHERE message_id = ?;`, + [ messageId ], + err => { + return nextMessageId(err); + } + ); + }, + err => { + return callback(err); + }); + }); + } + ], + err => { + if(err) { + return console.error(err.reason ? err.reason : err.message); + } + + console.info('User has been deleted.'); + } + ); } function modUserGroups(user) {