Reputation: 3
I'm trying to write a program that will synchronize events between a CRM and Google Calendar of several Google accounts.
It's a Windows Console application.
For each Google account, in the API Console I enabled the Calendar API, created an application named "UpdateSync" (type : native) then downloaded the JSON file.
I renamed those files using the account mail address (ie [email protected])
Next, I wrote the code bellow :
/// <summary>
/// Loads updated event from Google Calender after last synchonization date
/// </summary>
/// <param name="user">The user we want to get appointments</param>
public List<Appointment> LoadAppointments(User user)
{
Console.WriteLine("LoadAppointments({0})", user.Email);
List<Appointment> Appointments = new List<Appointment>();
UserCredential credential;
using (var stream = new FileStream(string.Format("credentials\\{0}.json", user.Email), FileMode.Open, FileAccess.Read))
{
try
{
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(GoogleClientSecrets.Load(stream).Secrets, new[] { CalendarService.Scope.Calendar }, "user", CancellationToken.None, new FileDataStore("UpdayeSync.Credentials")).Result;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
return null;
}
}
BaseClientService.Initializer initializer = new BaseClientService.Initializer();
initializer.HttpClientInitializer = credential;
initializer.ApplicationName = "UpdateSync";
service = new CalendarService(initializer);
EventsResource.ListRequest req = service.Events.List("primary");
req.TimeMin = DateTime.Now.AddMonths(-2).ToString("o");
req.ShowDeleted = true;
req.UpdatedMin = XmlConvert.ToString(LastSync, XmlDateTimeSerializationMode.Utc);
req.SingleEvents = true;
Events events;
try
{
events = req.Execute();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
return null;
}
// [...]
}
This code is called for each JSON file.
At the first call, the account to synchronize was "[email protected]". Google Chrome automatically oppened, and auto-logged with my own account ([email protected]) and asked me to allow my program to access Calendar API.
I accepted.
This popup never shown again.
Any change done for any account was done on my own calendar, not the one the JSON files refer to.
What's wrong ? How to access several Google accounts with a unique program ?
This program will run on a server as a scheduled task, and I must not open any window, as noone will look at the server's screen. I can't ask the user to authentificate himself, as there is not user.
But I can do anything on the Google account of any of the users (enabling API, creating keys, granting application, etc.)
Upvotes: 0
Views: 1444
Reputation: 3512
You should create a new CalendarService (lightweight component) per user. CalendarService and all other Google services are implemented as immutables (for simplicity and to support thread-safe operations).
Create a new service for each user and use a different userId ("user1", "user2", etc.) as a parameter to GoogleWebAuthorizationBroker.AuthorizeAsync.
UPDATE:
You should also create your own class of flow:
class ForceUIGoogleAuthorizationCodeFlow : AuthorizationCodeFlow { public override AuthorizationCodeRequestUrl CreateAuthorizationCodeRequest(string redirectUri) { return new GoogleAuthorizationCodeRequestUrl(new Uri(AuthorizationServerUrl)) { ClientId = ClientSecrets.ClientId, Scope = string.Join(" ", Scopes), RedirectUri = redirectUri, ApprovalPrompt = "force", }; } }
and then,
replace the your call to GoogleWebAuthorizationBroker with the following code:
var initializer = new GoogleAuthorizationCodeFlow.Initializer { ClientSecrets = clientSecrets, Scopes = [SCOPED_HERE]; initializer.DataStore = new FileDataStore("Credentials"); }; var flow = new ForceUIGoogleAuthorizationCodeFlow(initializer);
// Create authorization code installed app instance and authorize the user.
crdentials = await new AuthorizationCodeInstalledApp(flow,
new LocalServerCodeReceiver()).AuthorizeAsync
("USER_ID_HERE", taskCancellationToken).ConfigureAwait(false);
Upvotes: 2