How do I add attendees to a Calendar Event for the first time? - api

I have followed the answer here, which was really helpful:
How do I send the standard invitation email when calling addGuest on a CalendarEvent?
However, when I create an event in Apps Script it doesn't have an attendees property to add the email address to.
If I add a person to the invite manually, and then run the code, it executes successfully because there is now an attendee property to update.
Code to create the event:
function createCalendarEntry(programmeCalendar, eventName, eventStartDateTime, eventEndDateTime) {
var programmeCalendarID = CalendarApp.getCalendarById(programmeCalendar);
var event = programmeCalendarID.createEvent(eventName,
new Date(eventStartDateTime),
new Date(eventEndDateTime),
{sendInvites:true});
console.log('Event ID: ' + event.getId());
//Stop guests inviting other people
event.setGuestsCanInviteOthers(false);
var eventID = event.getId();
return eventID;
}
Code to add a new guest:
// Invite the user to the given event using the Advanced Calendar API
var trimmedEventID = eventID.toString().replace('#google.com', '');
var programmeCalendarID = 'my-calendar#example.com';
var advancedEvent = Calendar.Events.get(programmeCalendarID, trimmedEventID);
console.log('Advanced Event:' + advancedEvent);
if (typeof advancedEvent.attendees === 'undefined') {
console.log('Advanced Event Attendees: is undefined');
// how can I add the attendee property here?
} else {
var attendees = advancedEvent.attendees;
console.log('Advanced Event Attendees: is defined' + attendees);
attendees.push({email: guestEmailAddress});
var resource = { attendees: attendees };
}
var args = { sendUpdates: "all" };
// Add the guest to the invite while also sending an invite email
var eventObjectForDebugging = Calendar.Events.patch(resource, programmeCalendarID, trimmedEventID, args);
console.log('Event object for debugging:' + eventObjectForDebugging);

As you can read in the documentation, you can add guests with the option object, which has the following parameters:
You are actually already using this object in your code:
{sendInvites:true});
So adding the field guests to your object will be enough to add attendees:
{guests:'test1#example.com, test2#example.com', sendInvites:true});

It looks like you don't want to add guests to the event at the time of creation. Therefore you will end up with an event without an attendees[] property in the Event resource.
When you do come to add an attendee, you can do it like this:
// Invite user to the given event using the Advanced Calendar API
var trimmedEventID = eventID.toString().replace('#google.com', '');
var programmeCalendarID = 'my-calendar#example.com';
var advancedEvent = Calendar.Events.get(programmeCalendarID, trimmedEventID);
console.log('Advanced Event:' + advancedEvent);
var attendees = advancedEvent.attendees;
if (attendees) {
// If there are already attendees, push the new attendee onto the list
attendees.push({email: guestEmailAddress});
var resource = { attendees: attendees };
} else {
// If attendees[] doesn't exist, add it manually (there's probably a better way of doing this)
var resource = { attendees: [{email: guestEmailAddress}] }
}
var args = { sendUpdates: "all" };
var eventObjectForDebugging = Calendar.Events.patch(resource, programmeCalendarID, trimmedEventID, args);
console.log('Event object for debugging:' + eventObjectForDebugging);

Related

How to send a message when a trello card is moved to a certain list

