Sometimes, when running the addon it will throw out the following error:
Error with the add-on.
Run time error.
Cannot find method moveThreadToInbox((class)). [line 102, function:,file:Code]
Other times, it works perfectly fine.
I have tried to handle this how Google does in the demo here
But still, get the same error. In fact, thinking about it... this probably isn't the best way to do it. As the query may return a subject with the same string. So I then tried to use the ID for the new mail, but that wouldn't play nicely with moveThreadToInbox.
The code and error messages are below:
The line of code that the error is referencing is:
GmailApp.moveThreadToInbox(newMailSearch[0]);
Full code section:
function editThreadSubject(e) {
var accessToken = e.messageMetadata.accessToken;
GmailApp.setCurrentMessageAccessToken(accessToken);
var newSubject = e.formInputs.newSubject;
var firstMessage = GmailApp.getMessageById(e.messageMetadata.messageId)
.getThread()
.getMessages()[0];
var oldSubject = firstMessage.getSubject();
var thread = GmailApp.getMessageById(e.messageMetadata.messageId).getThread();
thread.getMessages().forEach(function(message) {
GmailApp.setCurrentMessageAccessToken(accessToken);
var messageId = message.getId();
var email = getEmail(messageId, accessToken);
var unencoded = Utilities.newBlob(
Utilities.base64DecodeWebSafe(email.raw)
).getDataAsString();
var updatedEmail = unencoded.replace(
"Subject: " + oldSubject,
"Subject: " + newSubject
);
email.raw = Utilities.base64EncodeWebSafe(updatedEmail);
var newMail = Gmail.Users.Messages.import(
{
raw: email.raw
},
"me",
Utilities.newBlob(email, "message/rfc822"),
{
deleted: false,
internalDateSource: "dateHeader",
neverMarkSpam: true,
processForCalendar: false
}
);
var newMailId = newMail.id;
var query = ["Subject:" + newSubject];
var newMailSearch = GmailApp.search(query);
GmailApp.moveThreadToInbox(newMailSearch[0]);
Gmail.Users.Messages.remove("me", messageId);
});
var notification = CardService.newNotification().setText(
"The subject has been updated"
);
var actionResponse = CardService.newActionResponseBuilder()
.setNotification(notification)
.setStateChanged(true)
.build();
return actionResponse;
}
It should insert the new mail into Gmail, delete the old mail and move the new mail in the inbox. As I said, it works some of the time so I'm stuck trying to figure out why it's not working when it doesn't!
If anyone can point me in the right direction, it would be fantastic and save me going prematurely bald through pulling my hair out!
You should probably put some type of test between this var newMailSearch = GmailApp.search(query); and this
GmailApp.moveThreadToInbox(newMailSearch[0]); to insure that what is returned meets the approach value and or type requirements for the function.
Related
I'm quite new to working with telegram bots, but I managed well so far with some basic bot. Now I want to improve a bit things and let my site "feed" the bot.
This is the scenario
I have a Google spreadsheet that make some calculation and then sends a message to the bot with the classic URL. Something like this...
var optionsUG = {
'method' : 'post',
'payload' : formDataUG,
'muteHttpExceptions':true
};
var optionsLG = {
'method' : 'post',
'payload' : formDataLG
};
//SpreadsheetApp.getUi().alert('UrlFetchApp options ['+options+"]");
//UrlFetchApp.fetch('https://api.telegram.org/bot'+token+'/sendMessage?chat_id='+channelNumber+'&text='+text);
var result = UrlFetchApp.fetch('https://api.telegram.org/bot'+token+'/sendMessage',optionsUG);
Utilities.sleep(5 * 1000);
result = UrlFetchApp.fetch('https://api.telegram.org/bot'+token+'/sendMessage',optionsLG);
now I would like to make something like but, instead of sendMessage I would like to call a method of my bot
I use JavaScript Telegraf framework ATM, but I can change is not a problem.
I want to achieve something like:
var result = UrlFetchApp.fetch('https://api.telegram.org/bot'+token+'/register',optionsUG);
here is the bot currently configured
const serverPath = "/home/bots/PlatoonAdvisor/telegram";
const commands = require(serverPath+'/package/modules/commands.js');
const config = require(serverPath+'/config.json');
var helpText = require(serverPath+'/package/help.txt');
const token = config.TELEGRAM_BOT_SECRET;
const Telegraf = require('telegraf');
const bot = new Telegraf(token);
const REGISTER_COM = 'register';
const HELP_COM = 'help';
const REQUIREMENTS_COM = 'requirements';
const CAHT_ID_COM = 'chatid';
const getCommandParameters = function (text, command) {
var reg = "/\/"+command+" (.*)/g";
var arr = text.match(reg);
return arr;
}
/*
bot.on('text', message=> {
return message.reply('I am Grooth');
})
*/
bot.command(HELP_COM, ctx=> {
return ctx.reply(helpText);
});
bot.command(REGISTER_COM, ctx=> {
var replyMsg;
var param = getCommandParameters(ctx.message.text, REGISTER_COM);
var player_name, allycode;
if (param != null) {
try {
var params = param.split(",");
if (params.length < 2) {
replyMsg = "Missing parameters, try /help if you need help :)";
throw replyMsg;
}
player_name = params[1];
allycode = params[0];
var channel = ctx.chat.id;
commands.registerTPlayer(player_name, allycode, channel);
replyMsg = "Successfully registered player ${player_name} with allycode ${allycode}!"
} catch (ex) {
console.log (ex);
}
}
return ctx.reply(replyMsg);
});
bot.command(REQUIREMENTS_COM, ctx=> {
var param = getCommandParameters(ctx.message.text, REQUIREMENTS_COM);
var params = param.split(",");
var json = ctx.chat.id;
return ctx.reply(json);
});
bot.command(CAHT_ID_COM, ctx=> {
var id = ctx.chat.id;
var msg = "The chat id requested is ${id}";
return ctx.reply(msg);
});
bot.startPolling();
is that even possible? I'm looking over the internet for a while now and was not able to find any clue about.
EDIT: Doing some more digging I found webhooks to send content to a web server when something happens in the bot but not vice versa. I'm getting frustrated.
My goal is to update the local database with information the spreadsheet have but the bot still don't so users can later ask to the bot to retrieve those information.
I mean I could make an ajax call if it were a real web server, but it is just a spreadsheet which doesn't act as a server.
Ok I forgot to answer this question with the solution I found.
there is no way indeed to call a specific function of the bot from the outside because it is not a real function, it is a parsed string that a user type and the bot interpret as a command.
So I had to be creative and expose a RestServer from the bot itself (the NodeJS express library did the trick) which I was then able to call from the script.
Here an handy guide for Express.js
This is my solution which is working great now.
I'm newer in servicenow developing.
I try to create a bundle "Script Include" - "Client Script".
Using background script I see, that my script include works fine.
But when I try to call this include via client script, it doesn't return any response.
Here is my method in Script Include:
usersCounter: function () {
var gr = new GlideRecord('sys_user');
gr.query();
var users = gr.getRowCount();
gs.info('Number of users'+ ' ' + users);
return users;
And here is my client script:
var ga = new GlideAjax('SCI_Training_ScriptIncludeOnChange');
ga.addParam('sysparm_name', 'usersCounter');
ga.getXML(getUsers);
function getUsers(response) {
var numberOfUsers = response.responseXML.documentElement.getAttribute("answer");
g_form.clearValue('description');
console.log(numberOfUsers);
And I have null in my console.
What have I missed?
Irrespective of why it's not working, you probably want to change your server side GlideRecord to use GlideAggregate instead, and just let mysql return the row count:
var gr = new GlideAggregate('sys_user');
gr.addAggregate('COUNT');
gr.query();
gr.next();
var users = gr.getAggregate('COUNT');
gs.info('Number of users'+ ' ' + users);
return users;
Doing a GlideRecord#query with no where clause is essentially doing a "SELECT * FROM sys_user", bringing over all the data, when all you're asking for is the row count from the metadata in the result set.
Beyond that, make sure your Script Include properly extends AbstractAjaxProcessor and has the client-callable field set to true per this:
https://docs.servicenow.com/bundle/geneva-servicenow-platform/page/script/server_scripting/reference/r_ExamplesOfAsynchronousGlideAjax.html
You can try to debug your getUsers() method. Try to check what the object structure of response is.
You could also use
var ga = new GlideAjax('SCI_Training_ScriptIncludeOnChange');
ga.addParam('sysparm_name', 'usersCounter');
ga.getXMLAnswer(getUsers);
function getUsers(response) {
var numberOfUsers = response;
g_form.clearValue('description');
console.log(numberOfUsers);
}
In Mirth, I have a JavaScript Reader connector and in the source, I have a call to a stored procedure. This procedure returns multiple rows. Is there any way to script it so that for each row returned from the procedure, I can generate the message and send appropriately? The other option that I am already aware of is to script it to generate only 1 message and have the polling interval set to every 100ms or so in addition to changing the procedure. Any help or insight would be greatly appreciated.
var procedure = 'exec dbo.mystoredprocedure';
objresult = dbConn.executeCachedQuery(procedure);
while (objresult.next())
{
var msg = <HL7Message/>;
msg.MSH['MSH.1'] = '|';
msg.MSH['MSH.2'] = '^~\\&';
msg.MSH['MSH.3'] = 'MedicalRecords';
msg.MSH['MSH.4'] = 'Application';
msg.MSH['MSH.5'] = 'Test';
msg.MSH['MSH.6'] = 'Something';
msg.MSH['MSH.7'] = DateUtil.getCurrentDate("yyyyMMddHHmmssSSS");
msg.MSH['MSH.8'] = '';
msg.MSH['MSH.9']['MSH.9.1'] = 'ADT';
msg.MSH['MSH.9']['MSH.9.2'] = 'A08';
msg.MSH['MSH.10'] = DateUtil.getCurrentDate("yyyyMMddHHmmssSSS");
msg.MSH['MSH.11'] = 'P';
msg.MSH['MSH.12'] = '2.5';
.
.
.
.
return msg;
}
Yes, you can return a List with multiple messages. Each element in the list will be dispatched to the channel as a separate message.
Great thanks! I did some digging and found what I was looking for.
var messages = new java.util.ArrayList();
messages.add(message1);
messages.add(message2);
return messages;
My jquery will not run my java script function on document ready.
cont += "<script>";
cont += "$(document).ready(function() {Puma.getReasonForBTI()});";
cont += "</script>";
JS function
Puma.getReasonForBTI = function() {
var reason = document.getElementById("reasonId").value;
var msql = "SELECT Pid FROM tPid WHERE Reason = 'reason'";
sql = "action=getReasonForBTI&sql=" + encodeURIComponent(msql);
objAjaxAd.main_flag = "getReasonForBTI";
objAjaxAd.SendQuery(sql);
}
Any help would be appreciated.
Why not just add the DocReady to your JS?
Puma.getReasonForBTI = function() {
var reason = document.getElementById("reasonId").value;
var msql = "SELECT Pid FROM tPid WHERE Reason = 'reason'";
sql = "action=getReasonForBTI&sql=" + encodeURIComponent(msql);
objAjaxAd.main_flag = "getReasonForBTI";
objAjaxAd.SendQuery(sql);
}
$(document).ready(function() {
Puma.getReasonForBTI()
});
EDIT:
Also, I would send reason by itself and Sanitize it server side, then put it into a query. Sending a SQL query over Javascript/AJAX is just asking for trouble.
Faux-Code:
sql("
SELECT Pid
FROM tPid
WHERE Reason = ?
", $ajax.reason)
DOUBLE EDIT
Also, putting reason in single quotes in a string does not evaluate the value of reason. Just figured I'd save you some future headache
var foo = "bar";
console.log("The value of foo is 'foo'");
=> "The value of foo is 'foo'"
console.log("The value of foo is " + foo);
=> "The value of foo is bar"
Try a chrome browser and the Development tools (F12).
Take a look at the errorconsole.
Fix the error
Change your Code, because Someone can use YOUR code to delete any data from the underlying database
update
var reason = document.getElementById("reasonId").value;
// reason is entered directly byy a user (or Mr. EvilHacker).
var msql = "SELECT Pid FROM tPid WHERE Reason = 'reason'";
// Here you create a SQL, which may sounds like this:
SELECT Pid FROM tPid WHERE Reason = ''; DROP table tPid;--'
if the evil hacker entered ';DROP table tPid;-- into the textbox. Look at owasp.org for further information
I have tried to get some information from W3C regarding the update of an objectStore item in a indexedDB database, but with not so much susccess.
I found here a way to do it, but it doesn't really work for me.
My implementation is something like this
DBM.activitati.edit = function(id, obj, callback){
var transaction = DBM.db.transaction(["activitati"], IDBTransaction.READ_WRITE);
var objectStore = transaction.objectStore("activitati");
var keyRange = IDBKeyRange.only(id);
objCursor = objectStore.openCursor(keyRange);
objCursor.onsuccess = function(e){
var cursor = e.target.result;
console.log(obj);
var request = cursor.update(obj);
request.onsuccess = function(){
callback();
}
request.onerror = function(e){
conosole.log("DBM.activitati.edit -> error " + e);
}
}
objCursor.onerror = function(e){
conosole.log("DBM.activitati.edit -> error " + e);
}
}
I have all DBM.activitati.(add | remove | getAll | getById | getByIndex) methods working, but I can not resolve this.
If you know how I can manage it, please, do tell!
Thank you!
Check out this jsfiddle for some examples on how to update IDB records. I worked on that with another StackOverflower -- it's a pretty decent standalone example of IndexedDB that uses indexes and does updates.
The method you seem to be looking for is put, which will either insert or update a record if there are unique indexes. In that example fiddle, it's used like this:
phodaDB.indexedDB.addUser = function(userObject){
//console.log('adding entry: '+entryTxt);
var db = phodaDB.indexedDB.db;
var trans = db.transaction(["userData"],IDBTransaction.READ_WRITE);
var store = trans.objectStore("userData");
var request = store.put(userObject);
request.onsuccess = function(e){
phodaDB.indexedDB.getAllEntries();
};
request.onerror = function(e){
console.log('Error adding: '+e);
};
};
For what it's worth, you've got some possible syntax errors, misspelling "console" in console.log as "conosole".
A bit late for an answer, but possible it helps others. I still stumbled -as i guess- over the same problem, but it's very simple:
If you want to INSERT or UPDATE records you use objectStore.put(object) (help)
If you only want to INSERT records you use objectStore.add(object) (help)
So if you use add(object), and a record key still exists in DB, it will not overwritten and fires error 0 "ConstraintError: Key already exists in the object store".
If you use put(object), it will be overwritten.
this is case of update infos of an user object
var transaction = db.transaction(["tab_user"], "readwrite");
var store = transaction.objectStore("tab_user");
var req = store.openCursor();
req.onerror = function(event) {
console.log("case if have an error");
};
req.onsuccess = function(event) {
var cursor = event.target.result;
if(cursor){
if(cursor.value.idUser == users.idUser){//we find by id an user we want to update
var user = {};
user.idUser = users.idUser ;
user.nom = users.nom ;
var res = cursor.update(user);
res.onsuccess = function(e){
console.log("update success!!");
}
res.onerror = function(e){
console.log("update failed!!");
}
}
cursor.continue();
}
else{
console.log("fin mise a jour");
}
}
I'm a couple of years late, but thought it'd be nice to add my two cents in.
First, check out BakedGoods if you don't want to deal with the complex IndexedDB API.
It's a library which establishes a uniform interface that can be used to conduct storage operations in all native, and some non-native client storage facilities. It also maintains the flexibility and options afforded to the user by each. Oh, and it's maintained by yours truly :) .
With it, placing one or more data items in an object store can be as simple as:
bakedGoods.set({
data: [{key: "key1", value: "value1"}, {key: "key2", value: "value2"}),
storageTypes: ["indexedDB"],
complete: function(byStorageTypeResultDataObj, byStorageTypeErrorObj){}
});
Now to answer the actual question...
Lets begin by aggregating the valuable information spread across the existing answers:
IDBObjectStore.put() adds a new record to the store, or updates an existing one
IDBObjectStore.add() adds a new record to the store
IDBCursor.update() updates the record at the current position of the cursor
As one can see, OP is using an appropriate method to update a record. There are, however, several things in his/her code, unrelated to the method, that are incorrect (with respect to the API today at least). I've identified and corrected them below:
var cursorRequest = objectStore.openCursor(keyRange); //Correctly define result as request
cursorRequest.onsuccess = function(e){ //Correctly set onsuccess for request
var objCursor = cursorRequest.result; //Get cursor from request
var obj = objCursor.value; //Get value from existing cursor ref
console.log(obj);
var request = objCursor.update(obj);
request.onsuccess = function(){
callback();
}
request.onerror = function(e){
console.log("DBM.activitati.edit -> error " + e); //Use "console" to log :)
}
}
cursorRequest.onerror = function(e){ //Correctly set onerror for request
console.log("DBM.activitati.edit -> error " + e); //Use "console" to log :)
}