public async Task <(string, bool, string)> Handle(CallbackQuery data, object context = default, CancellationToken cancellationToken = default) { var callback = data.Data.Split(':'); if (callback[0] != "adjust") { return(null, false, null); } if (!PollEx.TryGetPollId(callback.ElementAtOrDefault(1), out var pollId, out var format)) { return("Poll is publishing. Try later.", true, null); } if (!int.TryParse(callback.ElementAtOrDefault(2) ?? "", NumberStyles.Integer, CultureInfo.InvariantCulture, out var offset)) { return("", false, null); } var poll = (await myRaidService.GetOrCreatePollAndMessage(new PollMessage(data) { PollId = pollId }, myUrlHelper, format, cancellationToken))?.Poll; if (poll == null) { return("Poll is not found.", true, null); } var user = data.From; if (!await myChatInfo.CandEditPoll(poll.Owner, user.Id, cancellationToken)) { return("You can't edit the poll.", true, null); } poll.Time = poll.Time?.AddMinutes(offset); if (poll.Time > poll.Raid?.RaidBossEndTime) { return($"Raid will end in {poll.Time:t}.", true, null); } var changed = await myContext.SaveChangesAsync(cancellationToken) > 0; if (changed) { await myRaidService.UpdatePoll(poll, myUrlHelper, cancellationToken); } return($"Poll is scheduled at {poll.Time:t}.", false, null); }
public async Task <(string text, bool showAlert, string url)> Handle(CallbackQuery data, object context = default, CancellationToken cancellationToken = default) { var callback = data.Data?.Split(':'); if (callback?[0] != ID) { return(null, false, null); } var player = await myDb.Set <Player>().Get(data.From, cancellationToken); switch (callback.Skip(1).FirstOrDefault()?.ToLowerInvariant()) { case Commands.ClearIGN: if (player != null) { player.Nickname = null; await myDb.SaveChangesAsync(cancellationToken); } await myBot.EditMessageReplyMarkupAsync(data, InlineKeyboardMarkup.Empty(), cancellationToken); return("Your IGN is removed", false, null); case Commands.ClearFriendCode: if (player != null) { player.FriendCode = null; await myDb.SaveChangesAsync(cancellationToken); } await myBot.EditMessageReplyMarkupAsync(data, InlineKeyboardMarkup.Empty(), cancellationToken); return("Your Friend Code is removed", false, null); } return(null, false, null); }
public async Task <bool?> Handle(MessageEntityEx entity, PollMessage context = default, CancellationToken cancellationToken = default) { if (entity.Message.Chat.Type != ChatType.Private) { return(false); } var commandText = entity.AfterValue.Trim(); switch (entity.Command.ToString().ToLowerInvariant()) { case "/ign": case "/nick": case "/nickname": var author = entity.Message.From; var player = await myContext.Set <Player>().Where(p => p.UserId == author.Id).FirstOrDefaultAsync(cancellationToken); var nickname = commandText.ToString(); if (string.IsNullOrEmpty(nickname)) { if (player != null) { myContext.Remove(player); } } else { if (player == null) { player = new Player { UserId = author.Id }; myContext.Add(player); } player.Nickname = nickname; } await myContext.SaveChangesAsync(cancellationToken); return(true); default: return(false); } }
public async Task <bool?> Process(User user, string nickname, CancellationToken cancellationToken = default) { var player = await myContext.Set <Player>().Get(user, cancellationToken); if (!string.IsNullOrEmpty(nickname)) { if (player == null) { player = new Player { UserId = user.Id }; myContext.Add(player); } player.Nickname = nickname; await myContext.SaveChangesAsync(cancellationToken); } IReplyMarkup?replyMarkup = null; var builder = new TextBuilder(); if (!string.IsNullOrEmpty(player?.Nickname)) { builder .Append($"Your IGN is {player.Nickname:bold}") .NewLine() .NewLine(); replyMarkup = new InlineKeyboardMarkup(InlineKeyboardButton.WithCallbackData("Clear IGN", $"{PlayerCallbackQueryHandler.ID}:{PlayerCallbackQueryHandler.Commands.ClearIGN}")); } builder .Append($"To set up your in-game-name reply with it to this message.").NewLine() .Append($"Or use /{COMMAND} command.").NewLine() .Code("/ign your-in-game-name"); await myBot.SendTextMessageAsync(user.Id, builder.ToTextMessageContent(), cancellationToken : cancellationToken, replyMarkup : replyMarkup ?? new ForceReplyMarkup { InputFieldPlaceholder = "in-game-name" }); return(false); // processed, but not pollMessage }
public async Task ApproveFriendship(User host, User user, CancellationToken cancellationToken = default) { var friendshipDB = myDB.Set <Friendship>(); Expression <Func <Friendship, bool> > findFriendPredicate = friendship => friendship.Id == host.Id && friendship.FriendId == user.Id || friendship.Id == user.Id && friendship.FriendId == host.Id; var friendship = friendshipDB.Local.SingleOrDefault(findFriendPredicate.Compile()) ?? await friendshipDB.FirstOrDefaultAsync(findFriendPredicate, cancellationToken); if (friendship == null) { friendship = new Friendship { Id = host.Id, FriendId = user.Id }; friendshipDB.Add(friendship); } friendship.Type = FriendshipType.Approved; await myDB.SaveChangesAsync(cancellationToken); }
public async Task <(string, bool, string)> Handle(CallbackQuery data, object context = default, CancellationToken cancellationToken = default) { var callback = data.Data.Split(':'); if (callback[0] != "cancel") { return(null, false, null); } if (!PollEx.TryGetPollId(callback.ElementAtOrDefault(1), out var pollId, out var format)) { return("Poll is publishing. Try later.", true, null); } var poll = (await myRaidService.GetOrCreatePollAndMessage(new PollMessage(data) { PollId = pollId }, myUrlHelper, format, cancellationToken))?.Poll; if (poll == null) { return("Poll is not found.", true, null); } var user = data.From; if (!await myChatInfo.CandEditPoll(poll.Owner, user.Id, cancellationToken)) { return("You can't cancel the poll.", true, null); } poll.Cancelled = true; var changed = await myContext.SaveChangesAsync(cancellationToken) > 0; if (changed) { await myRaidService.UpdatePoll(poll, myUrlHelper, cancellationToken); } return(changed ? "Poll is canceled." : "Poll is already canceled.", false, null); }
public async Task <bool?> Handle(ChosenInlineResult data, object context = default, CancellationToken cancellationToken = default) { var resultParts = data.ResultId.Split(':'); switch (resultParts[0]) { case PREFIX: if (myTimeZoneNotifyService.DecodeId(resultParts.Skip(1).FirstOrDefault(), out var chatId, out var messageId) && resultParts.Skip(2).FirstOrDefault() is {} timeZoneId&& myDateTimeZoneProvider.GetZoneOrNull(timeZoneId) is {}) { if (!await CheckRights(chatId, data.From, cancellationToken)) { await myBot.EditMessageTextAsync(data.InlineMessageId !, new InputTextMessageContent("You have no rights"), cancellationToken : cancellationToken); return(false); } var settings = myDB.Set <TimeZoneSettings>(); if (await EntityFrameworkQueryableExtensions.FirstOrDefaultAsync(settings.Where(s => s.ChatId == chatId && s.TimeZone == timeZoneId), cancellationToken) == null) { settings.Add(new TimeZoneSettings { ChatId = chatId, TimeZone = timeZoneId }); await myDB.SaveChangesAsync(cancellationToken); } var(content, replyMarkup) = await myTimeZoneNotifyService.GetSettingsMessage(new Chat { Id = chatId, Type = ChatType.Sender }, cancellationToken : cancellationToken); await myBot.EditMessageTextAsync(data.InlineMessageId !, content, replyMarkup, cancellationToken); if (messageId != 0) { await myBot.DeleteMessageAsync(chatId, messageId, cancellationToken); } return(true); } break; }
public async Task <(string text, bool showAlert, string url)> Handle(CallbackQuery data, object context = default, CancellationToken cancellationToken = default) { var callback = data.Data.Split(':'); if (callback[0] != ID) { return(null, false, null); } if (!PollEx.TryGetPollId(callback.ElementAtOrDefault(1), out var pollId, out var format)) { return("Poll is publishing. Try later.", true, null); } if (!Enum.TryParse <PollMode>(callback.ElementAtOrDefault(2) ?? "", out var pollMode)) { return("", false, null); } var pollMessage = await myRaidService.GetOrCreatePollAndMessage(new PollMessage(data) { BotId = myBot.BotId, PollId = pollId }, myUrlHelper, format, cancellationToken); if (pollMessage.Poll == null) { return("Poll is not found.", true, null); } pollMessage.PollMode = pollMode; var changed = await myDb.SaveChangesAsync(cancellationToken) > 0; if (changed) { await myRaidService.UpdatePollMessage(pollMessage, myUrlHelper, cancellationToken); return("Mode have been switched", false, null); } return(null, false, null); }
public async Task <PollMessage> AddPollMessage([CanBeNull] PollMessage message, IUrlHelper urlHelper, CancellationToken cancellationToken = default, bool withLog = false) { if (message?.Poll == null) { return(message); } message.Poll.AllowedVotes = message.Poll.AllowedVotes ?? await myContext.Set <Settings>().GetFormat(message.UserId, cancellationToken); var raidUpdated = false; var eggRaidUpdated = false; if (message.Poll?.Raid is Raid raid) { if (raid.Id == 0) { var sameRaids = myContext .Set <Raid>() .Where(_ => _.Lon == raid.Lon && _.Lat == raid.Lat); var existingRaid = await sameRaids .Where(_ => _.RaidBossLevel == raid.RaidBossLevel && _.Pokemon == raid.Pokemon && _.EndTime == raid.EndTime) .Include(_ => _.EggRaid) .IncludeRelatedData() .FirstOrDefaultAsync(cancellationToken); if (existingRaid != null) { if (((existingRaid.Gym ?? existingRaid.PossibleGym) == null) && ((raid.Gym ?? raid.PossibleGym) != null)) { existingRaid.PossibleGym = raid.Gym ?? raid.PossibleGym; raidUpdated = true; } if (string.IsNullOrEmpty(message.Poll.Title)) { // use existing poll if have rights for any prev message foreach (var existingRaidPoll in existingRaid.Polls) { foreach (var existingRaidPollMessage in existingRaidPoll.Messages) { if (await myChatInfo.CanReadPoll(existingRaidPollMessage.ChatId ?? existingRaidPollMessage.Poll.Owner, message.UserId ?? message.ChatId, cancellationToken)) { if ((existingRaidPoll.Votes?.Count ?? 0) >= (message.Poll.Messages?.Count ?? 0)) { message.Poll = existingRaidPoll; break; } } } if (message.Poll == existingRaidPoll) { break; } } } raid = message.Poll.Raid = existingRaid; } if ((raid.Pokemon != null) && (raid.EggRaid == null)) // check for egg raid { var eggRaid = await sameRaids .Where(_ => _.Pokemon == null && _.RaidBossEndTime == raid.RaidBossEndTime) .IncludeRelatedData() .DecompileAsync() .FirstOrDefaultAsync(cancellationToken); if ((eggRaid != null) && (raid.Id != eggRaid.Id)) { var eggRaidPolls = eggRaid.Polls = eggRaid.Polls ?? new List <Poll>(0); var raidPolls = raid.Polls = raid.Polls ?? new List <Poll>(eggRaidPolls.Count); // on post egg raid creation update all existing polls to new raid foreach (var eggRaidPoll in new List <Poll>(eggRaidPolls)) { eggRaidPolls.Remove(eggRaidPoll); raidPolls.Add(eggRaidPoll); eggRaidPoll.Raid = raid; raidUpdated = true; if (!string.IsNullOrEmpty(message.Poll.Title)) { continue; } // use existing poll if have rights for any prev message foreach (var eggRaidPollMessage in eggRaidPoll.Messages) { if (await myChatInfo.CanReadPoll(eggRaidPollMessage.ChatId ?? eggRaidPollMessage.Poll.Owner, message.UserId ?? message.ChatId, cancellationToken)) { if ((eggRaidPoll.Votes?.Count ?? 0) >= (message.Poll.Messages?.Count ?? 0)) { message.Poll = eggRaidPoll; break; } } } } message.Poll.Raid = raid; raid.EggRaid = eggRaid; eggRaidUpdated = true; } } } } var messageEntity = myContext.Set <PollMessage>().Attach(message); await myContext.SaveChangesAsync(cancellationToken); // update current raid poll messages if changed if (raidUpdated && message.Poll.Raid is Raid raidToUpdate) { foreach (var poll in raidToUpdate.Polls ?? Enumerable.Empty <Poll>()) { await UpdatePoll(poll, urlHelper, cancellationToken); } } // update egg raid poll messages if any if (eggRaidUpdated && message.Poll.Raid?.EggRaid is Raid eggRaidToUpdate) { foreach (var poll in eggRaidToUpdate.Polls ?? Enumerable.Empty <Poll>()) { await UpdatePoll(poll, urlHelper, cancellationToken); } } var content = message.Poll.GetMessageText(urlHelper, disableWebPreview: message.Poll.DisableWebPreview()); if (message.Chat is Chat chat) { var postedMessage = await myBot.SendTextMessageAsync(chat, content.MessageText, content.ParseMode, content.DisableWebPagePreview, replyMarkup : await message.GetReplyMarkup(myChatInfo, cancellationToken), disableNotification : true, cancellationToken : cancellationToken); message.Chat = postedMessage.Chat; message.MesssageId = postedMessage.MessageId; } else if (message.InlineMesssageId is string inlineMessageId) { //await myBot.EditInlineMessageTextAsync(inlineMessageId, messageText, RaidEx.ParseMode, disableWebPagePreview: message.Poll.GetRaidId() == null, // replyMarkup: await message.GetReplyMarkup(myChatInfo, cancellationToken), cancellationToken: cancellationToken); } await myContext.SaveChangesAsync(cancellationToken); // log message if (withLog && myLogChat != null) { await AddPollMessage(new PollMessage { ChatId = myLogChat, Poll = message.Poll }, urlHelper, cancellationToken); } return(message); }
public async Task <(string, bool, string)> Handle(CallbackQuery data, object context = default, CancellationToken cancellationToken = default) { var callback = data.Data.Split(':'); if (callback[0] != "set") { return(null, false, null); } if (!await myChatInfo.CandEditPoll(data.Message.Chat, data.From?.Id, cancellationToken)) { return("You can't edit the poll.", true, null); } var chatId = data.Message.Chat.Id; var settingsSet = myContext.Set <Settings>(); var allSettings = await settingsSet.GetSettings(chatId).AsTracking().ToListAsync(cancellationToken); Settings settings = null; switch (callback.ElementAtOrDefault(1)) { case "list": return(await Return(await SettingsList(chatId, cancellationToken))); case var identifier when int.TryParse(identifier, out var id): settings = allSettings.FirstOrDefault(setting => setting.Id == id); break; } if (settings == null) { // create a new settings = new Settings { Chat = chatId, Order = allSettings.Select(_ => _.Order).DefaultIfEmpty(-1).Max() + 1, Format = VoteEnum.Standard }; await settingsSet.AddAsync(settings, cancellationToken); } string message = null; switch (callback.ElementAtOrDefault(2) ?? "") { case "default": settings.Order = allSettings.Select(_ => _.Order).DefaultIfEmpty(1).Min() - 1; await myContext.SaveChangesAsync(cancellationToken); return(await Return(await SettingsList(chatId, cancellationToken), "Default poll format is changed.")); case "delete": settingsSet.Remove(settings); await myContext.SaveChangesAsync(cancellationToken); return(await Return(await SettingsList(chatId, cancellationToken), "Poll format is deleted.")); case var format when FlagEnums.TryParseFlags(format, out VoteEnum toggleVotes, EnumFormat.DecimalValue): settings.Format = FlagEnums.ToggleFlags(settings.Format, toggleVotes); // adjust ⁺¹ if (settings.Format.HasAnyFlags(VoteEnum.Plus) && !settings.Format.HasAnyFlags(VoteEnum.Countable)) { settings.Format = settings.Format.RemoveFlags(VoteEnum.Plus); } if (await myContext.SaveChangesAsync(cancellationToken) > 0) { message = "Poll format is changed."; } goto default; default: var buttons = new [] { VoteEnum.Team, VoteEnum.TeamHarmony, VoteEnum.Plus1, VoteEnum.Remotely, VoteEnum.Invitation, VoteEnum.MayBe, VoteEnum.Yes, VoteEnum.Thumbs, VoteEnum.HarryPotter, VoteEnum.Cancel, VoteEnum.Share } .Select(format => new [] { InlineKeyboardButton.WithCallbackData($"{(settings.Format.HasAllFlags(format) ? '☑' : '☐')} {format.Format(new StringBuilder())}", $"{ID}:{settings.Id}:{format:D}") }); if (allSettings.FirstOrDefault() is Settings existingDefault && existingDefault != settings) { buttons = buttons.Append(new[] { InlineKeyboardButton.WithCallbackData("Make as a default", $"{ID}:{settings.Id}:default") }); } buttons = buttons .Append(new [] { InlineKeyboardButton.WithCallbackData("Delete", $"{ID}:{settings.Id}:delete") }) .Append(new [] { InlineKeyboardButton.WithCallbackData("Back", $"{ID}:list") }); return(await Return(( settings.Format.Format(new StringBuilder("Selected poll format:").AppendLine()).ToTextMessageContent(), new InlineKeyboardMarkup(buttons)), message)); } async Task <(string, bool, string)> Return((InputTextMessageContent content, InlineKeyboardMarkup replyMarkup) pass, string notification = "") { await myTelegramBotClient.EditMessageTextAsync(data.Message.Chat, data.Message.MessageId, pass.content.MessageText, pass.content.ParseMode, pass.content.DisableWebPagePreview, pass.replyMarkup, cancellationToken); return(notification, false, null); } }
public async Task <bool?> Handle(InlineQuery data, object context = default, CancellationToken cancellationToken = default) { var location = data.Location; var queryParts = data.Query.Split(' ', StringSplitOptions.RemoveEmptyEntries); var poll = default(Poll); var pollQuery = new List <string>(queryParts.Length); var searchQuery = new List <string>(queryParts.Length); var query = pollQuery; foreach (var queryPart in queryParts) { switch (queryPart) { case string locationPart when OpenLocationCode.IsValid(locationPart): location = OpenLocationCode.Decode(locationPart) is var code ? new Location { Longitude = (float)code.CenterLongitude, Latitude = (float)code.CenterLatitude } : location; break; case string part when Regex.Match(part, PATTERN) is Match match && match.Success: if (int.TryParse(match.Groups["pollId"].Value, out var pollId)) { poll = myRaidService.GetTemporaryPoll(pollId); } query = searchQuery; break; default: query.Add(queryPart); break; } } Portal[] portals; if (searchQuery.Count == 0) { portals = await myIngressClient.GetPortals(0.200, location, cancellationToken); } else { portals = await myIngressClient.Search(searchQuery, location, cancellationToken); } var results = new List <InlineQueryResultBase>(Math.Min(portals.Length, MAX_PORTALS_PER_RESPONSE) + 2); if ((poll == null) && (pollQuery.Count != 0)) { var voteFormat = await myDb.Set <Settings>().GetFormat(data.From.Id, cancellationToken); for (var i = 0; i < portals.Length && i < MAX_PORTALS_PER_RESPONSE; i++) { poll = new Poll(data) { Title = string.Join(" ", pollQuery), AllowedVotes = voteFormat, Portal = portals[i], ExRaidGym = false }; await myRaidService.GetPollId(poll, cancellationToken); results.Add(new InlineQueryResultArticle(poll.GetInlineId(), poll.GetTitle(myUrlHelper), poll.GetMessageText(myUrlHelper, disableWebPreview: poll.DisableWebPreview())) { Description = poll.AllowedVotes?.Format(new StringBuilder("Create a poll ")).ToString(), HideUrl = true, ThumbUrl = poll.GetThumbUrl(myUrlHelper).ToString(), ReplyMarkup = poll.GetReplyMarkup() }); if (i == 0) { poll.Id = -poll.Id; poll.ExRaidGym = true; results.Add(new InlineQueryResultArticle(poll.GetInlineId(), poll.GetTitle(myUrlHelper) + " (EX Raid Gym)", poll.GetMessageText(myUrlHelper, disableWebPreview: poll.DisableWebPreview())) { Description = poll.AllowedVotes?.Format(new StringBuilder("Create a poll ")).ToString(), HideUrl = true, ThumbUrl = poll.GetThumbUrl(myUrlHelper).ToString(), ReplyMarkup = poll.GetReplyMarkup() }); } } } else { for (var i = 0; i < portals.Length && i < MAX_PORTALS_PER_RESPONSE; i++) { var portal = portals[i]; var title = portal.Name is string name && !string.IsNullOrWhiteSpace(name) ? name : portal.Guid; if (portal.EncodeGuid() is string portalGuid) { InlineQueryResultArticle Init(InlineQueryResultArticle article, InlineKeyboardButton createButton) { const int thumbnailSize = 64; article.Description = portal.Address; article.ReplyMarkup = new InlineKeyboardMarkup(createButton); article.ThumbUrl = portal.GetImage(myUrlHelper, thumbnailSize)?.AbsoluteUri; article.ThumbHeight = thumbnailSize; article.ThumbWidth = thumbnailSize; return(article); } var portalContent = new StringBuilder() .Bold((builder, mode) => builder.Sanitize(portal.Name)).NewLine() .Sanitize(portal.Address) .Link("\u200B", portal.Image) .ToTextMessageContent(); results.Add(Init( new InlineQueryResultArticle($"portal:{portal.Guid}", title, portalContent), InlineKeyboardButton.WithSwitchInlineQuery("Create a poll", $"{PREFIX}{portalGuid} {poll?.Title}"))); if (i == 0) { var exRaidPortalContent = new StringBuilder() .Sanitize("☆ ") .Bold((builder, mode) => builder.Sanitize(portal.Name)) .Sanitize(" (EX Raid Gym)").NewLine() .Sanitize(portal.Address) .Link("\u200B", portal.Image) .ToTextMessageContent(); results.Add(Init( new InlineQueryResultArticle($"portal:{portal.Guid}+", $"☆ {title} (EX Raid Gym)", exRaidPortalContent), InlineKeyboardButton.WithSwitchInlineQuery("Create a poll ☆ (EX Raid Gym)", $"{PREFIX}{portalGuid}+ {poll?.Title}"))); } } } } if (searchQuery.Count == 0) { results.Add( new InlineQueryResultArticle("EnterGymName", "Enter a Gym's Title", new InputTextMessageContent("Enter a Gym's Title to search")) { Description = "to search", ThumbUrl = default(Portal).GetImage(myUrlHelper)?.AbsoluteUri }); } if (results.Count == 0) { var search = string.Join(" ", searchQuery); results.Add(new InlineQueryResultArticle("NothingFound", "Nothing found", new StringBuilder($"Nothing found by request ").Code((builder, mode) => builder.Sanitize(search, mode)).ToTextMessageContent()) { Description = $"Request {search}", ThumbUrl = myUrlHelper.AssetsContent(@"static_assets/png/btn_close_normal.png").AbsoluteUri }); } await myBot.AnswerInlineQueryWithValidationAsync(data.Id, results, cacheTime : 0, isPersonal : true, cancellationToken : cancellationToken); await myDb.SaveChangesAsync(cancellationToken); return(true); }
public async Task <(string text, bool showAlert, string url)> Handle(CallbackQuery data, object context = default, CancellationToken cancellationToken = default) { var callback = data.Data?.Split(':'); if (callback?[0] != ID) { return(null, false, null); } var host = data.From; var player = await myDB.Set <Player>().Get(host, cancellationToken); var command = callback.Skip(1).FirstOrDefault(); var commandParameter = callback.Skip(2).FirstOrDefault(); switch (command) { case Commands.SendCodeId: case Commands.AutoApproveId: case Commands.ApproveSettingsId when bool.TryParse(commandParameter, out var autoApprove) && autoApprove: if (player?.FriendCode == null) { await myFriendshipService.SetupFriendCode(myBot, host, StringSegment.Empty, cancellationToken); return("Please, specify your Friend Code first", true, null); } break; } switch (command) { case Commands.SendCodeId when long.TryParse(commandParameter, out var userId) && long.TryParse(callback.Skip(3).FirstOrDefault(), out var botId): try { if (!myBots.TryGetValue(botId, out var bot)) { bot = myBot; } await myFriendshipService.SendCode(bot, new User { Id = userId }, host, player, cancellationToken); await myBot.EditMessageReplyMarkupAsync(data, InlineKeyboardMarkup.Empty(), cancellationToken); return("Friend Code sent", false, null); } catch (ApiRequestException apiEx) when(apiEx.ErrorCode == 403) { return("User blocked personal messages for the bot.\r\nSend him/her code by yourself.", true, null); } case Commands.AskCodeId when long.TryParse(commandParameter, out var userId) && long.TryParse(callback.Skip(3).FirstOrDefault(), out var botId): try { if (!myBots.TryGetValue(botId, out var bot)) { bot = myBot; } await myFriendshipService.AskCode(host, myBot, new User { Id = userId }, bot, player, cancellationToken); await myBot.EditMessageReplyMarkupAsync(data, InlineKeyboardMarkup.Empty(), cancellationToken); return("Friend Code asked", false, null); } catch (ApiRequestException apiEx) when(apiEx.ErrorCode == 403) { return("User blocked personal messages for the bot.\r\nAsk him/her for the code by yourself.", true, null); } case Commands.ApproveId when int.TryParse(commandParameter, out var userId): await myFriendshipService.ApproveFriendship(host, new User { Id = userId }, cancellationToken); await myBot.EditMessageReplyMarkupAsync(data, InlineKeyboardMarkup.Empty(), cancellationToken); return("He/She marked as already Friend.", false, null); case Commands.AutoApproveId when int.TryParse(commandParameter, out var pollId): var poll = await myDB .Set <Poll>() .Where(_ => _.Id == pollId) .IncludeRelatedData() .FirstOrDefaultAsync(cancellationToken); if (poll == null) { return("Poll is publishing. Try later.", true, null); } var hostVote = poll.Votes.FirstOrDefault(_ => _.UserId == host.Id); if (hostVote == null) { return("Poll is publishing. Try later.", true, null); } hostVote.Team |= VoteEnum.AutoApproveFriend; // approve already awaiting requests foreach (var friendship in await myDB.Set <Friendship>() .Where(f => f.PollId == pollId && (f.Id == host.Id || f.FriendId == host.Id)).ToListAsync(cancellationToken)) { friendship.Type = FriendshipType.Approved; if (poll.Votes.SingleOrDefault(v => (v.UserId == friendship.Id || v.UserId == friendship.FriendId) && v.UserId != host.Id) is { } vote) { try { if (vote.BotId is not { } botId || !myBots.TryGetValue(botId, out var bot)) { bot = myBot; } await myFriendshipService.SendCode(bot, vote.User, host, player, cancellationToken); } catch (ApiRequestException apiEx) when(apiEx.ErrorCode == 403) { // personal messages banned for host - propose user to ask for FC manually } } } await myDB.SaveChangesAsync(cancellationToken); await myBot.EditMessageReplyMarkupAsync(data, InlineKeyboardMarkup.Empty(), cancellationToken); return($"All invitees of `{poll.Title}` will be automatically approved.", false, null); case Commands.ApproveSettingsId: if (player == null) { player = new Player { UserId = host.Id }; myDB.Add(player); } if (bool.TryParse(commandParameter, out var autoApprove)) { player.AutoApproveFriendship = autoApprove; } else { player.AutoApproveFriendship = null; } await myDB.SaveChangesAsync(cancellationToken); await myBot.EditMessageReplyMarkupAsync(data, FriendshipCommandHandler.GetInlineKeyboardMarkup(player), cancellationToken); return("Friendship settings modified", false, null); } return(null, false, null); }
public async Task <bool?> Handle(InlineQuery data, object context = default, CancellationToken cancellationToken = default) { IReadOnlyCollection <InlineQueryResultBase> inlineQueryResults; string query = null; Portal portal = null; bool exRaidGym = false; string switchPmParameter = null; foreach (var queryPart in data.Query.Split(' ', StringSplitOptions.RemoveEmptyEntries)) { switch (queryPart) { case string _ when queryPart.StartsWith(GymInlineQueryHandler.PREFIX): var guid = queryPart.Substring(GymInlineQueryHandler.PREFIX.Length); if (guid.EndsWith('+')) { guid = guid.Substring(0, guid.Length - 1); exRaidGym = true; } var portalGuid = PortalEx.DecodeGuid(guid); portal = await myIngressClient.Get(portalGuid, data.Location, cancellationToken); break; default: query += (query == null ? default(char?) : ' ') + queryPart; break; } } if (string.IsNullOrWhiteSpace(data.Query)) // check whole query for sharing branch { inlineQueryResults = await myShareInlineQueryHandler.GetActivePolls(data.From, cancellationToken); } else if (string.IsNullOrWhiteSpace(query)) { inlineQueryResults = new[] { new InlineQueryResultArticle($"EnterPollTopic", "Enter a topic", new InputTextMessageContent("Enter a topic to create a poll")) { Description = "to create a poll", ThumbUrl = myUrlHelper.AssetsContent("static_assets/png/POI_Submission_Illustration_02.png").ToString() } }; } else { var pollId = await myRaidService.GetPollId(new Poll(data) { Title = query, Portal = portal }, cancellationToken); switchPmParameter = portal == null ? $"{SwitchToGymParameter}{pollId}" : null; ICollection <VoteEnum> voteFormats = await myDb.Set <Settings>().GetFormats(data.From.Id, cancellationToken).ToListAsync(cancellationToken); if (voteFormats.Count == 0) { voteFormats = VoteEnumEx.DefaultVoteFormats; } inlineQueryResults = voteFormats .Select(format => new Poll { Id = exRaidGym ? -pollId : pollId, Title = query, AllowedVotes = format, Portal = portal, ExRaidGym = exRaidGym }) .Select((fakePoll, i) => new InlineQueryResultArticle(fakePoll.GetInlineId(i), fakePoll.GetTitle(myUrlHelper), fakePoll.GetMessageText(myUrlHelper, disableWebPreview: fakePoll.DisableWebPreview())) { Description = fakePoll.AllowedVotes?.Format(new StringBuilder("Create a poll ")).ToString(), HideUrl = true, ThumbUrl = fakePoll.GetThumbUrl(myUrlHelper).ToString(), ReplyMarkup = fakePoll.GetReplyMarkup() }) .ToArray(); } await myBot.AnswerInlineQueryWithValidationAsync(data.Id, inlineQueryResults, switchPmText : switchPmParameter != null? "Link the poll to a gym" : null, switchPmParameter : switchPmParameter, cacheTime : 0, cancellationToken : cancellationToken); await myDb.SaveChangesAsync(cancellationToken); return(true); }
public async Task <bool?> Handle(InlineQuery data, object context = default, CancellationToken cancellationToken = default) { var location = await myDb.Set <UserSettings>().GetLocation(data, cancellationToken); var queryParts = data.Query.Split(' ', StringSplitOptions.RemoveEmptyEntries); var poll = default(Poll); List <VoteLimit> limits = default; var pollQuery = new List <string>(queryParts.Length); var searchQuery = new List <string>(queryParts.Length); var query = pollQuery; foreach (var queryPart in queryParts) { switch (queryPart) { case { } locationPart when OpenLocationCode.IsValid(locationPart): location = OpenLocationCode.Decode(locationPart) is var code ? new Location { Longitude = (float)code.CenterLongitude, Latitude = (float)code.CenterLatitude } : location; break; case { } part when Regex.Match(part, PATTERN) is { Success: true } match: if (int.TryParse(match.Groups["pollId"].ValueSpan, out var pollId)) { poll = myRaidService .GetTemporaryPoll(pollId) .InitImplicitVotes(data.From, myBot.BotId); } query = searchQuery; break; case { } part when myGeneralInlineQueryHandler.ProcessLimitQueryString(ref limits, part): break; default: query.Add(queryPart); break; } } Portal[] portals; if (searchQuery.Count == 0) { portals = await myIngressClient.GetPortals(0.200, location, cancellationToken); } else { portals = await myIngressClient.Search(searchQuery, location, near : true, cancellationToken); } var results = new List <InlineQueryResult>(Math.Min(portals.Length, MAX_PORTALS_PER_RESPONSE) + 2); if (poll == null && pollQuery.Count != 0) { var voteFormat = await myDb.Set <Settings>().GetFormat(data.From.Id, cancellationToken); poll = await new Poll(data) { Title = string.Join(" ", pollQuery), AllowedVotes = voteFormat, ExRaidGym = false, Limits = limits }.DetectRaidTime(myTimeZoneService, () => Task.FromResult(location), async ct => myClock.GetCurrentInstant().InZone(await myGeoCoder.GetTimeZone(data, ct)), cancellationToken); for (var i = 0; i < portals.Length && i < MAX_PORTALS_PER_RESPONSE; i++) { var portalPoll = new Poll(poll) { Portal = portals[i], Limits = poll.Limits ?? limits }.InitImplicitVotes(data.From, myBot.BotId); await myRaidService.GetPollId(portalPoll, data.From, cancellationToken); results.Add(myGeneralInlineQueryHandler.GetInlineResult(portalPoll)); if (i == 0) { portalPoll.Id = -portalPoll.Id; portalPoll.ExRaidGym = true; results.Add(myGeneralInlineQueryHandler.GetInlineResult(portalPoll)); } } } else { for (var i = 0; i < portals.Length && i < MAX_PORTALS_PER_RESPONSE; i++) { var portal = portals[i]; var title = portal.Name is { } name&& !string.IsNullOrWhiteSpace(name) ? name : portal.Guid; if (portal.EncodeGuid() is { } portalGuid) { InlineQueryResultArticle Init(InlineQueryResultArticle article, InlineKeyboardButton createButton) { const int thumbnailSize = 64; article.Description = portal.Address; article.ReplyMarkup = new InlineKeyboardMarkup(createButton); article.ThumbUrl = portal.GetImage(myUrlHelper, thumbnailSize)?.AbsoluteUri; article.ThumbHeight = thumbnailSize; article.ThumbWidth = thumbnailSize; return(article); } var portalContent = new TextBuilder() .Bold(builder => builder.Sanitize(portal.Name)).NewLine() .Sanitize(portal.Address) .Link("\u200B", portal.Image) .ToTextMessageContent(); results.Add(Init( new InlineQueryResultArticle($"portal:{portal.Guid}", title, portalContent), InlineKeyboardButton.WithSwitchInlineQuery("Create a poll", $"{PREFIX}{portalGuid} {poll?.Title}"))); if (i == 0) { var exRaidPortalContent = new TextBuilder() .Sanitize("☆ ") .Bold(builder => builder.Sanitize(portal.Name)) .Sanitize(" (EX Raid Gym)").NewLine() .Sanitize(portal.Address) .Link("\u200B", portal.Image) .ToTextMessageContent(); results.Add(Init( new InlineQueryResultArticle($"portal:{portal.Guid}+", $"☆ {title} (EX Raid Gym)", exRaidPortalContent), InlineKeyboardButton.WithSwitchInlineQuery("Create a poll ☆ (EX Raid Gym)", $"{PREFIX}{portalGuid}+ {poll?.Title}"))); } } } } if (searchQuery.Count == 0) { results.Add( new InlineQueryResultArticle("EnterGymName", "Enter a Gym's Title", new InputTextMessageContent("Enter a Gym's Title to search")) { Description = "to search", ThumbUrl = default(Portal).GetImage(myUrlHelper)?.AbsoluteUri }); } if (results.Count == 0) { var search = string.Join(" ", searchQuery); results.Add(new InlineQueryResultArticle("NothingFound", "Nothing found", new TextBuilder($"Nothing found by request ").Code(builder => builder.Sanitize(search)).ToTextMessageContent()) { Description = $"Request {search}", ThumbUrl = myUrlHelper.AssetsContent(@"static_assets/png/btn_close_normal.png").AbsoluteUri }); } await myBot.AnswerInlineQueryWithValidationAsync(data.Id, results, cacheTime : 0, isPersonal : true, cancellationToken : cancellationToken); await myDb.SaveChangesAsync(cancellationToken); return(true); }
public async Task <bool?> Handle(InlineQuery data, object context = default, CancellationToken cancellationToken = default) { IReadOnlyCollection <InlineQueryResult> inlineQueryResults; Task <Location> location = null; async Task <Location> GetLocation() => await(location ??= myDb.Set <UserSettings>().GetLocation(data, cancellationToken)); string query = null; Portal portal = null; bool exRaidGym = false; string switchPmParameter = null; List <VoteLimit> limits = default; foreach (var queryPart in data.Query.Split(' ', StringSplitOptions.RemoveEmptyEntries)) { switch (queryPart) { case { } when queryPart.StartsWith(GymInlineQueryHandler.PREFIX): var guid = queryPart.Substring(GymInlineQueryHandler.PREFIX.Length); if (guid.EndsWith('+')) { guid = guid.Substring(0, guid.Length - 1); exRaidGym = true; } var portalGuid = PortalEx.DecodeGuid(guid); portal = await myIngressClient.Get(portalGuid, await GetLocation(), cancellationToken); break; case { } when ProcessLimitQueryString(ref limits, queryPart): break; default: query += (query == null ? default(char?) : ' ') + queryPart; break; } } if (string.IsNullOrWhiteSpace(data.Query)) // check whole query for sharing branch { inlineQueryResults = await myShareInlineQueryHandler.GetActivePolls(data.From, cancellationToken); } else if (string.IsNullOrWhiteSpace(query)) { inlineQueryResults = new[] { new InlineQueryResultArticle($"EnterPollTopic", "Enter a topic", new InputTextMessageContent("Enter a topic to create a poll")) { Description = "to create a poll", ThumbUrl = myUrlHelper.AssetsContent("static_assets/png/POI_Submission_Illustration_02.png").ToString() } }; } else { var poll = await new Poll(data) { Title = query, Portal = portal, Limits = limits } .DetectRaidTime(myTimeZoneService, GetLocation, async ct => myClock.GetCurrentInstant().InZone(await myGeoCoder.GetTimeZone(data, ct)), cancellationToken); var pollId = await myRaidService.GetPollId(poll, data.From, cancellationToken); switchPmParameter = portal == null ? $"{SwitchToGymParameter}{pollId}" : null; ICollection <VoteEnum> voteFormats = await myDb.Set <Settings>().GetFormats(data.From.Id).ToListAsync(cancellationToken); if (voteFormats.Count == 0) { voteFormats = VoteEnumEx.DefaultVoteFormats; } inlineQueryResults = voteFormats .Select(format => new Poll(poll) { Id = exRaidGym ? -pollId : pollId, AllowedVotes = format, ExRaidGym = exRaidGym }.InitImplicitVotes(data.From, myBot.BotId)) .Select((fakePoll, i) => GetInlineResult(fakePoll, i)) .ToArray(); } await myBot.AnswerInlineQueryWithValidationAsync(data.Id, inlineQueryResults, switchPmText : switchPmParameter != null? "Link the poll to a gym" : null, switchPmParameter : switchPmParameter, cacheTime : 0, cancellationToken : cancellationToken); await myDb.SaveChangesAsync(cancellationToken); return(true); }