public async Task <bool?> Handle(InlineQuery data, object context = default, CancellationToken cancellationToken = default)
        {
            var queryParts = new StringSegment(data.Query).Split(new[] { ' ' }).FirstOrDefault().Split(new[] { ':' });

            if (!PollEx.TryGetPollId(queryParts.ElementAtOrDefault(1), out var pollId, out var format))
            {
                return(null);
            }

            var poll = (await myRaidService.GetOrCreatePollAndMessage(new PollMessage(data)
            {
                BotId = myBot.BotId, PollId = pollId
            }, myUrlHelper,
                                                                      format, cancellationToken))?.Poll;

            if (poll == null)
            {
                return(null);
            }

            var result = await GetResult(poll, cancellationToken);

            result ??= new InlineQueryResultArticle("NobodyToInvite", "Nobody to invite",
                                                    new TextBuilder().Sanitize($"Nobody to invite").ToTextMessageContent())
            {
                ThumbUrl = myUrlHelper.AssetsContent(@"static_assets/png/btn_close_normal.png").ToString()
            };

            await myBot.AnswerInlineQueryWithValidationAsync(data.Id, new[] { result }, cacheTime : 0, isPersonal : true, cancellationToken : cancellationToken);

            return(true);
        }
        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 <bool?> Handle(InlineQuery data, object context = default, CancellationToken cancellationToken = default)
        {
            var results = new List <InlineQueryResult>();

            var    query     = data.Query;
            string encodedId = null;

            if (Regex.Match(query, PATTERN) is { Success : true } match)
            {
                encodedId = match.Groups["Id"].Value;
                query     = query.Remove(match.Index, match.Length);
            }
            query = query.Trim();

            var matchedZones = myDateTimeZoneProvider.Ids.Where(id =>
            {
                // check tz id
                if (id.Contains(query, StringComparison.OrdinalIgnoreCase))
                {
                    return(true);
                }

                // check Region name
                return(myTimeZoneService.TryGetRegion(id, out var region) && (
                           region.EnglishName.Contains(query, StringComparison.OrdinalIgnoreCase) ||
                           region.NativeName.Contains(query, StringComparison.OrdinalIgnoreCase)));
            }).ToList();

            InlineKeyboardMarkup replyMarkup = null;

            if (myTimeZoneNotifyService.DecodeId(encodedId, out var chatId, out var messageId))
            {
                (_, replyMarkup) = await myTimeZoneNotifyService.GetSettingsMessage(new Chat { Id = chatId, Type = ChatType.Sender }, messageId, cancellationToken);
            }
            var instant = myClock.GetCurrentInstant();

            int.TryParse(data.Offset, out var offset);
            for (var index = offset; index < matchedZones.Count && index < offset + PAGE_SIZE; index++)
            {
                var id = matchedZones[index];
                if (myDateTimeZoneProvider.GetZoneOrNull(id) is { } timeZone)
                {
                    var title   = $"{timeZone.Id} ({timeZone.GetUtcOffset(instant)})";
                    var builder = new TextBuilder()
                                  .Append($"{title}\x00A0") // trailing space is necessary to allow edit it further to the same message
                                  .NewLine();

                    string countryString = null;
                    if (myTimeZoneService.TryGetRegion(timeZone.Id, out var country))
                    {
                        countryString = $"{country.EnglishName} {country.NativeName}";
                        builder.Sanitize(countryString).NewLine();
                    }

                    results.Add(new InlineQueryResultArticle($"{PREFIX}:{encodedId}:{timeZone.Id}", title, builder.ToTextMessageContent())
                    {
                        Description = countryString,
                        ReplyMarkup = replyMarkup
                    });
                }
            }

            string nextOffset = default;

            if (results.Count == 0 && offset == 0)
            {
                results.Add(new InlineQueryResultArticle("NothingFound", "Nothing found",
                                                         new TextBuilder($"Nothing found by request ").Code(builder => builder.Sanitize(query)).ToTextMessageContent())
                {
                    Description = $"Request {query}",
                    ThumbUrl    = myUrlHelper.AssetsContent(@"static_assets/png/btn_close_normal.png").AbsoluteUri
                });
            }
            else
            {
                nextOffset = (offset + PAGE_SIZE).ToString();
            }

            await myBot.AnswerInlineQueryWithValidationAsync(data.Id, results, nextOffset : nextOffset, cacheTime : 0, isPersonal : true, cancellationToken : cancellationToken);

            return(true);
        }
예제 #4
0
        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);
        }
예제 #5
0
        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);
        }