Events inserted using google's api and service account shows up fine when I view the calendar, but they are not included when I print the calendar.
Events manually inserted are printed as expected. I am using the following code.
string[] scopes = new string[] { CalendarService.Scope.Calendar };
GoogleCredential credential;
using (var stream = new FileStream("mikeServiceAccount.json", FileMode.Open,
FileAccess.Read))
{
credential = GoogleCredential.FromStream(stream).CreateScoped(scopes);
}
// Create the Calendar service.
var service = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Calendar Authentication Sample",
});
Event myEvent = new Event
{
Summary = "Summary Title",
Description = "event description"
Location = "Nashville, TN"
Start = new EventDateTime()
{
Date = "2018-10-19"
},
End = new EventDateTime()
{
Date = "2018-10-19"
}
};
service.Events.Insert(myEvent,"b4sbsrsdf9r82sbj0#group.calendar.google.com").Execute();
Here is a composite screen shot of what I see when I view and print the calendar. https://i.stack.imgur.com/8FqAk.png
I was able to work this out, but it was really just ended up being a proof of concept, so I don't have code I look back on. As I remember it the problem ended up being the value I used as my endDate. I don't remember specifics, but maybe I used the same date as the startDate and added the end time of midnight. Something like that anyway. Good luck and sorry I couldn't be more helpful.
Using the information provided by mikeh as a hint,
we were able to resolve the issue "All-day events are not displayed when printing".
The solution in my case by...
setting the start to "YYYY-MM-DDT00:00:00" and...
setting the end to 00:00:00 on the "next day" of the start.
Thank you.
start: {
dateTime : new Date("2020-01-25T00:00:00").toISOString()
,timeZone: 'Asia/Tokyo'
}
,end: {
dateTime : new Date("2020-01-26T00:00:00").toISOString()
,timeZone: 'Asia/Tokyo'
}
Related
I am trying to use Batch Requests with the Google Calendar API for .NET. What I am finding is that if there is any problem with an event in the batch it raises an exception and the whole batch fails with no easy way to check which event has the problem.
For example using their code
UserCredential credential;
using (var stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read))
{
credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
new[] { CalendarService.Scope.Calendar },
"user", CancellationToken.None, new FileDataStore("Calendar.Sample.Store"));
}
// Create the service.
var service = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Google Calendar API Sample",
});
// Create a batch request.
var request = new BatchRequest(service);
var eventId = "***Bad event id***";
request.Queue<Event>(service.Events.Update(
new Event
{
Summary = "Learn how to execute a batch request",
Start = new EventDateTime() { DateTime = new DateTime(2014, 1, 1, 10, 0, 0) },
End = new EventDateTime() { DateTime = new DateTime(2014, 1, 1, 12, 0, 0) }
}, calendar.Id, eventId),
(content, error, i, message) =>
{
// This is never called!!!
});
await request.ExecuteAsync();
Using this example to update an event, if I enter a bad event id in the update, it will raise an exception and the whole batch will fail. This would be less bad if the callback would be called and let me know which one, but that doesn't seem to ever even be called
What I am finding is that if there is any problem with an event in the batch it raises an exception and the whole batch fails with no easy way to check which event has the problem.
Yes this is true.
The only solution is to check if the request fails you will need to do an event list to find out which events were created and which were not. Then resend the ones that failed. In my experience most often they all fail and none are created but its not something that you can rely upon, so you need to check.
You will also find that when using batching that you may hit the user flood protection quota issues as all the requests get dumped at the server at the same time increasing your chance for a flooding error. You will then be left with trying to figure out which one failed and which one passed.
The only thing batching saves you is the HTTP Calls. Nothing else.
Batching introduces more issues then its worth, IMO.
I have been using Exchange WebServices (EWS) for some time now, in Asp.net C #, to add events in the calendars of Office365 users at my work.
I now needed those same events to appear at Microsoft Teams, with the possibility of going on videoconference.
Events appear but that possibility is not present.
One of the properties of "appointments" is "isOnlineMeeting". I tried to add it, making it true, but it always returns an error saying "Set action is invalid for property.".
In the online searches I have done, I have found that this is a read-only property.
So, is there any chance that I can "force" this property?
I have already configured my Exchange so that, in Outlook online when we do a new event, this is always by videoconference.
Some help?
Thank you!
UPDATE:
By the way, the code that I'm using is:
try {
ExchangeService service = new ExchangeService (ExchangeVersion.Exchange2013_SP1, TimeZoneInfo.FindSystemTimeZoneById ("GMT Standard Time"));
service.Url = new Uri ("https://outlook.office365.com/EWS/Exchange.asmx");
string User = "a#a.net";
string Password = "AAA";
service.Credentials = new NetworkCredential (User, Password);
Appointment appointment = new Appointment (service);
appointment.Subject = "Experiment";
appointment.Location = "Videoconference";
string dataStart = "10-02-2021 19:00:00.000";
string dataEnd = "10-02-2021 20:00:00.000";
appointment.Start = DateTime.Parse (dataStart);
appointment.End = DateTime.Parse (dataEnd);
appointment.Body = "<strong>Ignore! Just a test</strong>";
appointment.IsOnlineMeeting = true;
appointment.RequiredAttendees.Add ("b#a.net");
appointment.Save (SendInvitationsMode.SendOnlyToAll);
} catch (Exception ex) {
}
Posting the Answer for better knowledge
Copying from comments
Could you please try with this document by using Graph API. By using Graph API we can set "isOnlineMeeting" property to true, and "onlineMeetingProvider" property to "teamsForBusiness".
I'm using Google Calendar API with a service account. Actually I'm going to create an application that synchronize the events from a local database to a specific email user. The adding of an event seems working pretty well but the problem's coming when I need to update an event. In particular before the update I check if the event exist or not on the Google Calendar of a specific user, let me show an example, this is how I create the service account:
string[] scopes = new string[]
{
CalendarService.Scope.Calendar,
CalendarService.Scope.CalendarReadonly
};
var certificate = new X509Certificate2(CPath, "notasecret", X509KeyStorageFlags.Exportable);
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer("my service account email")
{
Scopes = scopes
}.FromCertificate(certificate));
CalendarService service = new CalendarService(
new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName
});
return service;
before updating or adding an event I check if the event exist in this way:
public bool EventExist(string id)
{
try
{
var service = AuthenticationService();
Event foundResponse = service.Events.Get("foo#gmail.com", id).Execute(); //id is the id of the event
return true;
}
catch (Exception ex)
{
Log.Write(ex.Message);
return false;
}
}
Now AuthenticationService() service is the method that return the service variable (the first code wrote). Later, I use the service variable for get the event of a specific user, note that the email is the primary calendar of the user. Now if I pass "primary", the event was found, instead if I pass the email, as in this case, the event was not found.
I don't know why, maybe the service-account save the event of a specific user somewhere? This situation is very bad for me, 'cause if an user delete an event with a particular id I need to check if the element exist or not into the calendar of the user.
Maybe I'm wrong with something or Google don't allow to do this?
Authenticating, searching, and adding events/entires to the google calendar is working as expected, but deleting results in a 400 bad request error.
The code is mostly copied from google's documentation.
Below googleUri is the link to the calendar entry (created by this same application/user, titled "Event To Delete") that should be removed and ConfigurationManager.AppSettings contains authentication information.
The debug output shows the calendar entry is found, yet deleting is not successful.
This uses Google Calendar API v2 which should still be functioning until 10/2014. Moving to v3 would be nice but, as far as I can tell, offers no way to authenticate with a known user+password (instead using expiring tokens that have require manually entering google credentials (?) ).
Debug.Write ("want to remove: " + googleURI);
// autheticate and get service
CalendarService svc = new CalendarService(ConfigurationManager.AppSettings["GoogleCalendarName"]);
svc.setUserCredentials(ConfigurationManager.AppSettings["GoogleCalendarUsername"], ConfigurationManager.AppSettings["GoogleCalendarPassword"]);
svc.QueryClientLoginToken();
// find the event(s) -- should only be one that can match the googleuri
EventQuery evtquery = new EventQuery(ConfigurationManager.AppSettings["GoogleCalendarPostURI"]);
evtquery.Uri = new Uri(googleURI);
EventFeed evtfeed = svc.Query (evtquery);
//should only be one event in the query
if (evtfeed == null || evtfeed.Entries.Count != 1) {
Debug.Write ("No match or too many matches for " + googleURI); // if this is less than 1, we should panic
return;
}
// we found the right one
EventEntry entry = (EventEntry)(evtfeed.Entries[0]);
Debug.Write ("Title: " + entry.Title.Text);
//hangs here until "The remote server returned an error: (400) Bad Request.
entry.Delete();
The output is:
[0:] want to remove: https://www.google.com/calendar/feeds/default/private/full/77e0tr0e3b4ctlirug30igeop0
[0:] Title: Event To Delete
I've also tried using the batch method to no avial
// https://developers.google.com/google-apps/calendar/v2/developers_guide_dotnet?csw=1#batch
// Create an batch entry to delete an the appointment
EventEntry toDelete = (EventEntry)calfeed.Entries[0];
toDelete.Id = new AtomId(toDelete.EditUri.ToString());
toDelete.BatchData = new GDataBatchEntryData("Deleting Appointment", GDataBatchOperationType.delete);
// add the entry to batch
AtomFeed batchFeed = new AtomFeed(calfeed);
batchFeed.Entries.Add(toDelete);
// run the batch
EventFeed batchResultFeed = (EventFeed)svc.Batch(batchFeed, new Uri(ConfigurationManager.AppSettings["GoogleCalendarPostURI"] ));
// check for succses
Debug.Write (batchResultFeed.Entries [0].BatchData.Status.Code);
if (batchResultFeed.Entries [0].BatchData.Status.Code != 200) {
return;
}
Couldn't figure out what was going on with v2, but I Was able to move to v3 of APIs using a Service Account to autheticate.
using System;
using Google.Apis.Calendar.v3;
using Google.Apis.Calendar.v3.Data;
// for BaseClientService.Initializer
using Google.Apis.Services;
// provides ServiceAccountCredential
using Google.Apis.Auth.OAuth2;
// read in cert
using System.Security.Cryptography.X509Certificates;
namespace LunaIntraDBCalTest
{
public class Program
{
public static string calendarname = "xxxx#gmail.com"; //address is default calendar
public static string serviceAccountEmail = "yyyy#developer.gserviceaccount.com";
public static CalendarService getCalendarService(){
// certificate downloaded after creating service account access at could.google.com
var certificate = new X509Certificate2(#"key.p12", "notasecret", X509KeyStorageFlags.Exportable);
// autheticate
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = new[] { CalendarService.Scope.Calendar }
}.FromCertificate(certificate));
// Create the service.
var service = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "LunaIntraDB",
});
return service;
}
// create event object that will later be inserted
public static Event createEvent(string Summary, string Location, string Description, DateTime ApptDateTime, double duration ){
// create an event
Event entry= new Event
{
Summary = Summary,
Location = Location,
Description = Description,
Start = new EventDateTime { DateTime = ApptDateTime },
End = new EventDateTime { DateTime = ApptDateTime.AddHours(duration) },
};
return entry;
}
// capture event ID after inserting
public static string insertEvent(Event entry){
var service = getCalendarService ();
EventsResource.InsertRequest insert = service.Events.Insert (entry, calendarname);
// TODO: try catch here; will be throw exception if bad datetime
return insert.Execute().Id;
}
public static void deleteEvent(string id){
// TODO CATCH IF NOT FOUND
// to have access to this calendar, serviceAccountEmail needed permission set by ownner in google calendar
//Calendar cal1 = service.Calendars.Get (calnedarname).Execute();
var service = getCalendarService ();
service.Events.Delete (calendarname, id).Execute ();
}
public static void Main(string[] args)
{
// create event
var entry = createEvent ("TEST", "here", "this is a test", DateTime.Now, 1.5);
string id = insertEvent (entry);
Console.WriteLine("Run to your calendar to see that this event was created... (any key after checking)");
Console.ReadKey();
deleteEvent (id);
Console.WriteLine("Should now be deleted!... (any key to close)");
Console.ReadKey();
}
}
}
I am using "Google.GData.Calendar" API to add Events to the Google Calendar using c#. But there is time difference between the events created in my DB and Google Calendar.
Following is the Code to add an Event to Google Calendar using the Google.GData API:
public static void AddEventToGoogle()
{
//string timezone = "US Mountain Standard Time";
Uri postUri = new Uri("https://www.google.com/calendar/feeds/default/private/full");
try
{
GOAuthRequestFactory authFactory = new GOAuthRequestFactory("cl", "MyApp");
authFactory.ConsumerKey = ConfigurationManager.AppSettings["GConsumerKey"].ToString();
authFactory.ConsumerSecret = ConfigurationManager.AppSettings["GConsumerKeySecret"].ToString();
authFactory.Token = "xxxxxxxxxx";
authFactory.TokenSecret = "xxxxxx";
Google.GData.Calendar.CalendarService service = new Google.GData.Calendar.CalendarService(authFactory.ApplicationName);
service.RequestFactory = authFactory;
EventEntry entry = new EventEntry();
entry.Title.Text = "Test Google Event Create";
entry.Content.Content = "Test Google Event Create";
entry.Notifications = false;
When eventTime = new When();
eventTime.AllDay = false;
eventTime.StartTime = new DateTime(2013, 5, 9, 8, 0, 0);
eventTime.EndTime = new DateTime(2013, 5, 9, 11, 0, 0);
entry.Times.Add(eventTime);
// Send the request and receive the response:
EventEntry insertedEntry = service.Insert(postUri, entry);
if (insertedEntry != null && !string.IsNullOrEmpty(insertedEntry.EventId))
{
//Get the insertedEntry.EventId
}
}
catch (GDataRequestException gre)
{
HttpWebResponse response = (HttpWebResponse)gre.Response;
}
}
But with the above code there is a time difference with the event I intended to create and the entry in the Google Calendar. The TimeZone I have in my Google Calendar is "(GMT-07:00) Mountain Time - Arizona". This is happening when i change the TimeZones of my Google Calendar to CST, PST,...
Please suggest a workaround for this situation or where do I need to specify the TimeZone while adding an event to Google Calendar.
Updated my question with the complete method i used to add an event
The GData library uses v2 of the Google APIs. I think you will need to migrate your code to v3 in order to get proper support for time zones on events.
For example, see this page which shows an example of creating a recurring event. (Switch to the ".NET" tab".
Here are some resources that may help you:
Migration Guide
What's new in v3 (it doesn't mention time zones though)
Client libraries (see the ".NET" tab)
I did look through your code and the reference guide to the v2 GData library. I only see TimeZone properties on the CalendarEntry, EventFeed, and EventQuery classes. Since you're not using any of those, I don't think it is possible in v2.
UPDATE
It is possible in the v2 API. You can pass a time zone in the ICAL formatted <gd:recurrence> tag. Take a look at the note following the example in this documentation.
However, it doesn't appear that it is exposed as a property of the EventEntry class in the .Net GData client library. So my recommendation stands - use the v3 api and client library.