rightnow-crm and unavailable hours - rightnow-crm

we have recently implemented rightnow proactive chat on our website, we have the chat widget set up by our central IT department to work off hours of availability for chat. I've got the widget working to an OK standard using this example
http://cxdeveloper.com/article/proactive-chat-intercepting-chat-events
However, coming from Zendesk I was hoping to replicate the 'out of hours' or 'offline' modes of the Zendesk widget where it changes its behaviour when chat is offline.
After looking around I notice the widget can take a value for 'label_unavailable_hours:' however I cannot work out if this is available to the both the ConditionalChatLink and ProactiveChat modules. Does anyone have any experience with creating such functionality? I've also had a look at trying to pull data using chatAvailability but I am not doing that right either.
If anyone has an insight on how to get some kind of out of hours smarts working or if I am wasting my time try Id love to hear. My code is as below
$(document).ready(function() {
RightNow.Client.Controller.addComponent({
instance_id: "spac_0",
avatar_image: "",
label_question: "A team member is available to help, would you like to start a chat?",
label_avatar_image: "",
label_dialog_header: "",
logo_image: "",
seconds: 2,
enable_polling: "yes",
div_id: "proactiveChatDiv",
module: "ProactiveChat",
//module: "ConditionalChatLink",
min_agents_avail: 0, //remove this when live (when set to 0, no agents have to be free)
min_sessions_avail: 1,
label_unavailable_busy_template: "'All team members are busy. please email is us' + <a href='urlForEmail'>' + 'this place' + '</a>'", //out of hours
label_unavailable_hours: "'Outside of hours' + <a href='urlForEmail'>' + 'this place' + '</a>'",
type: 2
},
"https://ourWidgetCode"
);
//Widget loaded callback - this doesn't seem to work correctly hence the code below
RightNow.Client.Event.evt_widgetLoaded.subscribe(function(event_name, data) {
if (data[0].id == "spac_0") {
//Initialization
console.log('widget loaded');
}
/* this wont work
spac_0.prototype.chatAvailability = spac_0.chatAvailability;
spac_0.chatAvailability = function()
{
console.log(spac_0.chatAvailability);
{}
};*/
//Reset prototype
spac_0.prototype = {};
//Handle Chat Offered
spac_0.prototype.chatOffered = spac_0.chatOffered;
spac_0.chatOffered = function() {
console.log("Chat Offered Handled");
spac_0.prototype.chatOffered.call(this);
//animate the widget to popup from bottom
setTimeout(function() {
$('div.yui-panel-container').addClass('animate');
}, 2000)
//delete the annoying session cookie that only allows the chat to appear once per session by default
RightNow.Client.Util.setCookie("noChat", '', -10, '/', '', '');
};
//if the 'Do not ask again' is selected
spac_0.prototype.chatRefused = spac_0.chatRefused;
spac_0.chatRefused = function () {
console.log("Do not ask again Selected");
spac_0.prototype.chatRefused.call(this);
//Reset the Cookie to be valid only for the session
RightNow.Client.Util.setCookie("noChat",'RNTLIVE',0,'/',true,'');
};
});
});

Related

Is there any way to keep the session open after alexa timer api goes off?

I would like to know if there are any possible ways or tricks where we can leave the session open for the user's input after the timer goes off because the timer API doc doesn't cover it.
timer_request_1 = {
"duration": "PT15S",
"timerLabel": "Change name",
"creationBehavior": {
"displayExperience": {
"visibility": "VISIBLE"
}
},
"triggeringBehavior": {
"operation": {
"type": "ANNOUNCE",
"textToAnnounce": [
{
"locale": "en-US",
"text": "Would you like to proceed with the x task?"
}
]
},
"notificationConfig": {
"playAudible": False
}
}
}
REQUIRED_PERMISSIONS = ["alexa::alerts:timers:skill:readwrite"]
class TimerIntentHandler(AbstractRequestHandler):
def can_handle(self, handler_input):
return ask_utils.is_intent_name("TimerIntent")(handler_input)
def handle(self, handler_input):
permissions = handler_input.request_envelope.context.system.user.permissions
if not (permissions and permissions.consent_token):
return (
handler_input.response_builder
.speak("Please give permissions to set timers using the alexa app.")
.set_card(
AskForPermissionsConsentCard(permissions=REQUIRED_PERMISSIONS)
)
.response
)
timer_service = handler_input.service_client_factory.get_timer_management_service()
timer_response = timer_service.create_timer(timer_request)
if str(timer_response.status) == "Status.ON":
session_attr = handler_input.attributes_manager.session_attributes
if not session_attr:
session_attr['lastTimerId'] = timer_response.id
speech_text = 'Your 40 minutes timer has started!.'
return (
handler_input.response_builder
.speak(speech_text)
.response
.ask("Would you like to proceed x task?")
)
else:
speech_text = 'Timer did not start'
return (
handler_input.response_builder
.speak(speech_text)
.response
)
I tried by adding a return .ask() but I got 'Response' object has no attribute 'ask' error.
Looking forward to hearing your thoughts :)
You use response to get the response from response_builder so you should place all speak, ask etc. builder methods before response.
One way to keep the session alive is to not send "shouldEndSession". This will not let the session close. But this will not be approved if you go for certification.

