Updating event via MS Graph API removing Join Button in the event - microsoft-graph-api

I have created an event in the outlook calendar. The event contains Teams join link.
While I am updating the event from MS Graph API, the join button is being removed.
Here is the sample code of what I am doing:
void UpdateEventInCalendar(string eventId)
{
var getCalEvent = Task.Run(() =>
{
return service.Me.Events[eventId].Request().GetAsync();
});
Task.WaitAll(getCalEvent);
BodyType bodyType = BodyType.Text;
Event eventToUpdate = getCalEvent.Result;
Event updatedEvent = new Event();
updatedEvent.Id = eventToUpdate.Id;
updatedEvent.Subject = "Updated text";
updatedEvent.ShowAs = eventToUpdate.ShowAs;
updatedEvent.Body = new ItemBody
{
ContentType = bodyType,
Content = "Some new content"
};
graphServiceClient.Me.Events[updatedEvent.Id].Request().UpdateAsync(updatedEvent.Id);
}
Event before update:
Event update content:
Event after update:
How to keep the event while updating the event?

As a workaround you can try this to keep your online meeting appeared:
First: in your addEvent function, your body should be like this
AddedEvent.Body = new ItemBody
{
ContentType = BodyType.Html,
Content = "<p id = 'MsgContent'>Your Body</p>"
};
Second: In the update event, you can change the body content like this
HtmlDocument html = new HtmlDocument();
html.LoadHtml(EventToUpdate.Body.Content);
html.GetElementbyId("Msgcontent").InnerHtml = "Your new body";
updatedEvent.Body = EventToUpdate.Body;
updatedEvent.Body.Content = html.DocumentNode.OuterHtml;

Try not updating the body and you will be able to make it work. See this thread. Yes, if you update the body without isonlinemeeting, the teams meeting blob will be removed and this makes the isonlinemeeting property to false and we are loosing the button.

I faced the same issue and I got out with this solution, hope it helps.
You create an online event through the API with an empty body. The response from the server contains the HTML body with the join link and you store it. Then, if you update the event preserving all the online meeting related content, the event keeps having the join button, so you get the needed result.
If you update the event body deleting the online meeting related content, you loose the join button and, according to the docs, there's not much you can do about it.

Related

Stop Firebase from adding index number of ObservableCollection

Does anyone know how I can stop Real Time Firebase from adding the index of an observable collection as a title? All code is listed below along with how the data is shown in Firebase.
How data is presented in Firebase:
Index 0 is added to the DB as title '0'
//Await task that post the code to firebase
public static async Task AddExercise(ObservableCollection<Exercise> exercisepassed)
{
await Client.Child("exercises").PostAsync(exercisepassed);
}
Code that get sent to await task :
addexercise1.Add(new Exercise
{
id = uniqeexid,
title = title,
UserId = uid,
DurationMinutes = durationMinutes,
StartDate = startdate,
NotificationIds = notificationIds,
Time = time,
VideoId = videoId,
Often = often,
exerciseid = exid });
await DbFirebase.AddExercise(addexercise1);
If you want to get rid of the -N7... type keys, call PutAsync instead of PostAsync.
If you want to get rid of the 0, then don't post a ObservableCollection<Exercise>, but instead post a single Exercise object.

Mail properties not being saved in UpdateAsync

I am starting out in MS Graph. I have below code to pick up all mail messages from Inbox of a specific user. Then I go through each message, process it and set its Subject. When I try to save back message using UpdateAsync it executes fine but change in mail subject text doesn't seem to get saved.
What am I doing wrong?
Thanks
Regards
var inboxMessages = await graphClient
.Users[user.Id]
.MailFolders.Inbox
.Messages
.Request()
.OrderBy("receivedDateTime DESC")
.GetAsync();
foreach(Microsoft.Graph.Message x in inboxMessages) {
//Process message
// ...
x.Subject = "Processed: " + x.Subject
//Save changes to message Subject
await graphClient
.Users[user.Id]
.MailFolders.Inbox
.Messages[$"{x.Id}"]
.Request()
.UpdateAsync(x);
}
According to the documentation you can update Subject only for messages that have isDraft = true but not for those that have already been sent.

How does Outlook sync with events created in Google?

