From fdabe62819d71a92ddd9bcb8b4ff117943ea62d0 Mon Sep 17 00:00:00 2001 From: Robert Rudman Date: Fri, 4 Jan 2019 20:53:04 +1100 Subject: [PATCH] When a new post is featured, create a room and get burnaki to track it --- Rodgort/Services/BurnakiFollowService.cs | 2 +- Rodgort/Services/MetaCrawlerService.cs | 39 +++++++++-- Rodgort/Services/NewBurninationService.cs | 83 +++++++++++++++++++++-- Rodgort/Startup.cs | 3 +- StackExchangeChat.Console/Program.cs | 2 +- StackExchangeChat/ChatClient.cs | 2 +- 6 files changed, 116 insertions(+), 15 deletions(-) diff --git a/Rodgort/Services/BurnakiFollowService.cs b/Rodgort/Services/BurnakiFollowService.cs index 24e7c6d..0da5886 100644 --- a/Rodgort/Services/BurnakiFollowService.cs +++ b/Rodgort/Services/BurnakiFollowService.cs @@ -76,7 +76,7 @@ await events private static readonly Regex _userIdRegex = new Regex(@"\/users\/(\d+)"); - private async Task FollowInRoom(int roomId, int followingUserId, DateTime fromTime, string followingTag, DateService dateService, CancellationToken cancellationToken) + public async Task FollowInRoom(int roomId, int followingUserId, DateTime fromTime, string followingTag, DateService dateService, CancellationToken cancellationToken) { await RunWithLogging(async () => { diff --git a/Rodgort/Services/MetaCrawlerService.cs b/Rodgort/Services/MetaCrawlerService.cs index 2ef8fe0..d207084 100644 --- a/Rodgort/Services/MetaCrawlerService.cs +++ b/Rodgort/Services/MetaCrawlerService.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Net; @@ -12,6 +13,7 @@ using Rodgort.Utilities; using StackExchangeApi; using StackExchangeApi.Responses; +using StackExchangeChat; namespace Rodgort.Services { @@ -23,16 +25,22 @@ public class MetaCrawlerService private readonly ApiClient _apiClient; private readonly DateService _dateService; private readonly ILogger _logger; + private readonly NewBurninationService _newBurninationService; private static readonly object _locker = new object(); private static bool _alreadyProcessing; - public MetaCrawlerService(DbContextOptions dbContextOptions, ApiClient apiClient, DateService dateService, ILogger logger) + public MetaCrawlerService(DbContextOptions dbContextOptions, + ApiClient apiClient, + DateService dateService, + ILogger logger, + NewBurninationService newBurninationService) { _dbContextOptions = dbContextOptions; _apiClient = apiClient; _dateService = dateService; _logger = logger; + _newBurninationService = newBurninationService; } [SuppressMessage("ReSharper", "InconsistentlySynchronizedField", Justification = "Flagged _logger, but in both blocks we're guaranteed to run on a single thread")] @@ -67,6 +75,7 @@ public async Task CrawlMeta() var questionLookup = context.MetaQuestions.Where(q => questionIds.Contains(q.Id)) .Include(mq => mq.MetaQuestionMetaTags) + .Include(mq => mq.MetaQuestionTags) .ToDictionary(q => q.Id, q => q); var answerIds = metaQuestions.Items.Where(q => q.Answers != null).SelectMany(q => q.Answers.Select(a => a.AnswerId)).Distinct().ToList(); @@ -81,7 +90,7 @@ public async Task CrawlMeta() if (!questionLookup.ContainsKey(metaQuestion.QuestionId.Value)) { - dbMetaQuestion = new DbMetaQuestion {Id = metaQuestion.QuestionId.Value}; + dbMetaQuestion = new DbMetaQuestion {Id = metaQuestion.QuestionId.Value, MetaQuestionTags = new List()}; context.MetaQuestions.Add(dbMetaQuestion); questionLookup[dbMetaQuestion.Id] = dbMetaQuestion; @@ -107,21 +116,35 @@ public async Task CrawlMeta() if (metaQuestion.ClosedDate.HasValue) dbMetaQuestion.ClosedDate = Dates.UnixTimeStampToDateTime(metaQuestion.ClosedDate.Value); + var trackedTags = dbMetaQuestion.MetaQuestionTags.Where(mqt => mqt.TrackingStatusId == DbMetaQuestionTagTrackingStatus.TRACKED).ToList(); foreach (var tag in metaQuestion.Tags) { if (!dbMetaQuestion.MetaQuestionMetaTags.Any(t => string.Equals(t.TagName, tag, StringComparison.OrdinalIgnoreCase))) { context.MetaQuestionMetaTags.Add(new DbMetaQuestionMetaTag { TagName = tag, MetaQuestion = dbMetaQuestion }); - if (tag == DbMetaTag.STATUS_FEATURED) + { dbMetaQuestion.FeaturedStarted = utcNow; + if (!trackedTags.Any()) + { + await _newBurninationService.AnnounceNoTrackedTags(metaQuestion.Link); + } + else if (trackedTags.Count > 1) + { + await _newBurninationService.AnnounceMultipleTrackedTags(metaQuestion.Link, trackedTags.Select(t => t.TagName)); + } + else + { + await _newBurninationService.CreateRoomForBurn(trackedTags.First().TagName, metaQuestion.Link); + } + } if (tag == DbMetaTag.STATUS_PLANNED) dbMetaQuestion.BurnStarted = utcNow; } } - - - foreach (var dbTag in dbMetaQuestion.MetaQuestionMetaTags.ToList()) + + var metaQuestionList = dbMetaQuestion.MetaQuestionMetaTags.ToList(); + foreach (var dbTag in metaQuestionList) { if (!metaQuestion.Tags.Any(t => string.Equals(t, dbTag.TagName, StringComparison.OrdinalIgnoreCase))) { @@ -130,7 +153,11 @@ public async Task CrawlMeta() if (dbTag.TagName == DbMetaTag.STATUS_FEATURED) dbMetaQuestion.FeaturedEnded = utcNow; if (dbTag.TagName == DbMetaTag.STATUS_PLANNED) + { dbMetaQuestion.BurnEnded = utcNow; + foreach (var trackedTag in trackedTags) + await _newBurninationService.StopBurn(trackedTag.TagName); + } } } diff --git a/Rodgort/Services/NewBurninationService.cs b/Rodgort/Services/NewBurninationService.cs index ce0fb11..982aa0b 100644 --- a/Rodgort/Services/NewBurninationService.cs +++ b/Rodgort/Services/NewBurninationService.cs @@ -1,4 +1,10 @@ -using System.Threading.Tasks; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Metadata.Internal; +using Rodgort.Data; +using Rodgort.Data.Tables; using Rodgort.Utilities; using StackExchangeChat; @@ -7,24 +13,91 @@ namespace Rodgort.Services public class NewBurninationService { private readonly ChatClient _chatClient; - public NewBurninationService(ChatClient chatClient) + private readonly RodgortContext _rodgortContext; + private readonly DateService _dateService; + private readonly BurnakiFollowService _burnakiFollowService; + + private readonly bool Enabled; + + public NewBurninationService(ChatClient chatClient, RodgortContext rodgortContext, DateService dateService, BurnakiFollowService burnakiFollowService, IChatCredentials chatCredentials) { _chatClient = chatClient; + _rodgortContext = rodgortContext; + _dateService = dateService; + _burnakiFollowService = burnakiFollowService; + + var hasCookies = !string.IsNullOrWhiteSpace(chatCredentials.AcctCookie); + var hasCredentials = !string.IsNullOrWhiteSpace(chatCredentials.AcctCookie) && !string.IsNullOrWhiteSpace(chatCredentials.Password); + + Enabled = hasCookies || hasCredentials; + } + + public async Task AnnounceMultipleTrackedTags(string metaPostUrl, IEnumerable trackedTags) + { + if (!Enabled) + return; + + await _chatClient.SendMessage(ChatSite.StackOverflow, ChatRooms.SO_BOTICS_WORKSHOP, $"Discussion for the burnination of {metaPostUrl} started, but there are multiple tracked tags: {string.Join(", ", trackedTags)}"); + } + + public async Task AnnounceNoTrackedTags(string metaPostUrl) + { + if (!Enabled) + return; + + await _chatClient.SendMessage(ChatSite.StackOverflow, ChatRooms.SO_BOTICS_WORKSHOP, $"Discussion for the burnination of {metaPostUrl} started, but there are no tracked tags"); } - public async Task CreateRoomForBurn(ChatSite chatSite, int currentRoomId, string tag, string metaPostUrl) + public async Task StopBurn(string tag) + { + if (!Enabled) + return; + + await _chatClient.SendMessage(ChatSite.StackOverflow, ChatRooms.SO_BOTICS_WORKSHOP, $"@Gemmy stop tag {tag}"); + await _chatClient.SendMessage(ChatSite.StackOverflow, ChatRooms.SO_BOTICS_WORKSHOP, $"The burnination of [tag:{tag}] has finished!"); + + var follows = _rodgortContext.BurnakiFollows.Where(bf => bf.BurnakiId == 8300708 && bf.Tag == tag).ToList(); + foreach (var follow in follows) + { + follow.FollowEnded = _dateService.UtcNow; + } + + _rodgortContext.SaveChanges(); + } + + public async Task CreateRoomForBurn(string tag, string metaPostUrl) { var roomName = $"Observation room for [{tag}] burnination"; - var roomId = await _chatClient.CreateRoom(chatSite, currentRoomId, roomName, string.Empty); + var roomId = await _chatClient.CreateRoom(ChatSite.StackOverflow, ChatRooms.SO_BOTICS_WORKSHOP, roomName, string.Empty); var gemmyMessage = $"@Gemmy start tag [{tag}] {roomId} https://chat.stackoverflow.com/rooms/{roomId}"; await _chatClient.SendMessage(ChatSite.StackOverflow, ChatRooms.SO_BOTICS_WORKSHOP, gemmyMessage); - var burninationMessage = $"The burnination of [tag:{tag}] has begun! {metaPostUrl}"; + var burninationMessage = $"The burnination of [tag:{tag}] is now being discussed {metaPostUrl}"; var burninationMessageId = await _chatClient.SendMessage(ChatSite.StackOverflow, ChatRooms.SO_BOTICS_WORKSHOP, burninationMessage); await _chatClient.PinMessage(ChatSite.StackOverflow, ChatRooms.SO_BOTICS_WORKSHOP, burninationMessageId); + + var burnakiFollow = new DbBurnakiFollow + { + BurnakiId = 8300708, + FollowStarted = _dateService.UtcNow, + RoomId = roomId, + Tag = tag + }; + + _rodgortContext.BurnakiFollows.Add(burnakiFollow); + _rodgortContext.SaveChanges(); + + await _burnakiFollowService.FollowInRoom( + burnakiFollow.RoomId, + burnakiFollow.BurnakiId, + burnakiFollow.FollowStarted, + burnakiFollow.Tag, + _dateService, + CancellationToken.None + ); } } } diff --git a/Rodgort/Startup.cs b/Rodgort/Startup.cs index ab38fb9..74491b8 100644 --- a/Rodgort/Startup.cs +++ b/Rodgort/Startup.cs @@ -89,7 +89,8 @@ public void ConfigureServices(IServiceCollection services) services.AddScoped(); services.AddScoped(); - + services.AddScoped(); + services.AddHostedService(); } diff --git a/StackExchangeChat.Console/Program.cs b/StackExchangeChat.Console/Program.cs index b936662..a4b1a60 100644 --- a/StackExchangeChat.Console/Program.cs +++ b/StackExchangeChat.Console/Program.cs @@ -52,7 +52,7 @@ public static void Main(string[] args) var newBurninationService = serviceProvider.GetService(); - newBurninationService.CreateRoomForBurn(ChatSite.StackOverflow, ChatRooms.SO_BOTICS_WORKSHOP, "priority", "https://meta.stackoverflow.com/questions/285084/should-we-burninate-the-priority-tag").GetAwaiter().GetResult(); + // newBurninationService.CreateRoomForBurn(ChatSite.StackOverflow, ChatRooms.SO_BOTICS_WORKSHOP, "priority", "https://meta.stackoverflow.com/questions/285084/should-we-burninate-the-priority-tag").GetAwaiter().GetResult(); // var roomId = chatClient.CreateRoom(ChatSite.StackOverflow, 167908, "This is a testing room", "This is a testing description").GetAwaiter().GetResult(); //var events = chatClient.SubscribeToEvents(ChatSite.StackExchange, 86421); //events.Subscribe(System.Console.WriteLine); diff --git a/StackExchangeChat/ChatClient.cs b/StackExchangeChat/ChatClient.cs index 226f026..84da9d5 100644 --- a/StackExchangeChat/ChatClient.cs +++ b/StackExchangeChat/ChatClient.cs @@ -28,7 +28,7 @@ public ChatClient(SiteAuthenticator siteAuthenticator, HttpClientWithHandler htt public async Task SendMessage(ChatSite chatSite, int roomId, string message) { - return await ThrottlingUtils.Throttle(ChatThrottleGroups.WebRequestThrottle, async () => + return await ThrottlingUtils.Throttle(ChatThrottleGroups.WebRequestThrottle, async () => { var fkey = (await _siteAuthenticator.GetRoomDetails(chatSite, roomId)).FKey; await _siteAuthenticator.AuthenticateClient(_httpClient, chatSite);