I’m currently making a bot that informs me when a card is moved to the list titled Passed Applications.
I have already made the code and it basically sends a message once a card is moved to the specific list, however, it will randomly send a message and pull a card minutes/hours after it has already been pulled and sent the message.
What I’ve done so far is:
trello.js
var Trello = require("node-trello"),
EventEmitter = require("events").EventEmitter,
extend = require("extend"),
config,
trello,
timer,
e;
module.exports = function(options) {
var defaults = {
pollFrequency: 1000 * 60,
minId: 0,
trello: {
key: "",
token: "",
boards: []
},
start: true
};
e = new EventEmitter();
config = extend(true, defaults, options);
trello = new Trello(
process.env.TRELLO_API_KEY,
process.env.TRELLO_OAUTH_TOKEN
);
if (config.start) {
process.nextTick(function() {
start(config.pollFrequency, true);
});
}
function start(frequency, immediate) {
if (timer) {
return;
}
frequency = frequency || config.pollFrequency;
timer = setInterval(poll, frequency);
if (immediate) {
poll();
}
}
function poll() {
config.trello.boards.forEach(function(boardId) {
getBoardActivity(boardId);
});
}
function getBoardActivity(boardId) {
trello.get("/1/boards/" + boardId + "/actions", function(err, resp) {
if (err) {
return e.emit("trelloError", err);
}
var boardActions = resp.reverse();
var actionId;
for (var ix in boardActions) {
actionId = parseInt(boardActions[ix].id, 16);
if (actionId <= config.minId) {
continue;
}
var eventType = boardActions[ix].type;
e.emit(eventType, boardActions[ix], boardId);
}
config.minId = Math.max(config.minId, actionId);
e.emit("maxId", config.minId);
});
}
index.js
const conf = JSON.parse(fs.readFileSync("trelloconfig.json"));
let latestActivityID = fs.existsSync("./latestActivityID") ?
fs.readFileSync("./latestActivityID") :
0;
const eventEnabled = type =>
conf.enabledEvents.length > 0 ? conf.enabledEvents.includes(type) : true;
const TrelloEvents = require("./trello.js");
const events = new TrelloEvents({
pollFrequency: 60000,
minId: latestActivityID,
start: false,
trello: {
boards: conf.boardIDs,
key: process.env.TRELLO_API_KEY,
token: process.env.TRELLO_OAUTH_TOKEN
}
});
client.on("ready", () => {
events.start();
console.log(`[STATUS CHANGE] ${client.user.username} is now online.`);
client.user.setActivity("Cookout Grill");
});
events.on("updateCard", (event, board) => {
if (event.data.old.hasOwnProperty("idList")) {
if (!eventEnabled(`cardListChanged`)) return;
if (event.data.listAfter.name === "Passed Applications") {
let robloxId = event.data.card.name.split(" | ")[0];
client.channels.get("730839109236424756").send(robloxId);
if (database.find(x => x.RobloxUser === robloxId)) {
let data = database.find(x => x.RobloxUser === robloxId);
const person = client.users.get(data.DiscordID);
let embed = new discord.RichEmbed()
.setThumbnail(
"https://www.roblox.com/bust-thumbnail/image?userId=" +
data.RobloxID +
"&width=420&height=420&format=png"
)
.setTitle("APPLICATION RESULTS | Passed")
.setColor("3ef72d")
.setFooter("Cookout Grill", client.user.avatarURL)
.setDescription(
"Greetings, **" +
data.RobloxUser +
"**!\n\nAfter extensive review by our Management Team, we have decided to accept your Trainee Application at Cookout Grill. We believe that your application showed that you’re ready to become a staff member at our establishment.\n\nWe would like to congratulate you on passing your Trainee Application. Your application met our critical expectations and requirements in order to pass.\n\nIn order to work your way up throughout the staff ranks, you must attend a training at [Cookout Grill’s Training Center](https://www.roblox.com/groups/5634772/Cookout-Grill#!/about) during the specific session times. If you’re unable to attend one of our designated sessions, feel free to schedule a private session with a member of our Management Team.\n\nWe wish you the best of luck in continuing throughout the staff ranks at Cookout Grill. If you have any further questions, please do not hesitate to create a ticket in our main Discord Server."
)
.addField("**NEW RANK**", "`Trainee`");
person.send(embed);
roblox.message(
event.data.card.name.split(" | ")[1],
"APPLICATION RESULTS | Passed",
"Greetings, **" +
data.RobloxUser +
"**!\n\nAfter extensive review by our Management Team, we have decided to accept your Trainee Application at Cookout Grill.\n\nWe would like to congratulate you on passing your Trainee Application. Your application met our critical expectations and requirements in order to pass.\n\nIn order to work your way up throughout the staff ranks, you must attend a training at Cookout Grill’s Training Center during the specific session times. If you’re unable to attend one of our designated sessions, feel free to schedule a private session with a member of our Management Team.\n\nWe wish you the best of luck in continuing throughout the staff ranks at Cookout Grill."
);
}
let embed2 = new discord.RichEmbed()
.setTitle(`Card list changed!`)
.setDescription(
`**CARD:** ${
event.data.card.name
} — **[CARD LINK](https://trello.com/c/${
event.data.card.shortLink
})**\n\n**EVENT:** Card moved to list __${
event.data.listAfter.name
}__ from list __${event.data.listBefore.name}__ by **[${
conf.realNames
? event.memberCreator.fullName
: event.memberCreator.username
}](https://trello.com/${event.memberCreator.username})**`
);
client.channels.get("730839109236424756").send(embed2);
Trello.addCommentToCard(
event.data.card.id,
"User has been ranked.",
function(error, trelloCard) {
console.log(error);
}
);
} else return;
} else return;
});

Unable to record again after stopping record in Kurento

I am working on this Kurento application and there is a strange problem i am facing where once I start recording the video and stop the recording, I cant start another recording again. The event goes to the server but nothing seems to be happening! PFB the code:
room.pipeline.create('WebRtcEndpoint', function (error, outgoingMedia) {
if (error) {
console.error('no participant in room');
// no participants in room yet release pipeline
if (Object.keys(room.participants).length == 0) {
room.pipeline.release();
}
return callback(error);
}
outgoingMedia.setMaxVideoRecvBandwidth(256);
userSession.outgoingMedia = outgoingMedia;
// add ice candidate the get sent before endpoint is established
var iceCandidateQueue = userSession.iceCandidateQueue[socket.id];
if (iceCandidateQueue) {
while (iceCandidateQueue.length) {
var message = iceCandidateQueue.shift();
console.error('user : ' + userSession.id + ' collect candidate for outgoing media');
userSession.outgoingMedia.addIceCandidate(message.candidate);
}
}
userSession.outgoingMedia.on('OnIceCandidate', function (event) {
console.log("generate outgoing candidate : " + userSession.id);
var candidate = kurento.register.complexTypes.IceCandidate(event.candidate);
userSession.sendMessage({
id: 'iceCandidate',
sessionId: userSession.id,
candidate: candidate
});
});
// notify other user that new user is joining
var usersInRoom = room.participants;
var data = {
id: 'newParticipantArrived',
new_user_id: userSession.id,
receiveVid: receiveVid
};
// notify existing user
for (var i in usersInRoom) {
usersInRoom[i].sendMessage(data);
}
var existingUserIds = [];
for (var i in room.participants) {
existingUserIds.push({id: usersInRoom[i].id, receiveVid: usersInRoom[i].receiveVid});
}
// send list of current user in the room to current participant
userSession.sendMessage({
id: 'existingParticipants',
data: existingUserIds,
roomName: room.name,
receiveVid: receiveVid
});
// register user to room
room.participants[userSession.id] = userSession;
var recorderParams = {
mediaProfile: 'WEBM',
uri: "file:///tmp/Room_"+room.name+"_file"+userSession.id +".webm"
};
//make recorder endpoint
room.pipeline.create('RecorderEndpoint', recorderParams, function(error, recorderEndpoint){
userSession.outgoingMedia.recorderEndpoint = recorderEndpoint;
outgoingMedia.connect(recorderEndpoint);
});
On the screen when I click the record button, the function on the server is:
function startRecord(socket) {
console.log("in func");
var userSession = userRegistry.getById(socket.id);
if (!userSession) {
return;
}
var room = rooms[userSession.roomName];
if(!room){
return;
}
var usersInRoom = room.participants;
var data = {
id: 'startRecording'
};
for (var i in usersInRoom) {
console.log("in loop");
var user = usersInRoom[i];
// release viewer from this
user.outgoingMedia.recorderEndpoint.record();
// notify all user in the room
user.sendMessage(data);
console.log(user.id);
}}
The thing is, for the very 1st time, it records properly i.e. file created on server and video&audio recorded properly.
When I press stop to stop recording, the intended effect is seen i.e. recording stops.
NOW, when I press record again, a video file is not made. The event reaches the server properly (console.log says so)
Can anyone help me pls?!
Thanks.

Mouseover or div in the blocked elements in DHTMLX Scheduler in mvc 4

I am using DHTMLX scheduler in my MVC application. I am blocking some times in the scheduler. While mouseovering or clicking the blocked elements i need to display a div or just a message is it possible to do ?
My controller code to display the blocked elements in the scheduler
public ContentResult Data(DateTime from, DateTime to)
{
var scheduler = new DHXScheduler(this);
var user = (int)Session["UserID"];
//var data = new SchedulerAjaxData(
// new SYTEntities().tblBusinessUserHolidays.Where(a => a.BusinessUserId == id && a.UserTypeId == 5).Select(e => new { id = e.Id, start_date = e.HolidayDate, text = e.HolidayDesc, end_date = "2015-07-08 10:30:00.000" })
// );
var data = new SchedulerAjaxData(
new SYTEntities().tblApps.Where(a => a.UserId1 == user).Select(e => new { id = e.AppointmentID, start_date = e.StartDate, end_date = e.EndDate, text = e.Description, event_length = e.Event_length, event_pid = e.Event_pid, rec_type = e.rec_type })
);
var blocked = new SYTEntities().tblApps
.Where(e => e.UserId1 != user && e.StartDate < to && e.EndDate >= from)
.Select(e => new { e.StartDate, e.EndDate }).ToList();
// var res = new SchedulerAjaxData(data);`
data.ServerList.Add("blocked_time", blocked);
return Content(data);
}
Script file is
[![window.schedulerClient = {
init: function () {
scheduler.serverList("blocked_time");//initialize server list before scheduler initialization
scheduler.attachEvent("onXLS", function () {
scheduler.config.readonly = true;
});
scheduler.attachEvent("onXLE", function () {
var blocked = scheduler.serverList("blocked_time");
schedulerClient.updateTimespans(blocked);
blocked.splice(0, blocked.length);
//make scheduler editable again and redraw it to display loaded timespans
scheduler.config.readonly = false;
scheduler.setCurrentView();
});
},
updateTimespans: function (timespans) {
// preprocess loaded timespans and add them to the scheduler
for (var i = 0; i < timespans.length; i++) {
var span = timespans\[i\];
span.start_date = scheduler.templates.xml_date(span.StartDate);
span.end_date = scheduler.templates.xml_date(span.EndDate);
// add a label
span.html = scheduler.templates.event_date(span.start_date) +
" - " +
scheduler.templates.event_date(span.end_date);
//define timespan as 'blocked'
span.type = "dhx_time_block";
scheduler.deleteMarkedTimespan(span);// prevent overlapping
scheduler.addMarkedTimespan(span);
$(".dhx_scale_holder ").mouseover(function () {
alert("hi");
})
}
}
};
<script type="text/javascript">
$(".dhx_cal_container").delegate(".dhx_time_block", "mouseover", function (event) {
dhtmlx.message("Blocked ");
});
</script>
I added the script code like this after that only it works.
You can either use onMouseMove event from scheduler api, or you can catch event manually.
If you do the later - note that DOM elements of marked timespans are added and removed silently, i.e. it's better not to attach listeners directly to them but use event delegation instead:
// .dhx_cal_container - top node of dhtmlxScheduler
$(".dhx_cal_container").on("mouseover", ".dhx_time_block", function(event) {
// do something
});
Here is a complete example:
http://docs.dhtmlx.com/scheduler/snippet/263a0dfa

Creating a pdf from a Knockout JS view & viewModel

Scenario: In our application a user can create a invoice by filling in certain fields on a Knockout view. This invoice can be previewed, via another Knockout page. I want to use the preview url within our PDF creator (EVOPdf), so we can provide the user with a PDF from this invoice.
To preview the invoice we load the data (on document ready) via an ajax-request:
var InvoiceView = function(){
function _start() {
$.get("invoice/GetInitialData", function (response) {
var viewModel = new ViewModel(response.Data);
ko.applyBindings(viewModel, $("#contentData").get(0));
});
};
return{
Start: _start
};
}();
My problem is within the data-binding when the PDF creator is requesting the url: the viewModel is empty. This makes sense because the GetInitialData action is not called when the PDF creator is doing the request. Calling this _start function from the preview page directly at the end of the page does not help either.
<script type="text/javascript">
$(document).ready(function() {
InvoiceView.Start();
});
</script>
Looking at the documentation of EvoPdf, JavaScript should be executed, as the JavaScriptEnabled is true by default: http://www.evopdf.com/api/index.aspx
How could I solve this, or what is the best approach to create an pdf from a knockout view?
Controller action code:
public FileResult PdfDownload(string url)
{
var pdfConverter = new PdfConverter();
// add the Forms Authentication cookie to request
if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
{
pdfConverter.HttpRequestCookies.Add(
FormsAuthentication.FormsCookieName,
Request.Cookies[FormsAuthentication.FormsCookieName].Value);
}
var pdfBytes = pdfConverter.GetPdfBytesFromUrl(url);
return new FileContentResult(pdfBytes, "application/pdf");
}
Javascript:
var model = this;
model.invoiceToEdit = ko.observable(null);
model.downloadInvoice = function (invoice) {
model.invoiceToEdit(invoice);
var url = '/invoice/preview';
window.location.href = '/invoice/pdfDownload?url=' + url;
};
The comment of xdumaine prompted me to think into another direction, thank you for that!
It did take some time for the Ajax request to load, but I also discovered some JavaScript (e.g. knockout binding) errors along the way after I put a ConversionDelay on the pdf creator object
pdfConverter.ConversionDelay = 5; //time in seconds
So here is my solution for this moment, which works for me now:
To start the process a bound click event:
model.downloadInvoice = function (invoice) {
var url = '/invoice/preview/' + invoice.Id() + '?isDownload=true';
window.open('/invoice/pdfDownload?url=' + url);
};
which result in a GET resquest on the controller action
public FileResult PdfDownload(string url)
{
var pdfConverter = new PdfConverter { JavaScriptEnabled = true };
// add the Forms Authentication cookie to request
if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
{
pdfConverter.HttpRequestCookies.Add(
FormsAuthentication.FormsCookieName,
Request.Cookies[FormsAuthentication.FormsCookieName].Value);
}
pdfConverter.ConversionDelay = 5;
var absolutUrl = ToAbsulte(url);
var pdfBytes = pdfConverter.GetPdfBytesFromUrl(absolutUrl);
return new FileContentResult(pdfBytes, "application/pdf");
}
The Pdf creator is requesting this action on the controller, with isDownload = true (see bound click event):
public ActionResult Preview(string id, bool isDownload = false)
{
return PartialView("PdfInvoice", new InvoiceViewModel
{
IsDownload = isDownload,
InvoiceId = id
});
}
Which returns this partial view:
PartialView:
// the actual div with bindings etc.
#if (Model.IsDownload)
{
//Include your javascript and css here if needed
#Html.Hidden("invoiceId", Model.InvoiceId);
<script>
$(document).ready(function () {
var invoiceId = $("#invoiceId").val();
DownloadInvoiceView.Start(invoiceId);
});
</script>
}
JavaScript for getting the invoice and apply the knockout bindings:
DownloadInvoiceView = function() {
function _start(invoiceId) {
$.get("invoice/GetInvoice/" + invoiceId, function(response) {
var viewModel = new DownloadInvoiceView.ViewModel(response.Data);
ko.applyBindings(viewModel, $("#invoiceDiv").get(0));
});
};
return {
Start: _start
};
}();
DownloadInvoiceView.ViewModel = function (data) {
var model = this;
var invoice = new Invoice(data); //Invoice is a Knockout model
return model;
};

Cannot view MicrophoneLevel and VolumeEvent session info using OpenTok

I have set up a basic test page for OpenTok using API Key, Session and Token (for publisher). Is based on the QuickStart with code added to track the microphoneLevelChanged event. Page code is available here. The important lines are:
var apiKey = "API KEY HERE";
var sessionId = "SESSION ID HERE";
var token = "TOKEN HERE";
function sessionConnectedHandler(event) {
session.publish(publisher);
subscribeToStreams(event.streams);
}
function subscribeToStreams(streams) {
for (var i = 0; i < streams.length; i++) {
var stream = streams[i];
if (stream.connection.connectionId != session.connection.connectionId) {
session.subscribe(stream);
}
}
}
function streamCreatedHandler(event) {
subscribeToStreams(event.streams);
TB.log("test log stream created: " + event);
}
var pubProps = { reportMicLevels: true };
var publisher = TB.initPublisher(apiKey, null, pubProps);
var session = TB.initSession(sessionId);
session.publish(publisher);
session.addEventListener("sessionConnected", sessionConnectedHandler);
session.addEventListener("streamCreated", streamCreatedHandler);
session.addEventListener("microphoneLevelChanged", microphoneLevelChangedHandler);
session.connect(apiKey, token);
function microphoneLevelChangedHandler(event) {
TB.log("The microphone level for stream " + event.streamId + " is: " + event.volume);
}
I know that the logging works, as the logs show up from streamCreatedHandler. However, I am not getting any events logged in the microphoneLevelChangedHandler function. I have tried this with both one and two clients loading the pages (videos show up just fine).
What do I need to do to get the microphoneLevelChanged events to show up?
OpenTok's WebRTC js library does not have a microphoneLevelChanged event so there is nothing you can do, sorry.