I am writing a calendar integration and using the Google Calendar api and Outlook Graph api to sync calendar events. I am receiving webhook notifications as changes are made to events, so I need a way to identify that an event in Google and an event in Outlook are the same (or different) events. Theoretically, this should be done with the iCalUId.
However, when I create an event in Google that has an Outlook attendee, the event created in Outlook does not have the same iCalUId as the event in Google.
I created a work-around for this by reading the iCalUId from the attachment sent by Google to Outlook. However, the Outlook event itself still has a different iCalUId than the Google event, which makes it difficult to process future updates.
Conceptually, Outlook is able to update an event (and show it updated on the calendar) when it is updated by Google. So Outlook must be storing some reference to the Google event.
Does anyone know what that reference is and if it is accessible through the Graph API/SDK?
UPDATE
Here is the code I am using to save an event in Google using the Google API/SDK:
var service = await GoogleAuthenticationProvider.GetCalendarService(CALENDAR_CLIENT_ID, CALENDAR_CLIENT_SECRET, CALENDAR_ACCESS_SCOPES, Person.CalendarRefreshToken).ConfigureAwait(false);
var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(Person.TimeZone);
//in google, having the organizer as an attendee causes the organizer to receive notification emails from google- which we don't want, so remove him/her from the attendees
var attendees = Event.Attendees.Where(a => a.Value != Event.OrganizerEmail);
var tmpEvent = new Google.Apis.Calendar.v3.Data.Event
{
Id = ExternalID.IsNullOrEmptyExtension() ? Convert.ToString(Event.ID) : ExternalID,
Start = new EventDateTime
{
DateTime = Event.StartDate,
TimeZone = GetGoogleTimeZoneFromSystemTimeZone(timeZoneInfo.Id)
},
End = new EventDateTime
{
DateTime = Event.EndDate,
TimeZone = GetGoogleTimeZoneFromSystemTimeZone(timeZoneInfo.Id)
},
Summary = Event.Title,
Description = Event.Description,
Attendees = attendees.Select(a => new EventAttendee
{
Email = a.Value,
ResponseStatus = "accepted"
}).ToList(),
GuestsCanInviteOthers = false,
Location = Event.Location,
Recurrence = Event.RecurrenceRule.IsNullOrEmptyExtension() ? new List<string> { } : new List<string> { "RRULE:" + Event.RecurrenceRule }
};
var savedEvent = new Google.Apis.Calendar.v3.Data.Event { };
if (ExternalID.IsNullOrEmptyExtension())
{
EventsResource.InsertRequest insertRequest = service.Events.Insert(tmpEvent, GOOGLE_PRIMARY_CALENDARID);
insertRequest.SendUpdates = EventsResource.InsertRequest.SendUpdatesEnum.All;
savedEvent = await insertRequest.ExecuteAsync().ConfigureAwait(false);
}
else
{
var updateRequest = service.Events.Update(tmpEvent, GOOGLE_PRIMARY_CALENDARID, ExternalID);
updateRequest.SendUpdates = EventsResource.UpdateRequest.SendUpdatesEnum.All;
savedEvent = await updateRequest.ExecuteAsync().ConfigureAwait(false);
}

Gupshup - multiple messages delay feature not working

