diff --git a/Yavsc/Controllers/ManageController.cs b/Yavsc/Controllers/ManageController.cs index b30ff829..42264e37 100644 --- a/Yavsc/Controllers/ManageController.cs +++ b/Yavsc/Controllers/ManageController.cs @@ -10,7 +10,6 @@ using Microsoft.Extensions.OptionsModel; using Microsoft.Data.Entity; using System; using System.Collections.Generic; -using System.Net; using Microsoft.Extensions.Localization; using Yavsc.Models.Workflow; using Yavsc.Models.Identity; @@ -272,20 +271,12 @@ namespace Yavsc.Controllers } [HttpGet] - public async Task SetGoogleCalendar(string returnUrl) + public async Task SetGoogleCalendar(string returnUrl, string pageToken) { - try - { - ViewBag.Calendars = await _calendarManager.GetCalendarsAsync(User.GetUserId()); - } - catch (WebException ex) - { - // a bug - _logger.LogError("Google Api error"); - _logger.LogError("Code: "+ex.HResult+"\n"+ ex.Message); - return RedirectToAction("LinkLogin", new { provider = "Google" }); - } - return View(new SetGoogleCalendarViewModel { ReturnUrl = returnUrl }); + return View(new SetGoogleCalendarViewModel { + ReturnUrl = returnUrl, + Calendars = await _calendarManager.GetCalendarsAsync(User.GetUserId(), pageToken) + }); } [HttpPost, ValidateAntiForgeryToken] diff --git a/Yavsc/Helpers/GoogleHelpers.cs b/Yavsc/Helpers/GoogleHelpers.cs index d069bb7a..9fc275db 100644 --- a/Yavsc/Helpers/GoogleHelpers.cs +++ b/Yavsc/Helpers/GoogleHelpers.cs @@ -33,10 +33,9 @@ namespace Yavsc.Helpers using Yavsc.Models.Calendar; using Google.Apis.Auth.OAuth2; using Microsoft.Data.Entity; - using Google.Apis.Auth.OAuth2.Flows; using Microsoft.AspNet.Identity.EntityFramework; using Yavsc.Services; - + /// /// Google helpers. /// @@ -86,25 +85,16 @@ namespace Yavsc.Helpers } public static async Task> GetGoogleUserLoginAsync( - this UserManager userManager, - ApplicationDbContext context, + this ApplicationDbContext context, string yavscUserId) { - var user = await userManager.FindByIdAsync(yavscUserId); + var user = context.Users.FirstOrDefaultAsync(u=>u.Id==yavscUserId); + if (user==null) return null; var googleLogin = await context.UserLogins.FirstOrDefaultAsync( x => x.UserId == yavscUserId && x.LoginProvider == "Google" ); return googleLogin; } - public static UserCredential GetGoogleCredential(string googleUserLoginKey) - { - if (string.IsNullOrEmpty(googleUserLoginKey)) - throw new InvalidOperationException("No Google login"); - var flow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer()); - throw new NotImplementedException(); - // TokenResponse resp = flow. ; - // return new UserCredential(flow, googleUserLoginKey, resp); - } public static async Task GetFreeTime (this ICalendarManager manager, string calId, DateTime startDate, DateTime endDate) { diff --git a/Yavsc/Models/ApplicationDbContext.cs b/Yavsc/Models/ApplicationDbContext.cs index 8248f5fe..afe0dabf 100644 --- a/Yavsc/Models/ApplicationDbContext.cs +++ b/Yavsc/Models/ApplicationDbContext.cs @@ -125,28 +125,7 @@ namespace Yavsc.Models public DbSet Services { get; set; } public DbSet Products { get; set; } - public Task ClearTokensAsync() - { - Tokens.RemoveRange(this.Tokens); - SaveChanges(null); - return Task.FromResult(0); - } - - public Task DeleteTokensAsync(string email) - { - if (string.IsNullOrEmpty(email)) - { - throw new ArgumentException("email MUST have a value"); - } - - var item = this.Tokens.FirstOrDefault(x => x.UserId == email); - if (item != null) - { - Tokens.Remove(item); - SaveChanges(email); - } - return Task.FromResult(0); - } + public Task GetTokensAsync(string googleUserId) { diff --git a/Yavsc/Services/GoogleApis/CalendarClient.cs b/Yavsc/Services/GoogleApis/CalendarClient.cs deleted file mode 100644 index ff126bff..00000000 --- a/Yavsc/Services/GoogleApis/CalendarClient.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Google.Apis.Requests; -using Google.Apis.Services; -using Yavsc.Models.Google; - -namespace Yavsc.Services.GoogleApis -{ - public class CalendarClient : ClientServiceRequest - { - public CalendarClient(IClientService service) : base (service) { - - } - public override string HttpMethod - { - get - { - return "POST"; - } - } - public string calendarId - { - get; set; - } - public override string MethodName - { - get - { - return "calendar.events.insert"; - } - } - - public override string RestPath - { - get - { - return "calendars/{calendarId}/events"; - } - } - } -} \ No newline at end of file diff --git a/Yavsc/Services/GoogleApis/CalendarManager.cs b/Yavsc/Services/GoogleApis/CalendarManager.cs index 1af958b4..bec24aa7 100644 --- a/Yavsc/Services/GoogleApis/CalendarManager.cs +++ b/Yavsc/Services/GoogleApis/CalendarManager.cs @@ -28,12 +28,18 @@ using Google.Apis.Auth.OAuth2; using Google.Apis.Util.Store; using Google.Apis.Calendar.v3; using Google.Apis.Calendar.v3.Data; +using System.Collections.Generic; +using System.Linq; +using Google.Apis.Http; +using Google.Apis.Services; +using Microsoft.AspNet.Authentication.OAuth; +using Microsoft.Data.Entity; namespace Yavsc.Services { - using System.Collections.Generic; - using System.Linq; - using Google.Apis.Services; + using System.Threading; + using Google.Apis.Auth.OAuth2.Flows; + using Newtonsoft.Json; using Yavsc.Helpers; using Yavsc.Models; using Yavsc.Models.Calendar; @@ -43,164 +49,204 @@ namespace Yavsc.Services /// Google Calendar API client. /// public class CalendarManager : ICalendarManager - { - public class ExpiredTokenException : Exception {} + { + public class ExpiredTokenException : Exception { } protected static string scopeCalendar = "https://www.googleapis.com/auth/calendar"; private string _ApiKey; + private IAuthorizationCodeFlow _flow; + private readonly UserManager _userManager; - private readonly UserManager _userManager; + ApplicationDbContext _dbContext; - ApplicationDbContext _dbContext; - ILogger _logger; + IDataStore _dataStore; + ILogger _logger; - public CalendarManager(IOptions settings, - UserManager userManager, - ApplicationDbContext dbContext, - ILoggerFactory loggerFactory) - { + public CalendarManager(IOptions settings, + UserManager userManager, + ApplicationDbContext dbContext, + IDataStore dataStore, + 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) - { - var service = new CalendarService(); - - var listRequest = service.CalendarList.List(); - + _userManager = userManager; + _dbContext = dbContext; + _logger = loggerFactory.CreateLogger(); + _dataStore = dataStore; + _flow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer + { + ClientSecrets = new ClientSecrets + { + ClientId = Startup.GoogleSettings.ClientId, + ClientSecret = Startup.GoogleSettings.ClientSecret + }, + Scopes = new[] { scopeCalendar }, + DataStore = dataStore + }); + _logger.LogWarning($"Using Google data store from "+JsonConvert.SerializeObject(_dataStore)); + } + + /// + /// 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"; + + /// + /// Gets the calendar list. + /// + /// The calendars. + /// Yavsc user id + public async Task GetCalendarsAsync(string userId, string pageToken) + { + if (string.IsNullOrWhiteSpace(userId)) + throw new Exception("the user id is not specified"); + var service = await CreateUserCalendarServiceAsync(userId); + CalendarListResource.ListRequest calListReq = service.CalendarList.List (); + calListReq.PageToken = pageToken; + return calListReq.Execute (); + } + + + private ServiceAccountCredential GetServiceAccountCredential() + { + var creds = GoogleHelpers.GetCredentialForApi(new string[] { scopeCalendar }); + if (creds == null) + throw new InvalidOperationException("No credential"); + return creds; + } + /// + /// 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) + { + var service = await GetServiceAsync(); + var listRequest = service.Events.List(calid); return await listRequest.ExecuteAsync(); - } - - - private ServiceAccountCredential GetServiceAccountCredential() - { - var creds = GoogleHelpers.GetCredentialForApi(new string[]{scopeCalendar}); - if (creds==null) - throw new InvalidOperationException("No credential"); + } + public async Task CreateViewModelAsync( + string inputId, + string calid, DateTime mindate, DateTime maxdate) + { + if (calid == null) + return new DateTimeChooserViewModel + { + InputId = inputId, + MinDate = mindate, + MaxDate = maxdate + }; - return creds; - } - /// - /// 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) - { - var service = new CalendarService(); + var eventList = await GetCalendarAsync(calid, mindate, maxdate); + List free = new List(); + List busy = new List(); - var listRequest = service.Events.List(calid); - return await listRequest.ExecuteAsync(); - } - public async Task CreateViewModelAsync( - 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) { DateTime start = ev.Start.DateTime.Value; DateTime end = ev.End.DateTime.Value; - if (ev.Transparency == "transparent" ) + if (ev.Transparency == "transparent") { - free.Add(new Period { Start = start, End = end }); + free.Add(new Period { Start = start, End = end }); } else busy.Add(new Period { Start = start, End = end }); } - 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() - }; - } - -/// -/// Creates a event in a calendar -/// calendar.events.insert -/// -/// -/// -/// -/// -/// -/// -/// -/// + 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() + }; + } + + /// + /// Creates a event in a calendar + /// calendar.events.insert + /// + /// + /// + /// + /// + /// + /// + /// + /// public async Task CreateEventAsync(string calid, DateTime startDate, int lengthInSeconds, string summary, string description, string location, bool available) - { - - if (string.IsNullOrWhiteSpace (calid)) - throw new Exception ("the calendar identifier is not specified"); - var creds = GetServiceAccountCredential(); -GoogleCredential credential = await GoogleCredential.GetApplicationDefaultAsync(); -var computeService = new BaseClientService.Initializer() -{ - HttpClientInitializer = credential -}; -computeService.ApiKey = Startup.GoogleSettings.ApiKey; -computeService.ApplicationName = "Yavsc"; -computeService.Validate(); + { + + if (string.IsNullOrWhiteSpace(calid)) + throw new Exception("the calendar identifier is not specified"); + GoogleCredential credential = await GoogleCredential.GetApplicationDefaultAsync(); + var computeService = new BaseClientService.Initializer() + { + HttpClientInitializer = credential + }; + computeService.ApiKey = Startup.GoogleSettings.ApiKey; + computeService.ApplicationName = "Yavsc"; + computeService.Validate(); var service = new CalendarService(); - Event ev = new Event { + Event ev = new Event + { Start = new EventDateTime { DateTime = startDate }, End = new EventDateTime { DateTime = startDate.AddSeconds(lengthInSeconds) }, Summary = summary, Description = description }; - var insert = service.Events.Insert(ev,calid); + var insert = service.Events.Insert(ev, calid); var inserted = await insert.ExecuteAsync(); - + return inserted; + } + + public async Task GetServiceAsync() + { + GoogleCredential credential = await GoogleCredential.GetApplicationDefaultAsync(); + return new CalendarService(new BaseClientService.Initializer() + { + HttpClientInitializer = credential, + ApplicationName = "Yavsc" + }); + } + + /// + /// Creates Google User Credential + /// + /// Yavsc use id + /// + public async Task CreateUserCalendarServiceAsync(string userId) + { + var login = await _dbContext.GetGoogleUserLoginAsync(userId); + var token = await _flow.LoadTokenAsync(login.ProviderKey, CancellationToken.None); + UserCredential cred = new UserCredential(_flow,login.ProviderKey,token); + return new CalendarService(new BaseClientService.Initializer() + { + HttpClientInitializer = cred, + ApplicationName = "Yavsc" + }); } } } diff --git a/Yavsc/Services/ICalendarManager.cs b/Yavsc/Services/ICalendarManager.cs index 0bee2597..3cc9aa15 100644 --- a/Yavsc/Services/ICalendarManager.cs +++ b/Yavsc/Services/ICalendarManager.cs @@ -31,7 +31,7 @@ namespace Yavsc.Services /// I calendar manager. /// public interface ICalendarManager { - Task GetCalendarsAsync (string userId); + Task GetCalendarsAsync (string userId, string pageToken); Task GetCalendarAsync (string calid, DateTime mindate, DateTime maxdate); Task CreateViewModelAsync( string inputId, diff --git a/Yavsc/Startup/Startup.OAuth.cs b/Yavsc/Startup/Startup.OAuth.cs index ec4afe32..c9d389c7 100644 --- a/Yavsc/Startup/Startup.OAuth.cs +++ b/Yavsc/Startup/Startup.OAuth.cs @@ -15,9 +15,13 @@ using Microsoft.Extensions.OptionsModel; using Microsoft.Extensions.WebEncoders; using OAuth.AspNet.AuthServer; using OAuth.AspNet.Tokens; +using Google.Apis.Util.Store; using Yavsc.Auth; using Yavsc.Extensions; using Yavsc.Models; +using Newtonsoft.Json; +using Microsoft.Extensions.Logging; +using Google.Apis.Auth.OAuth2.Responses; namespace Yavsc { @@ -87,7 +91,7 @@ namespace Yavsc // } private void ConfigureOAuthApp(IApplicationBuilder app, - SiteSettings settingsOptions) + SiteSettings settingsOptions, ILogger logger) { app.UseIdentity(); @@ -144,9 +148,18 @@ namespace Yavsc { var gcontext = context as GoogleOAuthCreatingTicketContext; context.Identity.AddClaim(new Claim(YavscClaimTypes.GoogleUserId, gcontext.GoogleUserId)); - var service = - serviceScope.ServiceProvider.GetService(); - await service.StoreTokenAsync(gcontext.GoogleUserId, context.TokenResponse); + var dbContext = serviceScope.ServiceProvider.GetService(); + await dbContext.StoreTokenAsync(gcontext.GoogleUserId, context.TokenResponse); + var store = serviceScope.ServiceProvider.GetService(); + + await store.StoreAsync(gcontext.GoogleUserId, new TokenResponse { + AccessToken = gcontext.TokenResponse.AccessToken, + RefreshToken = gcontext.TokenResponse.RefreshToken, + TokenType = gcontext.TokenResponse.TokenType, + ExpiresInSeconds = int.Parse(gcontext.TokenResponse.ExpiresIn), + IssuedUtc = DateTime.Now + }); + } } } diff --git a/Yavsc/Startup/Startup.cs b/Yavsc/Startup/Startup.cs index 5764d9fe..211fca10 100755 --- a/Yavsc/Startup/Startup.cs +++ b/Yavsc/Startup/Startup.cs @@ -27,6 +27,7 @@ namespace Yavsc { using System.Net; using Formatters; + using Google.Apis.Util.Store; using Microsoft.Extensions.Localization; using Models; using PayPal.Manager; @@ -230,6 +231,7 @@ namespace Yavsc services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient( (sp) => new FileDataStore("googledatastore",false) ); services.AddTransient(); // TODO for SMS: services.AddTransient(); @@ -347,7 +349,7 @@ namespace Yavsc options.AutomaticAuthentication = false; }); - ConfigureOAuthApp(app, SiteSetup); + ConfigureOAuthApp(app, SiteSetup, logger); ConfigureFileServerApp(app, SiteSetup, env, authorizationService); ConfigureWebSocketsApp(app, SiteSetup, env); ConfigureWorkflow(app, SiteSetup, logger); diff --git a/Yavsc/ViewModels/Calendar/SetGoogleCalendarViewModel.cs b/Yavsc/ViewModels/Calendar/SetGoogleCalendarViewModel.cs index 50690385..f16fa40d 100644 --- a/Yavsc/ViewModels/Calendar/SetGoogleCalendarViewModel.cs +++ b/Yavsc/ViewModels/Calendar/SetGoogleCalendarViewModel.cs @@ -1,4 +1,6 @@ +using Google.Apis.Calendar.v3.Data; + namespace Yavsc.ViewModels.Calendar { public class SetGoogleCalendarViewModel @@ -6,6 +8,8 @@ namespace Yavsc.ViewModels.Calendar public string GoogleCalendarId { get; set; } public string ReturnUrl { get; set; } + + public CalendarList Calendars { get; set; } } } diff --git a/Yavsc/Views/Manage/SetGoogleCalendar.cshtml b/Yavsc/Views/Manage/SetGoogleCalendar.cshtml index 0c2256cc..cf12dec5 100644 --- a/Yavsc/Views/Manage/SetGoogleCalendar.cshtml +++ b/Yavsc/Views/Manage/SetGoogleCalendar.cshtml @@ -5,16 +5,16 @@ }
@{ var entryNum=0; } -@foreach (var calendar in ViewBag.Calendars?.items) +@foreach (var calendar in Model.Calendars.Items) { entryNum++; - @if (calendar.accessRole=="owner") { + @if (calendar.AccessRole=="owner") { } diff --git a/Yavsc/Views/_ViewImports.cshtml b/Yavsc/Views/_ViewImports.cshtml index ae05c24c..7efbb850 100755 --- a/Yavsc/Views/_ViewImports.cshtml +++ b/Yavsc/Views/_ViewImports.cshtml @@ -49,4 +49,3 @@ @inject IOptions GoogleSettings @inject IOptions SiteSettings @inject IHostingEnvironment HostingEnvironment -@inject ICalendarManager CalendarManager; diff --git a/Yavsc/Yavsc.csproj b/Yavsc/Yavsc.csproj index 513e0761..9c561200 100644 --- a/Yavsc/Yavsc.csproj +++ b/Yavsc/Yavsc.csproj @@ -1241,7 +1241,6 @@ - @@ -1249,6 +1248,13 @@ + + + + + + +