/// <summary> /// Syncs a srl race with it's persistent euivalent /// </summary> /// <param name="context">The database context</param> /// <param name="srlRace">The srl race</param> /// <returns>Returns the persisted race</returns> private static Race?SyncRace( DatabaseContext context , SRLRace srlRace ) { Logger.Info($"({srlRace.Id}) Synchronizing..."); Game g = SyncGame(context, srlRace); if (srlRace.State == SRLApiClient.Endpoints.RaceState.Over && context.GetRace(srlRace.Id) == null) { Logger.Info($"({srlRace.Id}) Race over and not persisted, continuing."); return(null); } Race?race = srlRace.Convert(g); race = context.AddOrUpdate(race); if (race != null) { race.ConsecutiveUpdateFailures = 0; SyncEntrants(context, srlRace, race); } return(race); }
/// <summary> /// Updates the existing or adss a new game entity based on the /// <paramref name="srlRace"/> /// </summary> /// <param name="context">The database context</param> /// <param name="srlRace">The SRL race</param> /// <returns>The updated game entity</returns> private static Game SyncGame( DatabaseContext context , SRLRace srlRace) { Game game = srlRace.Game.Convert(); return(context.AddOrUpdate(game)); }
/// <summary> /// Creates/updates and activates a guild /// </summary> /// <param name="context">The database context</param> /// <param name="guild">The guild</param> /// <returns>Returns the updated guild</returns> public static Guild EnableGuild( DatabaseContext context , SocketGuild guild) => context.AddOrUpdate( new Guild( guild.Id , guild.Name) { IsActive = true });
/// <summary> /// Creates/updates and activates a channel /// </summary> /// <param name="context">The database context</param> /// <param name="channel">The channel</param> /// <returns>Returns the updated guild</returns> public static Channel EnableChannel( DatabaseContext context , SocketTextChannel channel) => context.AddOrUpdate( new Channel( EnableGuild(context, channel.Guild) , channel.Id , channel.Name) { IsActive = true });
/// <summary> /// Updates existing, adds new and deletes removed entrants from /// the <paramref name="race"/> entity /// </summary> /// <param name="context">The database context</param> /// <param name="srlRace">The SRL race</param> /// <param name="race">The race entity</param> private static void SyncEntrants (DatabaseContext context , SRLRace srlRace , Race race) { foreach (SRLApiClient.Endpoints.Races.Entrant entrant in srlRace.Entrants) { context.AddOrUpdate(entrant.Convert(race)); } UpdateRemovedEntrants(context, srlRace, race); race.EntrantCount = srlRace.Entrants.Count; }
/// <summary> /// Adds a tracker or updates it if it's already present in the current guild /// </summary> /// <param name="message">The request message</param> /// <param name="discordService">The discord service</param> /// <param name="context">The database context</param> /// <param name="args">The command arguments</param> private static async Task AddTrackerAsync( SocketMessage message, DiscordService discordService, DatabaseContext context, string[] args ) { if (args.Length != 4) { Logger.Error("Invalid command pattern"); await discordService.ReplyAsync(message, "Invalid command pattern. Command usage: track <srl abbreviation> <channel mention>").ConfigureAwait(false); return; } if (message.MentionedChannels.Count != 1) { await discordService.ReplyAsync(message, "No channel specified! Command usage: track <srl abbreviation> <channel mention>").ConfigureAwait(false); return; } Game?game = context.GetGame(args[2]); if (game == null) { await discordService.ReplyAsync(message, $"Game abbreviation '{args[2]}' not found").ConfigureAwait(false); return; } SocketGuildChannel mentionedChannel = message.MentionedChannels.First(); Channel? channel = context.GetChannel(mentionedChannel.Id); if (channel == null) { await discordService.ReplyAsync(message, "Channel not registered yet, please try again later.").ConfigureAwait(false); return; } if (!channel.Guild.Snowflake.Equals(mentionedChannel.Guild.Id) || !channel.IsActive) { await discordService.ReplyAsync(message, "Channel not found.").ConfigureAwait(false); return; } if (discordService.HasRequiredPermissions(channel.Guild.Snowflake, channel.Snowflake) != true) { await discordService.ReplyAsync(message, $"Missing permissions in channel #{mentionedChannel.Name}").ConfigureAwait(false); return; } Tracker?tracker = context.GetActiveTracker(game, channel.Guild); if (tracker != null) { tracker.Channel = channel; tracker.State = TrackerState.Active; } else { tracker = new Tracker(channel, game) { State = TrackerState.Active }; context.AddOrUpdate(tracker); } context.SaveChanges(); await discordService.ReplyAsync(message, $"{game.Abbreviation} is now being tracked in {channel.DisplayName}").ConfigureAwait(false); }
/// <summary> /// Creates and updates announcements for the specified <paramref name="races"/> /// if an active tracker is found /// </summary> /// <param name="context">The database context</param> /// <param name="discordService">The discord service</param> /// <param name="races">The races</param> public static async Task UpdateAnnouncementsAsync( DatabaseContext context , DiscordService discordService , List <Race> races) { foreach (Race race in races) { foreach (Tracker tracker in context.GetActiveTrackers(race.Game)) { Logger.Info($"({race.SrlId}) Updating tracker {tracker.Id}"); Announcement?announcement = context.GetAnnouncement(race, tracker); try { if (discordService.HasRequiredPermissions(tracker.Channel.Guild.Snowflake, announcement?.Channel?.Snowflake ?? tracker.Channel.Snowflake) != true) { Logger.Error($"Missing permissions in channel {tracker.ChannelId}: {tracker.Channel.Guild.DisplayName}/{tracker.Channel.DisplayName}"); continue; } } catch (Exception ex) { Logger.Error($"({announcement?.Race?.SrlId}) Exception thrown:", ex); continue; } List <Entrant> entrants = new List <Entrant>(); foreach (Entrant e in context.GetEntrants(race)) { if (context.Entry(e).State != EntityState.Deleted) { entrants.Add(e); } } if ( announcement == null && race.State < SRLApiClient.Endpoints.RaceState.Finished && race.State != SRLApiClient.Endpoints.RaceState.Unknown ) { DateTime controlRange = DateTime.UtcNow.Subtract(TimeSpan.FromDays(7)); using DatabaseContext altContext = new ContextBuilder().CreateDbContext(); Race?persistedRace = await altContext .Races .AsQueryable() .FirstOrDefaultAsync(r => r .SrlId.Equals(race.SrlId, StringComparison.CurrentCultureIgnoreCase) && r.CreatedAt > controlRange) .ConfigureAwait(false); if (persistedRace != null) { // If a race with the same id was registered within the last week, skip announcement Logger.Info($"({race.SrlId}) Persisted race found: {persistedRace.Id}/{persistedRace.SrlId}. Skipping announcement!"); } else { announcement = await PostAnnouncementAsync(discordService, tracker, race, entrants).ConfigureAwait(false); if (announcement != null) { context.AddOrUpdate(announcement); } } } else if (announcement != null) { await UpdateAnnouncementAsync(discordService, announcement, entrants).ConfigureAwait(false); } } } }