I've tried to implement a delay feature on my bot to display multiple messages one after the other. The delay feature is displaying in my Flow Bot Builder diagram, but when I test in the conversation tester, and proxy bot on Messenger, the delay doesn't actually happen - all the messages display at once.
I have added the delay code in the IDE to the default.scr file:
[main]
label_dych:Hi! I'm delay-bot and I'm here to help you with any questions you have.:continue
((delay 2000))
label_gthk:I'll never need to take any personal or financial information from you, so as we chat please don't tell me any!:continue
((delay 1000))
label_ylbn:{"name":"quickreply","type":"quick_reply","alias":"What can I help you with?","msgid":"117af569-5188-ff7e-9b48-8c553c2f36cb","content":{"type":"text","text":"What can I help you with?"},"options":[{"type":"text","title":"My Page","iconurl":"","id":"ac49ad32-c9bc-469f-2152-c7c842bad8ea","isDuplicate":false,"name":"user"},{"type":"text","title":"Team Spaces","iconurl":"","id":"8a2017ac-2fc3-0901-be8d-1fad5a2dba12","isDuplicate":false,"name":"user"},{"type":"text","title":"Offline Support","iconurl":"","id":"70861407-e706-17a3-207b-c43958fde83e","isDuplicate":false,"name":"user"},{"type":"text","title":"Something else","iconurl":"","id":"d3f7b6b4-e70a-098d-dde9-1da3e8cc08dc","isDuplicate":false,"name":"user"}]}
I've also added the options.apikey line of code to the index.js file as instructed to do here: https://www.gupshup.io/developer/docs/bot-platform/guide/sending-multiple-messages-botscript
function ScriptHandler(context, event){
var options = Object.assign({}, scr_config);
options.current_dir = __dirname;
//options.default_message = "Sorry Some Error Occurred.";
// You can add any start point by just mentioning the
<script_file_name>.<section_name>
// options.start_section = "default.main";
options.success = function(opm){
context.sendResponse(JSON.stringify(opm));
};
options.error = function(err) {
console.log(err.stack);
context.sendResponse(options.default_message);
};
botScriptExecutor.execute(options, event, context);
options.apikey = "1mbccef47ab24dacad3f99557cb35643";
}
Is there any obvious reason why the delay effect wouldn't be working in between messages? I've used the apikey that is displayed for my gupshup account when I click the logo in the top right.
You have placed the API key after the scripting tool execute function is called. Place the API Key anywhere before the botScriptExecutor.execute and the delay should work.
Also, the timing of the delay is in milliseconds.
Sample:
function ScriptHandler(context, event){
var options = Object.assign({}, scr_config);
options.current_dir = __dirname;
//options.default_message = "Sorry Some Error Occurred.";
options.apikey = "1mbccef47ab24dacad3f99557cb35643";
// You can add any start point by just mentioning the
<script_file_name>.<section_name>
// options.start_section = "default.main";
options.success = function(opm){
context.sendResponse(JSON.stringify(opm));
};
options.error = function(err) {
console.log(err.stack);
context.sendResponse(options.default_message);
};
botScriptExecutor.execute(options, event, context);
}

Capturing twitter status timeline updates/infinite scroll updates

I'm using KRL to inject elements into twitter timeline statuses similar to Jesse Stay's TwitterBook. The problem I have is that these elements are only associated with statuses that are currently visible when the bookmarklet is initiated. If a new status is added through the 'new tweet' updated via Ajax or through status updates via infinite scroll, these new statuses are untouched.
Is there a way to either poll for new statuses or sense a twitter status update event via KRL in order to inject elements only into those newly added statuses?
The example posted at
http://kynetxappaday.wordpress.com/2010/12/25/day-21-modifying-facebook-stream-with-kynetx/
works with the Facebook stream but the concept is the same
create setTimeout infinite loop to look for stream items
only select stream items not marked as processed
process stream items
rinse and repeat
Code example from post
ruleset a60x512 {
meta {
name "MikeGrace-status-update-translator"
description <<
MikeGrace-status-update-translator
>>
author "Mike Grace"
logging on
}
global {
datasource insult:HTML <- "http://www.pangloss.com/seidel/Shaker/index.html?" cachable for 1 second;
}
rule find_status_updates_by_mike_grace {
select when pageview ".*"
{
notify("Starting to look for status upates by Mike Grace","");
emit <|
// get app object to raise web events
app = KOBJ.get_application("a60x512");
// function that finds FB status updates by Mike Grace
function findMikeGrace() {
// loop through each stream item on the page that hasn't been processed already by the app
$K("li[id^=stream_story]:not(li[kfbt])").each(function() {
var currentStreamItem = this;
// grab the current stream item posters name
var name = $K(currentStreamItem).find(".actorName").text();
// mark the stream item as being processed to reduce future processing times
$K(currentStreamItem).attr("kfbt","y");
// is the stream item by the perpetrator?
if (name == "Michael Grace") {
// strikethrough the original update
$K(currentStreamItem).find(".messageBody").wrap("<strike />");
// get selector to return translation of status update
var returnSelector = $K(currentStreamItem).attr("id");
returnSelector = "li#"+returnSelector+" .messageBody";
// raise web event to get translation for non geeks
app.raise_event("get_insult", {"returnSelector":returnSelector});
} // end of checking name
}); // end of looping through unprocessed stream items
// call myself again later to process new items on the page
setTimeout(function() {
findMikeGrace();
}, 9000);
}
// start the process of finding the perpetrator
findMikeGrace();
|>;
}
}
rule get_insult {
select when web get_insult
pre {
selector = event:param("returnSelector");
insulter = datasource:insult("#{selector}");
foundInsult = insulter.query("font");
singleInsult = foundInsult[0];
}
{
emit <|
console.log(singleInsult);
$K(selector).parent().after("<br/>"+singleInsult);
|>;
}
}
}

Resources