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());
        }
示例#4
0
        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);
        }
示例#8
0
        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);
        }