/// <inheritdoc /> public async Task <object> UpdateDirectionsForRouteAsync( string agencyTag, string routeTag, CancellationToken cancellationToken = default ) { var nextbusRouteConfig = await GetNextBusPolicy() .ExecuteAsync(_ => _nextbusClient.GetRouteConfig(agencyTag, routeTag), cancellationToken) .ConfigureAwait(false); var mongoRoute = await _routeRepo.GetByTagAsync(agencyTag, routeTag, cancellationToken) .ConfigureAwait(false); var directions = new List <RouteDirection>(nextbusRouteConfig.Directions.Length); foreach (var nextbusDirection in nextbusRouteConfig.Directions) { var mongoDirection = Converter.FromNextBusDirection(nextbusDirection); // todo persist its bus stops await AddNewBusStopsAsync(agencyTag, routeTag, nextbusRouteConfig.Stops, cancellationToken) .ConfigureAwait(false); // todo add its directions with refs to the bus stops directions.Add(mongoDirection); } mongoRoute.Directions = directions.ToArray(); await _routeRepo.UpdateAsync(mongoRoute, cancellationToken) .ConfigureAwait(false); return(null); }
public async Task <(float Longitude, float Latitude, string Tag, string Title)> FindClosestBusStopAsync( string agencyTag, string routeTag, string directionTag, double longitude, double latitude, CancellationToken cancellationToken ) { var route = await _routeRepo.GetByTagAsync(agencyTag, routeTag, cancellationToken) .ConfigureAwait(false); var direction = route.Directions.Single(d => d.Tag == directionTag); var busStop = await _busStopRepo .FindClosestToLocationAsync(longitude, latitude, direction.Stops, cancellationToken) .ConfigureAwait(false); return( (float)busStop.Location.Coordinates.X, (float)busStop.Location.Coordinates.Y, busStop.Tag, busStop.Title ); }
public async Task HandleAsync(IUpdateContext context, UpdateDelegate next, CancellationToken cancellationToken) { var match = Regex.Match(context.Update.CallbackQuery.Data, "^bus/r:(?<route>.+)/d:(?<direction>.+)$"); if (match.Success) { string routeTag = match.Groups["route"].Value; string directionName = match.Groups["direction"].Value; string directionTag; { _logger.LogTrace("Getting direction tag from the direction name."); var userProfile = (UserProfile)context.Items[nameof(UserProfile)]; // ToDo this query might be from a different(previously selected) agency tag var route = await _routeRepo .GetByTagAsync(userProfile.DefaultAgencyTag, routeTag, cancellationToken) .ConfigureAwait(false); directionTag = route.Directions.First(d => d.Name == directionName).Tag; } BusPredictionsContext busContext; { _logger.LogTrace("Updating the route and direction tags in the cache for this userchat"); var userchat = context.Update.ToUserchat(); busContext = await _cache.GetBusPredictionAsync(userchat, cancellationToken) .ConfigureAwait(false); busContext = busContext ?? new BusPredictionsContext(); busContext.RouteTag = routeTag; busContext.DirectionTag = directionTag; busContext.Interfaces = busContext.Interfaces ?? new List <string>(); busContext.Interfaces.Add("callback_query"); await _cache.SetBusPredictionAsync(userchat, busContext, cancellationToken) .ConfigureAwait(false); } await context.Bot.Client.MakeRequestAsync( new EditMessageTextRequest( context.Update.CallbackQuery.Message.Chat, context.Update.CallbackQuery.Message.MessageId, context.Update.CallbackQuery.Message.Text + "\n" + directionName ), cancellationToken ).ConfigureAwait(false); context.Items[nameof(BusPredictionsContext)] = busContext; await next(context, cancellationToken).ConfigureAwait(false); } context.Items[nameof(WebhookResponse)] = new AnswerCallbackQueryRequest(context.Update.CallbackQuery.Id); }
public async Task HandleAsync(IUpdateContext context, UpdateDelegate next, CancellationToken cancellationToken) { var userchat = context.Update.ToUserchat(); var cachedCtx = await GetCachedContextsAsync(context, userchat, cancellationToken) .ConfigureAwait(false); if (cachedCtx.Bus != null && cachedCtx.Location != null) { _logger.LogTrace("Bus route and location is provided. Sending bus predictions."); var busStop = await _predictionsService.FindClosestBusStopAsync( cachedCtx.Profile.DefaultAgencyTag, cachedCtx.Bus.RouteTag, cachedCtx.Bus.DirectionTag, cachedCtx.Location.Longitude, cachedCtx.Location.Latitude, cancellationToken ).ConfigureAwait(false); var predictions = await _predictionsService.GetPredictionsAsync( cachedCtx.Profile.DefaultAgencyTag, cachedCtx.Bus.RouteTag, busStop.Tag, cancellationToken ).ConfigureAwait(false); IReplyMarkup locationReplyMarkup; if (string.IsNullOrWhiteSpace(cachedCtx.Bus.Origin)) { locationReplyMarkup = new ReplyKeyboardRemove(); } else { locationReplyMarkup = new InlineKeyboardMarkup( InlineKeyboardButton.WithCallbackData("🚩 Remember this location", "loc/save") ); } await context.Bot.Client.MakeRequestWithRetryAsync( new SendLocationRequest(userchat.ChatId, busStop.Latitude, busStop.Longitude) { ReplyToMessageId = cachedCtx.Location.LocationMessageId, ReplyMarkup = locationReplyMarkup, }, cancellationToken ).ConfigureAwait(false); string text = "👆 That's the nearest bus stop"; if (!string.IsNullOrWhiteSpace(busStop.Title)) { text += $", *{busStop.Title}*"; } text += " 🚏."; string message = RouteMessageFormatter.FormatBusPredictionsReplyText(predictions.Predictions); text += "\n\n" + message; var predictionsMessage = await context.Bot.Client.MakeRequestWithRetryAsync( new SendMessageRequest(userchat.ChatId, text) { ParseMode = ParseMode.Markdown, ReplyMarkup = (InlineKeyboardMarkup)InlineKeyboardButton.WithCallbackData("Update", "pred/"), }, cancellationToken ).ConfigureAwait(false); var prediction = new BusPrediction { AgencyTag = cachedCtx.Profile.DefaultAgencyTag, RouteTag = cachedCtx.Bus.RouteTag, DirectionTag = cachedCtx.Bus.DirectionTag, BusStopTag = busStop.Tag, Origin = cachedCtx.Bus.Origin, UserLocation = new GeoJsonPoint <GeoJson2DCoordinates>( new GeoJson2DCoordinates(cachedCtx.Location.Longitude, cachedCtx.Location.Latitude)), }; await _predictionRepo.AddAsync(cachedCtx.Profile.Id, prediction, cancellationToken) .ConfigureAwait(false); await context.Bot.Client.MakeRequestWithRetryAsync( new EditMessageReplyMarkupRequest( predictionsMessage.Chat, predictionsMessage.MessageId, InlineKeyboardButton.WithCallbackData("Update", $"pred/id:{prediction.Id}") ), cancellationToken ).ConfigureAwait(false); } else if (cachedCtx.Bus != null) { _logger.LogTrace("Location is missing. Asking user to send his location."); var route = await _routeRepo.GetByTagAsync( cachedCtx.Profile.DefaultAgencyTag, cachedCtx.Bus.RouteTag, cancellationToken ).ConfigureAwait(false); var direction = route.Directions.Single(d => d.Tag == cachedCtx.Bus.DirectionTag); string text = _routeMessageFormatter.GetMessageTextForRouteDirection(route, direction); text += "\n\n*Send your current location* so I can find you the nearest bus stop 🚏 " + "and get the bus predictions for it."; int replyToMessage = context.Update.Message?.MessageId ?? context.Update.CallbackQuery?.Message?.MessageId ?? 0; await context.Bot.Client.MakeRequestWithRetryAsync( new SendMessageRequest(userchat.ChatId, text) { ParseMode = ParseMode.Markdown, ReplyToMessageId = replyToMessage, ReplyMarkup = new ReplyKeyboardMarkup(new[] { KeyboardButton.WithRequestLocation("Share my location") }, true, true) }, cancellationToken ).ConfigureAwait(false); } else if (cachedCtx.Location != null) { _logger.LogTrace("Bus route and direction are missing. Asking user to provide them."); await context.Bot.Client.MakeRequestWithRetryAsync( new SendMessageRequest( userchat.ChatId, "There you are! What's the bus you want to catch?\n" + "Send me using 👉 /bus command." ) { ReplyToMessageId = context.Update.Message.MessageId, ReplyMarkup = new ReplyKeyboardRemove() }, cancellationToken ).ConfigureAwait(false); } // ToDo: Remove keyboard if that was set in /bus command // // var userchat = context.Update.ToUserchat(); // // if (context.Update.Message?.Location != null) // { // await HandleLocationUpdateAsync( // context.Bot, // userchat, // context.Update.Message.Location, // context.Update.Message.MessageId, // cancellationToken // ).ConfigureAwait(false); // } // else if (context.Update.Message?.Text != null) // { // _logger.LogTrace("Checking if this text message has location coordinates."); // // var result = _locationService.TryParseLocation(context.Update.Message.Text); // if (result.Successful) // { // _logger.LogTrace("Location is shared from text"); // await HandleLocationUpdateAsync( // context.Bot, // userchat, // new Location { Latitude = result.Lat, Longitude = result.Lon }, // context.Update.Message.MessageId, // cancellationToken // ).ConfigureAwait(false); // } // else // { // _logger.LogTrace("Message text does not have a location. Ignoring the update."); // } // } // // var locationTuple = _locationsManager.TryParseLocation(context.Update); // // if (locationTuple.Successful) // { // _locationsManager.AddLocationToCache(userchat, locationTuple.Location); // // await _predictionsManager // .TryReplyWithPredictionsAsync(context.Bot, userchat, context.Update.Message.MessageId) // .ConfigureAwait(false); // } // else // { // // todo : if saved location available, offer it as keyboard // await context.Bot.Client.SendTextMessageAsync( // context.Update.Message.Chat.Id, // "_Invalid location!_", // ParseMode.Markdown, // replyToMessageId: context.Update.Message.MessageId // ).ConfigureAwait(false); // } }