Make Scrapy send POST data from Javascript function

I'm playing with Scrapy and playing with this tutorial. Things look good but I noticed Steam changed their age check so there is no longer a form in DOM. So the suggested solution will not work:
form = response.css('#agegate_box form')
action = form.xpath('#action').extract_first()
name = form.xpath('input/#name').extract_first()
value = form.xpath('input/#value').extract_first()
formdata = {
name: value,
'ageDay': '1',
'ageMonth': '1',
'ageYear': '1955'
}
yield FormRequest(
url=action,
method='POST',
formdata=formdata,
callback=self.parse_product
)
Checking an example game that forces age check; I noticed the View Page button is no longer a form:
<a class="btnv6_blue_hoverfade btn_medium" href="#" onclick="ViewProductPage()"><span>View Page</span></a>
And the function being called will eventually call this one:
function CheckAgeGateSubmit( callbackFunc )
{
if ( $J('#ageYear').val() == 2019 )
{
ShowAlertDialog( '', 'Please enter a valid date' );
return false;
}
$J.post(
'https://store.steampowered.com/agecheckset/' + "app" + '/9200/',
{
sessionid: g_sessionID,
ageDay: $J('#ageDay').val(),
ageMonth: $J('#ageMonth').val(),
ageYear: $J('#ageYear').val()
}
).done( function( response ) {
switch ( response.success )
{
case 1:
callbackFunc();
break;
case 24:
top.location.reload();
break;
case 15:
case 2:
ShowAlertDialog( 'Error', 'There was a problem verifying your age. Please try again later.' );
break;
}
} );
}
So basically this is making a POST with some data...what would be the best way to do this in Scrapy, since this is not a form any longer? I'm just thinking on ignoring the code where the form is obtained and simply send the request with the FormRequest object...but is this the way to go? An alternative could also be setting cookies for age and pass it on every single request so possibly the age check is ignored altogether?
Thanks!
You should probably just set an appropriate cookie and you'll be let right through!
If you take a look at what your browser has when entering the page:
and replicate that in scrapy:
cookies = {
'wants_mature_content':'1',
'birthtime':'189302401',
'lastagecheckage': '1-January-1976',
}
url = 'https://store.steampowered.com/app/9200/RAGE/'
Request(url, cookies)
lastagecheckage should probably be enough on it's own but I haven't tested it.

"Parsing error: Unexpected token )" with bot

I'm making a discord bot and I'm trying to make a timer that every second it edits the message to time + 1 second like a real clock (Like 0:00). I'm a noob at this. This is my script:
const Discord = require("discord.js");
exports.run = async(bot, message, args) => {
let timerMessage = await message.channel.send('0');
for (i = 0, 10000000000) {
setTimeout(function() {
timerMessage.edit(timerMessage + 1);
}, 1000);
}
}
module.exports.help = {
name: "timer"
}
I have an error and it says: "Parsing error: Unexpected token )"
I would really appreciate it if you would help me with my problem, Thanks!
(Btw I'm using it in Glitch on Google Chrome)
It says that there's an unexpected token ) because you wrote your loop like this:
for (i = 0, 10000000000) {...}
You forgot to add the third argument (usually i++). Also, if you want it to run 10000000000 times you should write a comparison:
for (let i = 0; i < 10000000000; i++) {...}
I see what you're trying to achieve, but I would do it in a simpler way, using setInterval() instead of setTimeout().
setInterval(() => {
timerMessage.edit(timerMessage + 1);
}, 1000);
You seem to be missing a right parenthesis after the setTimeout function. I am not entirely familiar with what you are doing, but I would try something like this :
const Discord = require("discord.js");
exports.run = async (bot, message, args) => {
let timerMessage = await message.channel.send('0');
for (i = 0, 10000000000) {
setTimeout(function()) {
timerMessage.edit(timerMessage + 1);
}, 1000);
}
}
module.exports.help = {
name: "timer";
}
Although this should (maybe) replace the missing parenthesis in your code, it seems to have many other issues. For example, your for loop does not make much sense. Normally a for loop would look something like this (to repeat a certain number of times in java) :
for (int i = 0; i < 10; i++) {
System.out.println(i);
} // will print numbers 0-9, repeat 10 times
The whole chunk of code with the setTimeout bit seems to be messed up... It would help to have a little more context on what you are trying to do / some commenting in your code.
If you are trying to get into coding, I'd recommend something much more basic or some tutorials. CodingTrain has great coding videos on youtube and you will learn a ton no matter what language you go with. Hope this helped...

