telegram-image-uploader-bot/botEngine.js

245 lines
8.4 KiB
JavaScript
Raw Normal View History

2019-06-26 03:20:05 +00:00
// Node imports
const fs = require('fs');
const path = require('path');
// Telegram Module
const TelegramBot = require('node-telegram-bot-api');
// Congifuration
const config = require('./config');
let admin_chatId;
let authorizedUsers;
let telegram;
const SLIDESHOW_LOCATION = config.slideShowFolderPath;
/**
* Runs the bot.
* @param {Array} args CLI arguments
* @return {void}
*/
let runBot = (args) => {
loadDB();
telegram = new TelegramBot(config.botId, {
polling: true
});
telegram.on('message', (msg) => {
const chatId = msg.chat.id;
if (args.indexOf('--printMessage') > 0) {
console.log(JSON.stringify(msg, null, 2));
process.exit(0);
}
if (userAllowd(msg)) {
handleMessage(msg);
} else {
let message = config.messages.sendieResponse.unauthorizedUser;
message = message.replace('{username}', msg.from.username);
message = message.replace('{messageObj}', JSON.stringify(msg, null, 2));
telegram.sendMessage(chatId, message);
message = config.messages.adminNotifications.unauthorizedUser;
message = message.replace('{username}', msg.from.username);
message = message.replace('{messageObj}', JSON.stringify(msg, null, 2));
console.warn(message);
notifyAdmin(message);
}
});
console.log('Telegram bot is alive and listening!');
}
/**
* Save a photo to config.slideShowFolderPath
* @param {string} fileId fileId (received from telegram)
* @param {Function} callback post save function - args: {Error} error, {string} filePath
* @return {void}
*/
function storeFile(fileId, callback) {
telegram.downloadFile(fileId, SLIDESHOW_LOCATION)
.then((filePath) => {
let message = config.messages.sendieResponse.fileSuccessfullySaved;
message = message.replace('{fileLocation}', filePath);
callback(null, filePath);
})
.catch((err) => {
callback(err);
});
}
let storeFileCallback = (err, filePath, chatId, photoId) => {
let response;
if (err) {
console.error('Failed to save file...[ERROR]\n', err);
response = config.messages.sendieResponse.failedToSaveFile;
response = response.replace('{error}', err);
telegram.sendMessage(chatId, response);
response = config.messages.sendieResponse.failedToSaveFile;
response = response.replace('{error}', err);
if (admin_chatId !== chatId) notifyAdmin(response, photoId);
} else {
response = config.messages.sendieResponse.fileSuccessfullySaved;
response = response.replace('{fileLocation}', filePath);
telegram.sendMessage(chatId, response);
response = config.messages.adminNotifications.fileSuccessfullySaved;
response = response.replace('{fileLocation}', filePath);
if (admin_chatId !== chatId) notifyAdmin(response, photoId);
}
};
/**
* This function is called on every message from an authorized user.
* @param {JSON} msg telegram message object
* @return {void}
*/
let handleMessage = (msg) => {
const chatId = msg.chat.id;
if (msg.photo || (msg.document && msg.document.mime_type.indexOf('image/') === 0)) { // Handle Images
if (msg.photo) {
storeFile(msg.photo[msg.photo.length - 1].file_id, (err, filePath) => {
storeFileCallback(err, filePath, chatId, msg.photo[msg.photo.length - 1].file_id);
});
} else { // document - uncompressed photo
storeFile(msg.document.file_id, (err, filePath) => {
storeFileCallback(err, filePath, chatId, msg.document.file_id);
});
}
} else if (msg.contact) { // Handle Contact
addRemoveUser(msg.contact, msg.from);
} else {
// send a message to the chat acknowledging receipt of their message
let message = config.messages.sendieResponse.unableToDoThat;
message = message.replace('{username}', msg.from.username);
telegram.sendMessage(chatId, message);
}
};
/**
* Check if a user is authorized to interact with this bot
* @param {JSON} msg telegram message object
* @return {boolean} true/false
*/
let userAllowd = (msg) => {
if (msg.from.id === config.admin.id) {
admin_chatId = msg.chat.id;
return true;
}
if (config.permissions.allowAll) return true;
if (authorizedUsers.indexOf(msg.from.id) >= 0) return true;
return false;
};
/**
* Sends a message to admin. Only if config.admin.notifyActivity is true
* @param {string} msg message to send
* @param {string} photo_id the photo to send to admin incase config.notifyActivity.sendPhoto is true
* @return {void}
*/
let notifyAdmin = (msg, photo_id) => {
if (admin_chatId != null && config.admin.notifyActivity) {
telegram.sendMessage(admin_chatId, msg);
if (photo_id && config.admin.sendPhotoOnSave) telegram.sendPhoto(admin_chatId, photo_id);
}
};
/**
* Will add/remove a user from authorized users list. (Saved in a file)
* If a user is not in the list, it will add him. Else remove him.
* Will notify admin if wanted (config.admin.notifyActivity) and send the initiating user on fail/success
* @param {JSON} contact Telegram contact object. The user to add/remove
* @param {JSON} from Telegram user object. Who wanted to add/remove the contact
*/
let addRemoveUser = (contact, from) => {
if (!config.permissions.allowAddingUsers) {
// Ignore...
console.warn('Attempt to add/remove a user. this functionality is disabled.');
return;
} else {
if (from.id != config.admin.id && !config.permissions.allowNonAdminToAddUsers) {
telegram.sendMessage(from.id, config.messages.sendieResponse.noPermissions);
console.warn('Attempt to add/remove a user from an unpermited user. id: ', from.id);
return;
}
}
let toAdd = true;
if (authorizedUsers.indexOf(contact.user_id) < 0) {
// Add user
authorizedUsers.push(contact.user_id);
} else {
// remove user
toAdd = false;
authorizedUsers.splice(authorizedUsers.indexOf(contact.user_id), 1);
}
if (saveToDB()) {
let message;
if (toAdd) message = config.messages.sendieResponse.userAdded;
else message = config.messages.sendieResponse.userRemoved;
message = message.replace('{username}', contact.first_name);
telegram.sendMessage(from.id, message); // response to the user that added the new one
// Not supported yet - a bot can't start a chat with a new user... so can't do this.
// if(toAdd) message = config.messages.userAdded.added;
// else message = config.messages.userRemoved.removed;
// message = message.replace('{username_add_rem}', contact.first_name);
// message = message.replace('{username}', from.first_name);
// telegram.sendMessage(contact.user_id, message); // Notify the new/old user
if (toAdd) message = config.messages.adminNotifications.userAdded;
else message = config.messages.adminNotifications.userRemoved;
message = message.replace('{username_add_rem}', contact.first_name);
message = message.replace('{username}', from.first_name);
if (from.id != config.admin.id) notifyAdmin(message); // notifyAdmin
} else {
console.log('Failed to save DB!!!');
}
}
/**
* Load authorized users list from disk (Reading a JSON file). If not exists (Usually on first run), will create the file.
* Incase the file is not in valid JSON format. will kill process with err code 1.
* @return {void}
*/
let loadDB = () => {
let dbLocation = config.DBLocation;
if (dbLocation[dbLocation.length - 1] != '/') dbLocation += '/users.json';
else dbLocation += 'users.json';
try {
data = fs.readFileSync(path.resolve(dbLocation));
try {
authorizedUsers = JSON.parse(data.toString());
console.log('DB loaded. AuthorizedUsers: ', authorizedUsers);
} catch (err) {
console.error('DB file is corrupted. Please delete the file', dbLocation, 'And rerun this service');
process.exit(1);
}
} catch (err) {
authorizedUsers = [];
if (saveToDB()) {
console.log('DB was created. Everything is Okay.');
} else {
console.error('Unable to read from DB. Error:\n', err);
process.exit(1);
}
}
}
/**
* Saves the authorized users list to disk. (config.DBLocation)
* @return {boolean} true=success, false=fail
*/
let saveToDB = () => {
let dbLocation = config.DBLocation;
if (dbLocation[dbLocation.length - 1] != '/') dbLocation += '/users.json';
else dbLocation += 'users.json';
try {
fs.writeFileSync(dbLocation, JSON.stringify(authorizedUsers));
return true;
} catch (err) {
console.error('Failed to save to DB... ERROR:\n', err);
return false;
}
}
/**
* Bot engine exported interface
* @type {Object}
*/
module.exports = {
runBot: runBot
}