public Result <string> RefreshUser(long loginId, string refreshKey) { var login = _db.Logins.Include(x => x.User).SingleOrDefault(x => x.Id == loginId); if (login is null) { _logger.LogWarning($"Attempted to refresh missing login id {loginId}"); return(Result.Failure <string>("Invalid login id")); } if (login.RefreshKey != refreshKey) { _logger.LogWarning($"Attempted to refresh login id {loginId} with invalid refresh key"); return(Result.Failure <string>("Invalid refresh key")); } // mark entity as modified so the modified date will get updated _db.Entry(login).State = EntityState.Modified; _db.SaveChanges(); var accessKey = GenerateAccessToken(login.User, loginId); return(Result.Success(accessKey)); }
public async Task <Result <ActivityDetails, TurnError> > TakeTurnAsync(DateTimeOffset activityModifiedDate, int activityId, int byUserId, int forUserId, DateTimeOffset when) { try { var now = DateTimeOffset.Now; _db.Turns.Add(new Turn { ActivityId = activityId, CreatorId = byUserId, UserId = forUserId, Occurred = when }); var activity = GetActivity(activityId, false, true); if (activity == null) { _logger.LogError($"Activity {activityId} is missing"); return(Result.Failure <ActivityDetails, TurnError>(TurnError.ActivityMissing)); } if (_appSettings.Value.ValidateActivityModifiedDate && activity.ModifiedDate != activityModifiedDate) { _logger.LogWarning($"Activity {activity.Id} was modified {activity.ModifiedDate} and doesn't match {activityModifiedDate}"); return(Result.Failure <ActivityDetails, TurnError>(TurnError.ActivityModified)); } var details = ActivityDetails.Calculate(activity, byUserId, _mapper); var turnTaker = await _db.Users.FindAsync(forUserId); FormattableString fs = $"{turnTaker.DisplayName} took a turn."; var myTurnBuilder = new StringBuilder().AppendFormattable(fs); var otherTurnBuilder = new StringBuilder().AppendFormattable(fs); if (details.CurrentTurnUserId.HasValue) { otherTurnBuilder.AppendFormattable($" It's {details.CurrentTurnUserDisplayName}'s turn."); myTurnBuilder.AppendFormattable($" It's your turn."); } if (details.Due.HasValue) { fs = $" Due in {(details.Due.Value - now).ToDisplayString()}."; otherTurnBuilder.AppendFormattable(fs); myTurnBuilder.AppendFormattable(fs); } var myTurnMessage = myTurnBuilder.ToString(); var otherTurnMessage = otherTurnBuilder.ToString(); var url = $"{_appSettings.Value.PushNotifications.ServerUrl}/activity/{activityId}"; var failures = new List <PushFailure>(); foreach (var participant in activity.Participants) { var pushNotified = false; foreach (var setting in participant.NotificationSettings.OrderBy(x => x.Type)) { switch (setting.Type) { case NotificationType.OverdueAnybody: case NotificationType.OverdueMine: setting.NextCheck = now; // send a close push notification in case they still have a previous notification open but not if they // already got a notification about a turn being taken because that will replace any existing notification if (setting.Push && !pushNotified) { failures.AddRange(await _pushNotificationService.SendCloseToAllDevicesAsync("turn", setting.Participant.UserId, activityId.ToString())); pushNotified = true; } break; case NotificationType.TurnTakenAnybody: if (setting.Push) { failures.AddRange(await _pushNotificationService.SendToAllDevicesAsync("turn", setting.Participant.UserId, activity.Name, otherTurnMessage, url, activityId.ToString())); pushNotified = true; } break; case NotificationType.TurnTakenMine: if (details.CurrentTurnUserId.HasValue && setting.Push && setting.Participant.UserId == details.CurrentTurnUserId) { failures.AddRange(await _pushNotificationService.SendToAllDevicesAsync("turn", setting.Participant.UserId, activity.Name, myTurnMessage, url, activityId.ToString())); pushNotified = true; } break; default: _logger.LogError($"Unhandled notification type {setting.Type}"); break; } } } // Ensure we are done sending each push message before cleaning up failures and continuing await _pushNotificationService.CleanupFailuresAsync(failures); // Always mark the activity as modified when taking a turn so our checks elsewhere that compare // the modified timestamp will still work for activities that wouldn't normally have anything update, // like when they're non-periodic or the next-turn user doesn't change. _db.Entry(activity).State = EntityState.Modified; await _db.SaveChangesAsync(); details.Update(activity); return(Result.Success <ActivityDetails, TurnError>(details)); } catch (Exception e) { _logger.LogError(e, "Failed to take a turn"); return(Result.Failure <ActivityDetails, TurnError>(TurnError.Exception)); } }