/// <inheritdoc /> public async Task <Error> AddAsync( string userId, BusPrediction prediction, CancellationToken cancellationToken = default ) { prediction.User = new MongoDBRef("users", userId); Error error; try { await _collection.InsertOneAsync(prediction, cancellationToken : cancellationToken) .ConfigureAwait(false); error = null; } catch (MongoWriteException e) when(e.WriteError.Category == ServerErrorCategory.DuplicateKey && e.WriteError.Message.Contains($" index: ") ) { string index = Regex.Match(e.WriteError.Message, @" index: (\w+) ", RegexOptions.IgnoreCase).Value; error = new Error("data.duplicate_key", $@"Duplicate key ""{index}"""); } return(error); }
/// <inheritdoc /> public async Task <BusPrediction> GetByIdAsync( string id, CancellationToken cancellationToken = default ) { var filter = Filter.Eq("_id", ObjectId.Parse(id)); BusPrediction busPrediction = await _collection .Find(filter) .SingleOrDefaultAsync(cancellationToken) .ConfigureAwait(false); return(busPrediction); }
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); // } }