// // CalendarApi.cs // // Author: // Paul Schneider // // Copyright (c) 2015 - 2017 Paul Schneider // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program. If not, see . using System; using System.Net; using System.IO; using System.Web; using Newtonsoft.Json; using System.Threading.Tasks; using Microsoft.AspNet.Identity; using Microsoft.Extensions.Logging; using Microsoft.Extensions.OptionsModel; using Google.Apis.Auth.OAuth2; using Google.Apis.Util.Store; namespace Yavsc.Models.Google.Calendar { using System.Collections.Generic; using System.Linq; using Models.Google; using Yavsc.Helpers; using Yavsc.Models.Calendar; using Yavsc.ViewModels.Calendar; /// /// Google Calendar API client. /// public class CalendarManager : ICalendarManager { protected static string scopeCalendar = "https://www.googleapis.com/auth/calendar"; private string _ApiKey; private readonly UserManager _userManager; ApplicationDbContext _dbContext; ILogger _logger; public CalendarManager(IOptions settings, UserManager userManager, ApplicationDbContext dbContext, ILoggerFactory loggerFactory) { _ApiKey = settings.Value.ApiKey; _userManager = userManager; _dbContext = dbContext; _logger = loggerFactory.CreateLogger(); } /// /// The get cal list URI. /// protected static string getCalListUri = "https://www.googleapis.com/calendar/v3/users/me/calendarList"; /// /// The get cal entries URI. /// protected static string getCalEntriesUri = "https://www.googleapis.com/calendar/v3/calendars/{0}/events"; /// /// The date format. /// private static string dateFormat = "yyyy-MM-ddTHH:mm:ss"; /// /// The time zone. TODO Fixme with machine time zone /// private string timeZone = "+01:00"; private readonly IDataStore dataStore = new FileDataStore(GoogleWebAuthorizationBroker.Folder); /// /// Gets the calendar list. /// /// The calendars. /// Yavsc user id public async Task GetCalendarsAsync (string userId) { CalendarList res = null; var login = await _userManager.GetGoogleUserLoginAsync(_dbContext,userId); var token = await _dbContext.GetTokensAsync(login.ProviderKey); if (token==null) throw new InvalidOperationException("No Google token"); HttpWebRequest webreq = WebRequest.CreateHttp(getCalListUri); webreq.Headers.Add("Authorization", "Bearer "+ token.AccessToken); webreq.Method = "GET"; webreq.ContentType = "application/http"; using (WebResponse resp = webreq.GetResponse ()) { using (Stream respstream = resp.GetResponseStream ()) { using (var rdr = new StreamReader(respstream)) { string json = rdr.ReadToEnd(); _logger.LogInformation(">> Json calendar list : "+json); res = JsonConvert.DeserializeObject(json); } } resp.Close (); } webreq.Abort (); return res; } /// /// Gets a calendar event list, between the given dates. /// /// The calendar. /// Calendar identifier. /// Mindate. /// Maxdate. /// credential string. public async Task GetCalendarAsync (string calid, DateTime mindate, DateTime maxdate) { // ServiceAccountCredential screds = new ServiceAccountCredential(init); var creds = GoogleHelpers.GetCredentialForApi(new string[]{scopeCalendar}); if (creds==null) throw new InvalidOperationException("No credential"); if (string.IsNullOrWhiteSpace (calid)) throw new Exception ("the calendar identifier is not specified"); string uri = string.Format ( getCalEntriesUri, HttpUtility.UrlEncode (calid)) + string.Format ("?orderBy=startTime&singleEvents=true&timeMin={0}&timeMax={1}&key=" + _ApiKey, HttpUtility.UrlEncode (mindate.ToString (dateFormat) + timeZone), HttpUtility.UrlEncode (maxdate.ToString (dateFormat) + timeZone)); HttpWebRequest webreq = WebRequest.CreateHttp (uri); webreq.Headers.Add (HttpRequestHeader.Authorization, "Bearer "+ await creds.GetAccessTokenForRequestAsync()); webreq.Method = "GET"; webreq.ContentType = "application/http"; CalendarEventList res = null; try { using (WebResponse resp = await webreq.GetResponseAsync ()) { using (Stream respstream = resp.GetResponseStream ()) { try { using (var rdr = new StreamReader(respstream)) { string json = rdr.ReadToEnd(); _logger.LogVerbose(">> Calendar: "+json); res= JsonConvert.DeserializeObject(json); } } catch (Exception ) { respstream.Close (); resp.Close (); webreq.Abort (); throw ; } } resp.Close (); } } catch (WebException ) { webreq.Abort (); throw; } webreq.Abort (); return res; } public async Task CreateViewModel( string inputId, string calid, DateTime mindate, DateTime maxdate) { if (calid ==null) return new DateTimeChooserViewModel { InputId = inputId, MinDate = mindate, MaxDate = maxdate }; var eventList = await GetCalendarAsync(calid, mindate, maxdate); List free = new List (); List busy = new List (); foreach (var ev in eventList.items) { if (ev.transparency == "transparent" ) { free.Add(new Period { Start = ev.start.datetime, End = ev.end.datetime }); } else busy.Add(new Period { Start = ev.start.datetime, End = ev.end.datetime }); } return new DateTimeChooserViewModel { InputId = inputId, MinDate = mindate, MaxDate = maxdate, Free = free.ToArray(), Busy = busy.ToArray(), FreeDates = free.SelectMany( p => new string [] { p.Start.ToString("DD/mm/yyyy"), p.End.ToString("DD/mm/yyyy") }).Distinct().ToArray(), BusyDates = busy.SelectMany( p => new string [] { p.Start.ToString("DD/mm/yyyy"), p.End.ToString("DD/mm/yyyy") }).Distinct().ToArray() }; } } }