private async Task <StravaTokenSet> EnsureValidTokens(StravaTokenSet tokenSet, int athleteIdentifier) { if (tokenSet.ExpiresAt.ToUniversalTime() < DateTimeOffset.UtcNow.AddMinutes(5)) { _logger.LogInformation("Token expiring; refreshing."); var athlete = await _athleteRepository.GetAthlete(athleteIdentifier) ?? new Athlete(); var url = $"https://www.strava.com/api/v3/oauth/token?client_id={_stravaSettings.ClientId}&client_secret={_stravaSettings.ClientSecret}&grant_type=refresh_token&refresh_token={tokenSet.RefreshToken}"; var request = new HttpRequestMessage(HttpMethod.Post, url); var response = await _client.SendAsync(request); if (response.IsSuccessStatusCode) { var responseString = await response.Content.ReadAsStringAsync(); tokenSet = JsonConvert.DeserializeObject <StravaTokenSet>(responseString); athlete.AccessToken = tokenSet.AccessToken; athlete.RefreshToken = tokenSet.RefreshToken; athlete.ExpiresAt = tokenSet.ExpiresAt; _logger.LogInformation("Token refresh successful; updating saved athlete."); await _athleteRepository.CreateOrUpdateAthlete(athlete); } } return(tokenSet); }
private async Task <AthleteViewModel> CreateAthlete(StravaTokenSet tokenSet, string slackUserId, int athleteIdentifier, string name) { var athlete = await BuildAthleteViewModel(tokenSet, slackUserId, athleteIdentifier, name); var latestActivity = athlete.Activities.FirstOrDefault(); await _athleteRepository.CreateOrUpdateAthlete(athlete); await PostWelcomeMessage(slackUserId, latestActivity); return(athlete); }
public async Task <List <Activity> > GetRecentActivities(StravaTokenSet tokenSet, int athleteIdentifier) { tokenSet = await EnsureValidTokens(tokenSet, athleteIdentifier); var since = DateTime.UtcNow.AddDays(-DaysOfActivities).Date; var timestamp = (int)since.Subtract(new DateTime(1970, 1, 1)).TotalSeconds; var request = new HttpRequestMessage(HttpMethod.Get, $"https://www.strava.com/api/v3/athlete/activities?after={timestamp}"); var result = await SendStravaRequest <List <Activity> >(request, tokenSet, athleteIdentifier); return(result.OrderByDescending(a => a.StartDateLocal).ToList()); }
public async Task <IActionResult> Index() { try { if (User.Identity.IsAuthenticated) { var slackUserId = Request.Cookies["SlackUserId"]; if (string.IsNullOrWhiteSpace(slackUserId)) { return(RedirectToAction("Connect", "Slack")); } var tokenSet = new StravaTokenSet { AccessToken = await HttpContext.GetTokenAsync("access_token"), RefreshToken = await HttpContext.GetTokenAsync("refresh_token"), ExpiresAt = DateTime.Parse(await HttpContext.GetTokenAsync("expires_at")) }; if (!string.IsNullOrWhiteSpace(tokenSet.AccessToken) && User.Identity is ClaimsIdentity claimsIdentity) { var athleteIdentifier = int.Parse(claimsIdentity.FindFirst(AthleteIdentifier).Value); var athleteName = $"{claimsIdentity.FindFirst(FirstName).Value} {claimsIdentity.FindFirst(LastName).Value}"; var athleteViewModel = await _stravaService.GetOrCreateAthlete(tokenSet, slackUserId, athleteIdentifier, athleteName); athleteViewModel.StravaJoinDate = DateTime.Parse(claimsIdentity.FindFirst(StravaJoinDate).Value); athleteViewModel.SlackChannelUrl = $"{_slackSettings.SlackWorkspaceUrl}{_slackSettings.SlackChannelId}"; return(View(athleteViewModel)); } } } catch (Exception e) { var error = $"I'm sorry you had to see this. Could you send it to Russ please? {Environment.NewLine} {e.Message} - {e.StackTrace}"; return(View(new AthleteViewModel { Error = error })); } return(View()); }
public async Task <AthleteViewModel> GetOrCreateAthlete(StravaTokenSet tokenSet, string slackUserId, int athleteIdentifier, string name) { var existingAthlete = await _athleteRepository.GetAthlete(athleteIdentifier); if (existingAthlete == null) { tokenSet = await EnsureValidTokens(tokenSet, athleteIdentifier); return(await CreateAthlete(tokenSet, slackUserId, athleteIdentifier, name)); } else { tokenSet = await EnsureValidTokens(tokenSet, athleteIdentifier); return(await GetAthlete(tokenSet, slackUserId, athleteIdentifier, name)); } }
private async Task <T> SendStravaRequest <T>(HttpRequestMessage request, StravaTokenSet tokenSet, int athleteIdentifier) { tokenSet = await EnsureValidTokens(tokenSet, athleteIdentifier); var result = default(T); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", tokenSet.AccessToken); _logger.LogInformation($"Sending Strava request: {request.RequestUri}"); var response = await _client.SendAsync(request); if (response.IsSuccessStatusCode) { _logger.LogInformation("Strava request successful."); var responseString = await response.Content.ReadAsStringAsync(); result = JsonConvert.DeserializeObject <T>(responseString); } return(result); }
private async Task <AthleteViewModel> BuildAthleteViewModel(StravaTokenSet tokenSet, string slackUserId, int athleteIdentifier, string name) { var activities = await GetRecentActivities(tokenSet, athleteIdentifier); var latestActivity = activities.FirstOrDefault(); var athlete = new AthleteViewModel { Id = athleteIdentifier, Name = name, AccessToken = tokenSet.AccessToken, RefreshToken = tokenSet.RefreshToken, ExpiresAt = tokenSet.ExpiresAt, SlackUserId = slackUserId, SignupDateTimeUtc = DateTime.UtcNow, ReminderCount = 0, LastReminderDateTimeUtc = DateTime.UtcNow, LatestActivityId = latestActivity?.Id, Activities = activities }; return(athlete); }
public async Task Run() { _logger.LogInformation("Daemon task starting."); try { var athletes = await _athleteRepository.GetAthletes(); _logger.LogInformation($"Athletes: {JsonConvert.SerializeObject(athletes)}"); Exception exception = null; foreach (var athlete in athletes) { try { _logger.LogInformation($"Checking {athlete.Name} now."); var tokenSet = new StravaTokenSet(athlete.AccessToken, athlete.RefreshToken, athlete.ExpiresAt); var activities = await _stravaService.GetRecentActivities(tokenSet, athlete.Id); _logger.LogInformation($"Athlete: {JsonConvert.SerializeObject(athlete)}"); _logger.LogInformation($"Activities: {JsonConvert.SerializeObject(activities)}"); if (activities.Any()) { await CheckForNewActivity(athlete, activities); } else { _logger.LogInformation($"No activities for {athlete.Name}."); } if (athlete.ReminderCount == 0) { //await CheckForWeeklyReminder(activities, athlete); } else if (athlete.ReminderCount == 1) { //await CheckForFortnightReminder(athlete); } else if (athlete.ReminderCount == 2) { //await CheckForMonthReminder(athlete); } } catch (Exception e) { _logger.LogError(e, $"Exception thrown for {athlete.Name}."); exception = e; } } if (exception != null) { throw exception; } } catch (Exception e) { _logger.LogError(e, $"Daemon task failed: '{e.Message}'"); await Task.Delay(20000); //Wait for logs to flush } _logger.LogInformation("Daemon task ending."); }
private async Task <AthleteViewModel> GetAthlete(StravaTokenSet tokenSet, string slackUserId, int athleteIdentifier, string name) { var athlete = await BuildAthleteViewModel(tokenSet, slackUserId, athleteIdentifier, name); return(athlete); }