From 3513e090e45bcc2b9bbd8c557923e2efc5dc7179 Mon Sep 17 00:00:00 2001 From: Luchs Date: Tue, 14 May 2019 14:13:49 +0200 Subject: [PATCH] Major updates to Artist Alley table registration service --- .../ArtistsAlley/TableRegistrationRecord.cs | 42 +++++- .../ArtistsAlley/ITableRegistrationService.cs | 9 +- .../ArtistsAlley/TableRegistrationRequest.cs | 8 +- .../Telegram/ITelegramMessageSender.cs | 2 + .../ArtistsAlley/TableRegistrationService.cs | 123 +++++++++++++++++- .../Eurofurence.App.Server.Services.csproj | 3 +- .../Telegram/AdminConversation.cs | 98 +++++++++++++- .../Telegram/BotManager.cs | 98 ++++++-------- .../Telegram/TelegramMessageBroker.cs | 14 ++ 9 files changed, 324 insertions(+), 73 deletions(-) diff --git a/src/Eurofurence.App.Domain.Model/ArtistsAlley/TableRegistrationRecord.cs b/src/Eurofurence.App.Domain.Model/ArtistsAlley/TableRegistrationRecord.cs index 1c610dbb..e0e09349 100644 --- a/src/Eurofurence.App.Domain.Model/ArtistsAlley/TableRegistrationRecord.cs +++ b/src/Eurofurence.App.Domain.Model/ArtistsAlley/TableRegistrationRecord.cs @@ -1,17 +1,57 @@ using Eurofurence.App.Domain.Model.Fragments; +using System; +using System.Collections.Generic; namespace Eurofurence.App.Domain.Model.ArtistsAlley { public class TableRegistrationRecord : EntityBase { + public class StateChangeRecord + { + public DateTime ChangedDateTimeUtc{ get; set; } + public string ChangedByUid { get; set; } + public RegistrationStateEnum OldState { get; set; } + public RegistrationStateEnum NewState { get; set; } + } + + public enum RegistrationStateEnum + { + Pending = 0, + Accepted = 1, + Published = 2, + Rejected = 3 + } + public string OwnerUid { get; set; } public string DisplayName { get; set; } - public string Merchandise { get; set; } + public string WebsiteUrl { get; set; } public string ShortDescription { get; set; } public ImageFragment Image { get; set; } + + public RegistrationStateEnum State { get; set; } + + public IList StateChangeLog { get; set; } + + public TableRegistrationRecord() + { + this.StateChangeLog = new List(); + } + + public void ChangeState(RegistrationStateEnum newState, string uid) + { + StateChangeLog.Add(new StateChangeRecord() + { + ChangedByUid = uid, + ChangedDateTimeUtc = DateTime.UtcNow, + NewState = newState, + OldState = State + }); + + State = newState; + } } } diff --git a/src/Eurofurence.App.Server.Services/Abstractions/ArtistsAlley/ITableRegistrationService.cs b/src/Eurofurence.App.Server.Services/Abstractions/ArtistsAlley/ITableRegistrationService.cs index 8ac50892..3c0c9af3 100644 --- a/src/Eurofurence.App.Server.Services/Abstractions/ArtistsAlley/ITableRegistrationService.cs +++ b/src/Eurofurence.App.Server.Services/Abstractions/ArtistsAlley/ITableRegistrationService.cs @@ -1,9 +1,16 @@ -using System.Threading.Tasks; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Eurofurence.App.Domain.Model.ArtistsAlley; namespace Eurofurence.App.Server.Services.Abstractions.ArtistsAlley { public interface ITableRegistrationService { Task RegisterTableAsync(string uid, TableRegistrationRequest request); + Task> GetRegistrations(TableRegistrationRecord.RegistrationStateEnum? state); + + Task ApproveByIdAsync(Guid id, string operatorUid); + Task RejectByIdAsync(Guid id, string operatorUid); } } diff --git a/src/Eurofurence.App.Server.Services/Abstractions/ArtistsAlley/TableRegistrationRequest.cs b/src/Eurofurence.App.Server.Services/Abstractions/ArtistsAlley/TableRegistrationRequest.cs index b63dd65b..7fa2c58e 100644 --- a/src/Eurofurence.App.Server.Services/Abstractions/ArtistsAlley/TableRegistrationRequest.cs +++ b/src/Eurofurence.App.Server.Services/Abstractions/ArtistsAlley/TableRegistrationRequest.cs @@ -1,14 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Eurofurence.App.Server.Services.Abstractions.ArtistsAlley +namespace Eurofurence.App.Server.Services.Abstractions.ArtistsAlley { public class TableRegistrationRequest { public string DisplayName { get; set; } - public string Merchandise { get; set; } + public string WebsiteUrl { get; set; } public string ShortDescription { get; set; } diff --git a/src/Eurofurence.App.Server.Services/Abstractions/Telegram/ITelegramMessageSender.cs b/src/Eurofurence.App.Server.Services/Abstractions/Telegram/ITelegramMessageSender.cs index 41b68e12..45ae3be5 100644 --- a/src/Eurofurence.App.Server.Services/Abstractions/Telegram/ITelegramMessageSender.cs +++ b/src/Eurofurence.App.Server.Services/Abstractions/Telegram/ITelegramMessageSender.cs @@ -6,10 +6,12 @@ namespace Eurofurence.App.Server.Services.Abstractions.Telegram public interface ITelegramMessageSender { Task SendMarkdownMessageToChatAsync(string chatId, string message); + Task SendImageToChatAsync(string chatId, byte[] imageBytes, string message = ""); } public interface ITelegramMessageBroker : ITelegramMessageSender { event Func OnSendMarkdownMessageToChatAsync; + event Func OnSendImageToChatAsync; } } \ No newline at end of file diff --git a/src/Eurofurence.App.Server.Services/ArtistsAlley/TableRegistrationService.cs b/src/Eurofurence.App.Server.Services/ArtistsAlley/TableRegistrationService.cs index 87075912..fd689b3c 100644 --- a/src/Eurofurence.App.Server.Services/ArtistsAlley/TableRegistrationService.cs +++ b/src/Eurofurence.App.Server.Services/ArtistsAlley/TableRegistrationService.cs @@ -1,43 +1,160 @@ using System; +using System.Collections.Generic; +using System.Text; using System.Threading.Tasks; +using Eurofurence.App.Common.ExtensionMethods; using Eurofurence.App.Domain.Model.Abstractions; using Eurofurence.App.Domain.Model.ArtistsAlley; +using Eurofurence.App.Domain.Model.Security; using Eurofurence.App.Server.Services.Abstractions.ArtistsAlley; using Eurofurence.App.Server.Services.Abstractions.Images; +using Eurofurence.App.Server.Services.Abstractions.Telegram; +using LinqToTwitter; namespace Eurofurence.App.Server.Services.ArtistsAlley { public class TableRegistrationService : ITableRegistrationService { + private readonly ArtistAlleyConfiguration _configuration; private readonly IEntityRepository _tableRegistrationRepository; + private readonly ITelegramMessageSender _telegramMessageSender; private readonly IImageService _imageService; + private readonly IEntityRepository _regSysIdentityRepository; + private TwitterContext _twitterContext; public TableRegistrationService( + ArtistAlleyConfiguration configuration, IEntityRepository tableRegistrationRepository, + ITelegramMessageSender telegramMessageSender, + IEntityRepository regSysIdentityRepository, IImageService imageService) { + _configuration = configuration; _tableRegistrationRepository = tableRegistrationRepository; + _telegramMessageSender = telegramMessageSender; + _regSysIdentityRepository = regSysIdentityRepository; _imageService = imageService; + + var auth = new SingleUserAuthorizer + { + CredentialStore = new SingleUserInMemoryCredentialStore + { + ConsumerKey = _configuration.TwitterConsumerKey, + ConsumerSecret = _configuration.TwitterConsumerSecret, + AccessToken = _configuration.TwitterAccessToken, + AccessTokenSecret = _configuration.TwitterAccessTokenSecret + } + }; + _twitterContext = new TwitterContext(auth); + } + + public async Task> GetRegistrations(TableRegistrationRecord.RegistrationStateEnum? state) + { + var records = await _tableRegistrationRepository.FindAllAsync(a => !state.HasValue || a.State == state.Value); + return records; } public async Task RegisterTableAsync(string uid, TableRegistrationRequest request) { + var identity = await _regSysIdentityRepository.FindOneAsync(a => a.Uid == uid); + byte[] imageBytes = Convert.FromBase64String(request.ImageContent); var imageFragment = _imageService.GenerateFragmentFromBytes(imageBytes); + imageFragment = _imageService.EnforceMaximumDimensions(imageFragment, 1500, 1500); + var record = new TableRegistrationRecord() { OwnerUid = uid, DisplayName = request.DisplayName, - Merchandise = request.Merchandise, + WebsiteUrl = request.WebsiteUrl, ShortDescription = request.ShortDescription, - Image = imageFragment + Image = imageFragment, + State = TableRegistrationRecord.RegistrationStateEnum.Pending }; record.NewId(); record.Touch(); await _tableRegistrationRepository.InsertOneAsync(record); + await _telegramMessageSender.SendMarkdownMessageToChatAsync( + _configuration.TelegramAdminGroupChatId, + $"*New Table Registration Request:*\n\nFrom: *{identity.Username.RemoveMarkdown()} ({uid})*\n\nDisplay Name: *{record.DisplayName.RemoveMarkdown()}*\n_{record.ShortDescription.RemoveMarkdown()}_"); + } + + public async Task ApproveByIdAsync(Guid id, string operatorUid) + { + var record = await _tableRegistrationRepository.FindOneAsync(a => a.Id == id + && a.State == TableRegistrationRecord.RegistrationStateEnum.Pending); + var identity = await _regSysIdentityRepository.FindOneAsync(a => a.Uid == record.OwnerUid); + + record.ChangeState(TableRegistrationRecord.RegistrationStateEnum.Accepted, operatorUid); + record.Touch(); + + await _tableRegistrationRepository.ReplaceOneAsync(record); + + await _telegramMessageSender.SendMarkdownMessageToChatAsync( + _configuration.TelegramAdminGroupChatId, + $"*Approved:* {identity.Username} ({record.OwnerUid} / {record.Id})\n\nRegistration has been approved by *{operatorUid}* and will be published on Twitter/Telegram."); + + + + await BroadcastAsync(record); + // Todo: Send a message to user. + } + + private async Task BroadcastAsync(TableRegistrationRecord record) + { + var messageBuilder = new StringBuilder(); + messageBuilder.Append($"Now in the Artist Alley:\n\n*{record.DisplayName.RemoveMarkdown()}*\n\n"); + messageBuilder.Append($"_{record.ShortDescription.RemoveMarkdown()}_"); + if (record.WebsiteUrl != null) + { + messageBuilder.Append("\n\n"); + messageBuilder.Append(record.WebsiteUrl); + } + + var message = messageBuilder.ToString(); + + if (record.Image != null) + { + await _telegramMessageSender.SendImageToChatAsync( + _configuration.TelegramAnnouncementChannelId, + record.Image.ImageBytes, + message); + + var media = await _twitterContext.UploadMediaAsync( + record.Image.ImageBytes, + record.Image.MimeType, + "tweet_image"); + + await _twitterContext.TweetAsync(message.RemoveMarkdown(), new ulong[] { media.MediaID }); + } + else + { + await _telegramMessageSender.SendMarkdownMessageToChatAsync( + _configuration.TelegramAnnouncementChannelId, + message); + + await _twitterContext.TweetAsync(message.RemoveMarkdown()); + } + } + + public async Task RejectByIdAsync(Guid id, string operatorUid) + { + var record = await _tableRegistrationRepository.FindOneAsync(a => a.Id == id + && a.State == TableRegistrationRecord.RegistrationStateEnum.Pending); + var identity = await _regSysIdentityRepository.FindOneAsync(a => a.Uid == record.OwnerUid); + + record.ChangeState(TableRegistrationRecord.RegistrationStateEnum.Rejected, operatorUid); + record.Touch(); + + await _tableRegistrationRepository.ReplaceOneAsync(record); + + await _telegramMessageSender.SendMarkdownMessageToChatAsync(_configuration.TelegramAdminGroupChatId, + $"*Rejected:* {identity.Username} ({record.OwnerUid} / {record.Id})\n\nRegistration has been rejected by *{operatorUid}*. Reason given: ..."); + + // Todo: Send a message to user. } } -} +} \ No newline at end of file diff --git a/src/Eurofurence.App.Server.Services/Eurofurence.App.Server.Services.csproj b/src/Eurofurence.App.Server.Services/Eurofurence.App.Server.Services.csproj index e082155d..c5771e3a 100644 --- a/src/Eurofurence.App.Server.Services/Eurofurence.App.Server.Services.csproj +++ b/src/Eurofurence.App.Server.Services/Eurofurence.App.Server.Services.csproj @@ -17,13 +17,14 @@ + - + diff --git a/src/Eurofurence.App.Server.Services/Telegram/AdminConversation.cs b/src/Eurofurence.App.Server.Services/Telegram/AdminConversation.cs index 492b69ef..bee766fa 100644 --- a/src/Eurofurence.App.Server.Services/Telegram/AdminConversation.cs +++ b/src/Eurofurence.App.Server.Services/Telegram/AdminConversation.cs @@ -20,9 +20,10 @@ using Telegram.Bot.Types.ReplyMarkups; using Eurofurence.App.Server.Services.Abstractions.Telegram; using Microsoft.Extensions.Logging; -using Telegram.Bot.Types.InlineKeyboardButtons; -using Telegram.Bot.Types.InlineQueryResults; using System.IO; +using Eurofurence.App.Server.Services.Abstractions.ArtistsAlley; +using Telegram.Bot.Types.InputFiles; +using Eurofurence.App.Domain.Model.Security; namespace Eurofurence.App.Server.Services.Telegram { @@ -33,7 +34,9 @@ public class AdminConversation : Conversation, IConversation private readonly IEntityRepository _pushNotificationChannelRepository; private readonly IEntityRepository _fursuitBadgeRepository; private readonly IEntityRepository _fursuitBadgeImageRepository; + private readonly IEntityRepository _regSysIdentityRepository; private readonly IPrivateMessageService _privateMessageService; + private readonly ITableRegistrationService _tableRegistrationService; private readonly ICollectingGameService _collectingGameService; private readonly ConventionSettings _conventionSettings; @@ -60,7 +63,8 @@ enum PermissionFlags SendPm = 1 << 5, BadgeChecksum = 1 << 6, CollectionGameAdmin = 1 << 7, - All = (1 << 8) - 1, + TableRegistrationAdmin = 1 << 8, + All = (1 << 9) - 1, } private User _user; @@ -88,7 +92,9 @@ public AdminConversation( IEntityRepository pushNotificationChannelRepository, IEntityRepository fursuitBadgeRepository, IEntityRepository fursuitBadgeImageRepository, + IEntityRepository regSysIdentityRepository, IPrivateMessageService privateMessageService, + ITableRegistrationService tableRegistrationService, ICollectingGameService collectingGameService, ConventionSettings conventionSettings, ILoggerFactory loggerFactory @@ -100,7 +106,9 @@ ILoggerFactory loggerFactory _pushNotificationChannelRepository = pushNotificationChannelRepository; _fursuitBadgeRepository = fursuitBadgeRepository; _fursuitBadgeImageRepository = fursuitBadgeImageRepository; + _regSysIdentityRepository = regSysIdentityRepository; _privateMessageService = privateMessageService; + _tableRegistrationService = tableRegistrationService; _collectingGameService = collectingGameService; _conventionSettings = conventionSettings; @@ -176,6 +184,13 @@ ILoggerFactory loggerFactory Description = "Unban someone from the game", RequiredPermission = PermissionFlags.CollectionGameAdmin, CommandHandler = CommandCollectionGameUnban + }, + new CommandInfo() + { + Command ="/tableRegistration", + Description = "Manage Table Registrations", + RequiredPermission = PermissionFlags.TableRegistrationAdmin, + CommandHandler = CommandTableRegistration } }; } @@ -211,7 +226,7 @@ await ReplyAsync( $"*{title} - Result*\nNo: *{badgeNo}*\nOwner: *{badge.OwnerUid}*\nName: *{badge.Name.RemoveMarkdown()}*\nSpecies: *{badge.Species.RemoveMarkdown()}*\nGender: *{badge.Gender.RemoveMarkdown()}*\nWorn By: *{badge.WornBy.RemoveMarkdown()}*\n\nLast Change (UTC): {badge.LastChangeDateTimeUtc}"); var imageContent = new MemoryStream((await _fursuitBadgeImageRepository.FindOneAsync(badge.Id)).ImageBytes); - await BotClient.SendPhotoAsync(ChatId, new FileToSend(badge.Id.ToString(), imageContent)); + await BotClient.SendPhotoAsync(ChatId, new InputOnlineFile(imageContent)); }, "Cancel=/cancel"); await c1(); } @@ -568,6 +583,79 @@ public async Task ReplyAsync(string message, params string[] commandOptions) await BotClient.SendTextMessageAsync(ChatId, message, ParseMode.Markdown, replyMarkup: MarkupFromCommands(commandOptions)); } + private async Task CommandTableRegistration() + { + Func c1 = null, c2 = null, c3 = null; + var title = "Table Registration"; + var requesterUid = $"Telegram:@{_user.Username}"; + + c1 = () => AskAsync($"*{title}* - What would you like to do?", + async c1a => + { + if (c1a == "*list") + { + var records = await _tableRegistrationService.GetRegistrations(Domain.Model.ArtistsAlley.TableRegistrationRecord.RegistrationStateEnum.Pending); + var ownerUids = records.Select(a => a.OwnerUid); + var ownerIdentities = await _regSysIdentityRepository.FindAllAsync(a => ownerUids.Contains(a.Uid)); + + var list = records.Select(record => + $"{record.Id} / {record.OwnerUid} {ownerIdentities.Single(a => a.Uid == record.OwnerUid).Username.RemoveMarkdown()}\n*{record.DisplayName.RemoveMarkdown()}*" + ); + + var response = $"There are currently *{records.Count()}* registrations pending reviews.\n\n{String.Join("\n\n", list)}"; + + await ReplyAsync(response); + + await c1(); + } + else if (c1a == "*review") + { + var records = await _tableRegistrationService.GetRegistrations(Domain.Model.ArtistsAlley.TableRegistrationRecord.RegistrationStateEnum.Pending); + var nextRecord = records.OrderBy(a => a.LastChangeDateTimeUtc).FirstOrDefault(); + + if (nextRecord == null) + { + await ReplyAsync("There are no registrations pending review."); + await c1(); + } else + { + var ownerIdentity = await _regSysIdentityRepository.FindOneAsync(a => a.Uid == nextRecord.OwnerUid); + + var message = new StringBuilder(); + + message.AppendLine("You are reviewing:"); + message.AppendLine($"*Id:*`{nextRecord.Id}` (from: { nextRecord.OwnerUid} { ownerIdentity.Username.RemoveMarkdown()})\n"); + + message.AppendLine($"Display Name: *{nextRecord.DisplayName.RemoveMarkdown()}*"); + message.AppendLine($"Website URL: *{nextRecord.WebsiteUrl.RemoveMarkdown()}*"); + message.AppendLine($"Short Description: _{nextRecord.ShortDescription.RemoveMarkdown()}_\n"); + message.AppendLine($"Image: {(nextRecord.Image != null ? "Available (see below)" : "Not provided")}"); + + await ReplyAsync(message.ToString()); + if (nextRecord.Image != null) + { + var imageContent = new MemoryStream(nextRecord.Image.ImageBytes); + await BotClient.SendPhotoAsync(ChatId, new InputOnlineFile(imageContent)); + } + + c2 = () => AskAsync($"Do you wish to approve `{nextRecord.Id}`? Doing so will trigger an post both to the Telegram announcement channel and Twitter feed.", + async c2a => + { + if (c2a == "*approve") await _tableRegistrationService.ApproveByIdAsync(nextRecord.Id, requesterUid); + if (c2a == "*reject") await _tableRegistrationService.RejectByIdAsync(nextRecord.Id, requesterUid); + + + await ReplyAsync("Done. Send /tableRegistration again if you wish to review/view further items."); + + }, "Approve=*approve", "Reject=*reject"); + + await c2(); + } + } + + }, "List all pending=*list", "Review next one=*review", "Cancel=/cancel"); + await c1(); + } private async Task CommandPinInfo() { @@ -670,7 +758,7 @@ await ReplyAsync( $"*{badge.Name.EscapeMarkdown()}* ({badge.Species.EscapeMarkdown()}, {badge.Gender.EscapeMarkdown()})"); var imageContent = new MemoryStream((await _fursuitBadgeImageRepository.FindOneAsync(badge.Id)).ImageBytes); - await BotClient.SendPhotoAsync(ChatId, new FileToSend(badge.Id.ToString(), imageContent)); + await BotClient.SendPhotoAsync(ChatId, new InputOnlineFile(imageContent)); askTokenValue = () => AskAsync( $"*{title} - Step 3 of 3*\nPlease enter the `code/token` on the sticker that was applied to the badge.", diff --git a/src/Eurofurence.App.Server.Services/Telegram/BotManager.cs b/src/Eurofurence.App.Server.Services/Telegram/BotManager.cs index 72e71b36..901beff4 100644 --- a/src/Eurofurence.App.Server.Services/Telegram/BotManager.cs +++ b/src/Eurofurence.App.Server.Services/Telegram/BotManager.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Net; @@ -14,15 +13,17 @@ using Eurofurence.App.Server.Services.Abstractions.Dealers; using Eurofurence.App.Server.Services.Abstractions.Events; using Eurofurence.App.Server.Services.Abstractions.Fursuits; -using Eurofurence.App.Server.Services.Abstractions.Images; using Eurofurence.App.Server.Services.Abstractions.Security; using Telegram.Bot; using Telegram.Bot.Args; using Telegram.Bot.Types.Enums; using Telegram.Bot.Types.InlineQueryResults; -using Telegram.Bot.Types.InputMessageContents; using Eurofurence.App.Server.Services.Abstractions.Telegram; using Microsoft.Extensions.Logging; +using System.IO; +using Eurofurence.App.Server.Services.Abstractions.ArtistsAlley; +using Telegram.Bot.Types.InputFiles; +using Eurofurence.App.Domain.Model.Security; // ReSharper disable CoVariantArrayConversion @@ -38,7 +39,9 @@ public class BotManager private readonly IEntityRepository _pushNotificationChannelRepository; private readonly IEntityRepository _fursuitBadgeRepository; private readonly IEntityRepository _fursuitBadgeImageRepository; + private readonly IEntityRepository _regSysIdentityRepository; private readonly IPrivateMessageService _privateMessageService; + private readonly ITableRegistrationService _tableRegistrationService; private readonly ICollectingGameService _collectingGameService; private readonly ConventionSettings _conventionSettings; private readonly ITelegramMessageBroker _telegramMessageBroker; @@ -80,6 +83,8 @@ public BotManager( IEntityRepository pushNotificationChannelRepository, IEntityRepository fursuitBadgeRepository, IEntityRepository fursuitBadgeImageRepository, + IEntityRepository regSysIdentityRepository, + ITableRegistrationService tableRegistrationService, IPrivateMessageService privateMessageService, ICollectingGameService collectingGameService, ConventionSettings conventionSettings, @@ -96,7 +101,9 @@ ITelegramMessageBroker telegramMessageBroker _pushNotificationChannelRepository = pushNotificationChannelRepository; _fursuitBadgeRepository = fursuitBadgeRepository; _fursuitBadgeImageRepository = fursuitBadgeImageRepository; + _regSysIdentityRepository = regSysIdentityRepository; _privateMessageService = privateMessageService; + _tableRegistrationService = tableRegistrationService; _collectingGameService = collectingGameService; _conventionSettings = conventionSettings; _telegramMessageBroker = telegramMessageBroker; @@ -122,7 +129,9 @@ ITelegramMessageBroker telegramMessageBroker _pushNotificationChannelRepository, _fursuitBadgeRepository, _fursuitBadgeImageRepository, + _regSysIdentityRepository, privateMessageService, + _tableRegistrationService, _collectingGameService, _conventionSettings, loggerFactory @@ -135,11 +144,12 @@ ITelegramMessageBroker telegramMessageBroker _botClient.OnInlineQuery += BotClientOnOnInlineQuery; _telegramMessageBroker.OnSendMarkdownMessageToChatAsync += _telegramMessageBroker_OnSendMarkdownMessageToChatAsync; + _telegramMessageBroker.OnSendImageToChatAsync += _telegramMessageBroker_OnSendImageToChatAsync; } - private async Task QueryEvents(string query) + private async Task QueryEvents(string query) { - if (query.Length < 3) return new InlineQueryResult[0]; + if (query.Length < 3) return new InlineQueryResultBase[0]; var events = (await _eventService.FindAllAsync(a => a.IsDeleted == 0 && a.Title.ToLower().Contains(query.ToLower()))) @@ -147,7 +157,7 @@ private async Task QueryEvents(string query) .Take(10) .ToList(); - if (events.Count == 0) return new InlineQueryResult[0]; + if (events.Count == 0) return new InlineQueryResultBase[0]; var eventConferenceRooms = await _eventConferenceRoomService.FindAllAsync(); @@ -173,15 +183,16 @@ private async Task QueryEvents(string query) messageBuilder.Append($"\n\n[Read more...](https://www.eurofurence.org/{_conventionSettings.ConventionIdentifier}/schedule/events/{e.SourceEventId}.en.html)"); - return new InlineQueryResultArticle() + var inputMessageContent = new InputTextMessageContent(messageBuilder.ToString()) + { + ParseMode = ParseMode.Markdown + }; + + return new InlineQueryResultArticle( + e.Id.ToString(), + e.Title + (string.IsNullOrEmpty(e.SubTitle) ? "" : $" ({e.SubTitle})"), + inputMessageContent) { - Id = e.Id.ToString(), - InputMessageContent = new InputTextMessageContent() - { - MessageText = messageBuilder.ToString(), - ParseMode = ParseMode.Markdown - }, - Title = e.Title + (string.IsNullOrEmpty(e.SubTitle) ? "" : $" ({e.SubTitle})"), Description = $"{e.StartDateTimeUtc.DayOfWeek}, {e.StartDateTimeUtc.Day}.{e.StartDateTimeUtc.Month} - {e.StartTime} until {e.EndTime}" }; @@ -190,9 +201,9 @@ private async Task QueryEvents(string query) } - private async Task QueryFursuitBadges(string query) + private async Task QueryFursuitBadges(string query) { - if (query.Length < 3) return new InlineQueryResult[0]; + if (query.Length < 3) return new InlineQueryResultBase[0]; var badges = @@ -201,15 +212,15 @@ private async Task QueryFursuitBadges(string query) .Take(5) .ToList(); - if (badges.Count == 0) return new InlineQueryResult[0]; + if (badges.Count == 0) return new InlineQueryResultBase[0]; return badges.Select(e => { - return new InlineQueryResultPhoto() + return new InlineQueryResultPhoto(e.Id.ToString(), + $"https://app.eurofurence.org/api/v2/Fursuits/Badges/{e.Id}/Image", + $"https://app.eurofurence.org/api/v2/Fursuits/Badges/{e.Id}/Image") { - Id = e.Id.ToString(), - Url = $"https://app.eurofurence.org/api/v2/Fursuits/Badges/{e.Id}/Image", - ThumbUrl = $"https://app.eurofurence.org/api/v2/Fursuits/Badges/{e.Id}/Image", + Title = e.Name, Caption = $"{e.Name}\n{e.Species} ({e.Gender})\n\nWorn by:{e.WornBy}\n\nhttps://fursuit.eurofurence.org/showSuit.php?id={e.ExternalReference}" }; @@ -218,39 +229,6 @@ private async Task QueryFursuitBadges(string query) } - private async Task QueryDealers(string query) - { - if (query.Length < 3) return new InlineQueryResult[0]; - - var dealers = - (await _dealerService.FindAllAsync(a => a.IsDeleted == 0 && ( - a.DisplayName.ToLower().Contains(query.ToLower()) || a.AttendeeNickname.ToLower().Contains(query.ToLower()) - ))) - .Take(5) - .ToList(); - - if (dealers.Count == 0) return new InlineQueryResult[0]; - - return dealers.Select(e => - { - var messageBuilder = new StringBuilder(); - messageBuilder.Append($"*{e.AttendeeNickname} {e.DisplayName}*"); - - messageBuilder.Append("\n\n[Read more...](https://app.eurofurence.org)"); - - return new InlineQueryResultPhoto() - { - Id = e.Id.ToString(), - Url = "https://app.eurofurence.org/images/qrcode_getAndroidApp.png", - ThumbUrl = "https://app.eurofurence.org/images/qrcode_getAndroidApp.png", - Title = e.AttendeeNickname, - Description = "..." - }; - }) - .ToArray(); - } - - private async void BotClientOnOnInlineQuery(object sender, InlineQueryEventArgs inlineQueryEventArgs) { try @@ -259,8 +237,6 @@ private async void BotClientOnOnInlineQuery(object sender, InlineQueryEventArgs var queries = new[] { QueryEvents(queryString), - // QueryFursuitBadges(queryString) - // QueryDealers(queryString) }; Task.WaitAll(queries); @@ -336,5 +312,15 @@ private async Task _telegramMessageBroker_OnSendMarkdownMessageToChatAsync(strin { await _botClient.SendTextMessageAsync(chatId, message, ParseMode.Markdown); } + + private async Task _telegramMessageBroker_OnSendImageToChatAsync(string chatId, byte[] imageBytes, string message) + { + await _botClient.SendPhotoAsync( + chatId, new InputOnlineFile(new MemoryStream(imageBytes)), + caption: message, + parseMode: ParseMode.Markdown); + + } + } } diff --git a/src/Eurofurence.App.Server.Services/Telegram/TelegramMessageBroker.cs b/src/Eurofurence.App.Server.Services/Telegram/TelegramMessageBroker.cs index ad5f26d9..92f22703 100644 --- a/src/Eurofurence.App.Server.Services/Telegram/TelegramMessageBroker.cs +++ b/src/Eurofurence.App.Server.Services/Telegram/TelegramMessageBroker.cs @@ -21,6 +21,20 @@ public async Task SendMarkdownMessageToChatAsync(string chatId, string message) await Task.WhenAll(handlerTasks); } + public async Task SendImageToChatAsync(string chatId, byte[] imageBytes, string message = "") + { + var invocationList = OnSendImageToChatAsync.GetInvocationList(); + var handlerTasks = new Task[invocationList.Length]; + + for (var i = 0; i < invocationList.Length; i++) + { + handlerTasks[i] = ((Func)invocationList[i])(chatId, imageBytes, message); + } + + await Task.WhenAll(handlerTasks); + } + public event Func OnSendMarkdownMessageToChatAsync; + public event Func OnSendImageToChatAsync; } } \ No newline at end of file