Google Sheets API addProtectedRange Error: No grid with id: 0

I am not sure if I am making a mistake or if possibly this is related to the same issue reported here:
Google Sheets API V4 - Autofill Error - No grid with id: 0
I am getting:
HttpError 400
"Invalid requests[0].addProtectedRange: No grid with id: 1"
Code is something like this (additional addProtectedRange objects removed)
def add_protected_ranges(spreadsheet_id):
service = get_sheets_service()
requests = [
{
"addProtectedRange": {
'protectedRange': {
"range": {
"sheetId": 1,
"startRowIndex": 0,
"endRowIndex": 0,
"startColumnIndex": 0
},
"description": "Headers must not be changed",
"warningOnly": True
}
}
}
]
body = {
'requests': requests
}
response = service.spreadsheets().batchUpdate(spreadsheetId=spreadsheet_id,
body=body).execute()
Had kind of the same issue. I was confusing the sheet id with sheet index.
Easiest way to find the sheet id is in the browser URL when you open the spreadsheet / sheet: https://docs.google.com/spreadsheets/d/{spreadsheetId}/edit#gid={sheetId}
If you're looking for a more programmatic way you find that property on the SheetProperties.
I know that's an old question but I was looking for it too. You're looking for:
res.data.sheets[].properties.sheetId
To get the sheetId (not the spreadsheetId) use:
sheets.spreadsheets.get({
spreadsheetId
}).then(res => {
console.log("All the sheets:");
for(i in res.data.sheets) {
let title = res.data.sheets[i].properties.title;
let id = res.data.sheets[i].properties.sheetId;
console.log(title + ': ' + id);
}
});
Make sure that there is a workbook with the id 1 in your spreadsheet. In google sheet, a spreadsheet can contain multiple worksheet(grid), there is a unique id for each of the worksheet(grid).

Strophe.attach not working - I am using openfire locally

I am trying to implment the XMPP Client. I am using BOSH Connection manager and can run the Strophe.connect but not Strophe.Attach. I have tried incrementing the RID, but no effect.. Any help please ? There is no error here, but the Strophe.Status.CONNECTED is never reached via the attach method and so I cannot send IQ or Presence.
Here is my code
try
{
var cookieJid = $.cookie("jid");
var cookieSid = $.cookie("sid");
var cookieRid = $.cookie("rid");
var connt = new Strophe.Connection("http://localhost:7070/http-bind/");
connt.attach(cookieJid, cookieSid, cookieRid + 1, function(status)
{
if (status === Strophe.Status.CONNECTED)
{
alert ("hola connected");
$("#userName").append("hola connected : " + connt.jid );
var iq = $iq({type: 'get'}).c('query', {xmlns: 'jabber:iq:roster'});
connt.sendIQ(iq, handleRoster);
connt.send($pres());
}
});
}
catch (e)
{
$("#userName").append("Pinky error is " + e);
}
Edit
Thanks Eric and Charlie.
So I took the latest Strophe.js and now Attached status does work.
But the connection disconnects instantaneously. I am not even able to fetch the Roster.
We can possibly do every thing with Connection.attach() as we would with connection.connect(), right?
Any thoughts?
Change the line:
if (status === Strophe.Status.CONNECTED)
...to...
if (status === Strophe.Status.CONNECTED || status === Strophe.Status.ATTACHED)
Are you using the latest Strophe library? In the version I'm using, I see that the status can be these values:
Status: {
ERROR: 0,
CONNECTING: 1,
CONNFAIL: 2,
AUTHENTICATING: 3,
AUTHFAIL: 4,
CONNECTED: 5,
DISCONNECTED: 6,
DISCONNECTING: 7,
ATTACHED: 8
}
Make sure you convert your cookieRid to a Number by using new Number(cookieRid). Otherwise, when you do +1 on it, you will get "####1".
You can test this out for yourself in Javascript:
var s = "123";
alert(s+1); // "1231" and not "124"
Also, as Eric answered, there is a status ATTACHED so you need to handle that event.