kykint

Save/load user lang preference from DB

......@@ -91,4 +91,8 @@ typings/
# Config file
config.js
# Database
db/**
!db/.placeholder
# End of https://www.gitignore.io/api/node
......
......@@ -13,6 +13,10 @@ const translate_api_url = 'https://openapi.naver.com/v1/papago/n2mt';
// Language detection api url
const languagedetect_api_url = 'https://openapi.naver.com/v1/papago/detectLangs'
// Initialize database
const db = require('./db');
db.init();
// /echo [whatever]
bot.onText(/\/echo (.+)/, (msg, match) => {
// 'msg' is the received Message from Telegram
......@@ -29,10 +33,11 @@ bot.onText(/\/echo (.+)/, (msg, match) => {
/**
* Translate given message and send it to the specified chatroom.
*
* @param {*} userId Id of the user that wants to translate
* @param {*} message Message to translate
* @param {*} chatId Id of the chatroom to send translated message to
*/
function translate(message, chatId) {
function translate(userId, message, chatId) {
// Language detection options
var lang_detect_options = {
url: languagedetect_api_url,
......@@ -56,37 +61,51 @@ function translate(message, chatId) {
console.log('Language detected: ' + detect_body.langCode);
// Translate using papago
// Target defaults to English for Korean source, or Korean for all other langs
// Try to grab source lang and target lang from user's preference first.
// If preference is not found, source default to detected language, and
// target defaults to English for Korean source, or Korean for all other langs.
if (detect_body.langCode != 'unk') {
source = detect_body.langCode;
target = source == 'ko' ? 'en' : 'ko';
// Papago translation options
var translate_options = {
url: translate_api_url,
form: {
'source': source, // Before translation
'target': target, // After translation
'text': message // Message to translate
},
headers: {
'X-Naver-Client-Id': config.papago.client_id,
'X-Naver-Client-Secret': config.papago.client_secret
db.findPref(userId, "pref", (dbResult) => {
// Choosing source language not implemented as of now
if (dbResult != undefined) {
source = dbResult.source != undefined ? dbResult.source : detect_body.langCode;
target = dbResult.target != undefined ? dbResult.target : (source == 'ko' ? 'en' : 'ko');
} else {
source = detect_body.langCode;
target = source == 'ko' ? 'en' : 'ko';
}
};
// Send translatation request
request.post(translate_options, function (error, response, body) {
// On success
if (!error && response.statusCode == 200) {
console.log(source + ' => ' + target);
// Papago translation options
var translate_options = {
url: translate_api_url,
form: {
'source': source, // Before translation
'target': target, // After translation
'text': message // Message to translate
},
headers: {
'X-Naver-Client-Id': config.papago.client_id,
'X-Naver-Client-Secret': config.papago.client_secret
}
};
// Send translatation request
request.post(translate_options, function (error, response, body) {
var objBody = JSON.parse(response.body);
result.text = objBody.message.result.translatedText;
if (!error && response.statusCode == 200) {
// On success
result.text = objBody.message.result.translatedText;
console.log('Before: ' + message);
console.log('After: ' + result.text);
} else {
// On failure
result.text = '[' + objBody.errorCode + '] ' + objBody.errorMessage;
}
// Send translated message
console.log('Before: ' + message);
console.log('After: ' + result.text);
bot.sendMessage(chatId, result.text);
}
});
});
}
// Language not detected
......@@ -100,6 +119,7 @@ function translate(message, chatId) {
// [Any normal message which is not a command (not starting with '/')]
bot.onText(/^(?!\/)((.|\n)+)/, (msg, match) => {
const userId = msg.from.id;
const chatId = msg.chat.id;
const chatType = msg.chat.type;
const received_msg = match[1];
......@@ -110,7 +130,7 @@ bot.onText(/^(?!\/)((.|\n)+)/, (msg, match) => {
return;
}
translate(received_msg, chatId);
translate(userId, received_msg, chatId);
});
// /t(ranslate) [Whatever]
......@@ -118,6 +138,7 @@ bot.onText(/^(?!\/)((.|\n)+)/, (msg, match) => {
// Also, if the given '/t' message is a reply to another message,
// translate the reply target message as well.
bot.onText(/^\/(t|translate)($| ((.|\n)+))/, (msg, match) => {
const userId = msg.from.id;
const chatId = msg.chat.id;
const chatType = msg.chat.type;
const received_msg = match[3];
......@@ -129,12 +150,12 @@ bot.onText(/^\/(t|translate)($| ((.|\n)+))/, (msg, match) => {
// Translate the reply's target message
if (isReply) {
const replyMsg = msg.reply_to_message.text;
translate(replyMsg, chatId);
translate(userId, replyMsg, chatId);
}
// Translate the message after '/t' if exists
if (msgExists) {
translate(received_msg, chatId);
translate(userId, received_msg, chatId);
}
});
......@@ -194,11 +215,15 @@ bot.onText(/^\/(l|anguage)/, (msg, match) => {
});
bot.on('callback_query', (query) => {
const data = query.data;
const queryId = query.id;
const userId = query.from.id;
const langCode = query.data;
const options = {
text: 'From now on, your messages will be translated into ' + data
}
db.updatePref(userId, { "pref": { "target": langCode } }, (result) => {
const options = {
text: 'From now on, your messages will be translated into ' + langCode
}
bot.answerCallbackQuery(query.id, options);
bot.answerCallbackQuery(queryId, options);
})
});
......
// MongoDB handling module
// TODO: error handling, data removal
const MongoClient = require('mongodb').MongoClient;
// Connection URL
const url = 'mongodb://localhost:27017';
var db, collection;
// Use connect method to connect to the server
const init = function () {
MongoClient.connect(url, function (err, client) {
if (err) {
return;
}
console.log("Connected successfully to MongoDB server");
db = client.db('telegrambot');
collection = db.collection('users');
});
}
const findData = function (userId, key, callback) {
collection.find({ "userId": userId }).toArray(function (err, docs) {
var cur = docs[0];
if (cur != undefined) {
const keys = key.split('.');
for (var i = 0, subKey, len = keys.length; i < len; ++i) {
subKey = keys[i];
if (subKey == '') {
continue;
}
if (cur.hasOwnProperty(subKey)) {
cur = cur[subKey];
} else {
cur = undefined;
break;
}
}
}
callback(cur);
});
};
const updateData = function (userId, data, callback) {
collection.updateOne(
{ "userId": userId },
{ $set: data },
{ upsert: true },
function (err, result) {
callback(result);
});
};
module.exports = {
init: init,
findPref: findData,
updatePref: updateData
};
File mode changed
......@@ -74,6 +74,11 @@
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz",
"integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w=="
},
"bson": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/bson/-/bson-1.1.1.tgz",
"integrity": "sha512-jCGVYLoYMHDkOsbwJZBCqwMHyH4c+wzgI9hG7Z6SZJRXWr+x58pdIbm2i9a/jFGCkRJqRUr8eoI7lDWa0hTkxg=="
},
"caseless": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
......@@ -338,6 +343,12 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
},
"memory-pager": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
"integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
"optional": true
},
"mime": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
......@@ -356,6 +367,26 @@
"mime-db": "1.40.0"
}
},
"mongodb": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.2.6.tgz",
"integrity": "sha512-qnHc4tjEkHKemuzBq9R7ycYnhFE0Dlpt6+n6suoZp2DcDdqviQ+teloJU24fsOw/PLmr75yGk4mRx/YabjDQEQ==",
"requires": {
"mongodb-core": "3.2.6",
"safe-buffer": "^5.1.2"
}
},
"mongodb-core": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-3.2.6.tgz",
"integrity": "sha512-i+XRVjur9D0ywGF7cFebOUnALnbvMHajdNhhl3TQuopW6QDE655G8CpPeERbqSqfa3rOKEUo08lENDIiBIuAvQ==",
"requires": {
"bson": "^1.1.1",
"require_optional": "^1.0.1",
"safe-buffer": "^5.1.2",
"saslprep": "^1.0.0"
}
},
"ms": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
......@@ -500,6 +531,20 @@
"lodash": "^4.17.11"
}
},
"require_optional": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz",
"integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==",
"requires": {
"resolve-from": "^2.0.0",
"semver": "^5.1.0"
}
},
"resolve-from": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz",
"integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c="
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
......@@ -510,6 +555,29 @@
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"saslprep": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz",
"integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==",
"optional": true,
"requires": {
"sparse-bitfield": "^3.0.3"
}
},
"semver": {
"version": "5.7.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA=="
},
"sparse-bitfield": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
"integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=",
"optional": true,
"requires": {
"memory-pager": "^1.0.2"
}
},
"sshpk": {
"version": "1.16.1",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
......
......@@ -10,6 +10,7 @@
"author": "강수인",
"license": "MIT",
"dependencies": {
"mongodb": "^3.2.6",
"node-telegram-bot-api": "^0.30.0",
"request": "^2.88.0"
}
......