public override Task <PreconditionResult> CheckPermissionsAsync( ICommandContext context, CommandInfo command, IServiceProvider serviceProvider) { Verify.IsNotNull(context, nameof(context)); GlobalTournamentsManager globalManager = serviceProvider.GetService <GlobalTournamentsManager>(); TournamentsManager manager = globalManager.GetOrAdd(context.Guild.Id, CreateTournamentsManager); // TD is only allowed to run commands when they are a director of the current tournament. Result <bool> result = manager.TryReadActionOnCurrentTournament(currentTournament => currentTournament.GuildId == context.Guild.Id && CanActAsTournamentDirector(context, currentTournament) ); if (result.Success && result.Value) { return(Task.FromResult(PreconditionResult.FromSuccess())); } else if (command.Name == SetupCommandName && context.Message.Content.Length > SetupCommand.Length) { // TODO: We should investigate if there's a better place to make this check, because the attribute // now knows about "setup" string tournamentName = context.Message.Content.Substring(SetupCommand.Length).Trim(); if (IsAdminUser(context) || (manager.TryGetTournament(tournamentName, out ITournamentState tournament) && CanActAsTournamentDirector(context, tournament))) { return(Task.FromResult(PreconditionResult.FromSuccess())); } } return(Task.FromResult(PreconditionResult.FromError("User did not have tournament director privileges."))); }
public async Task AddTwoTournamentDirectors() { const ulong firstUserId = 123; const ulong secondUserId = 1234; MessageStore messageStore = new MessageStore(); ICommandContext context = this.CreateCommandContext(messageStore); GlobalTournamentsManager globalManager = new GlobalTournamentsManager(); AddTournamentDirectorDirectly(globalManager, firstUserId); BotCommandHandler commandHandler = new BotCommandHandler(context, globalManager); IGuildUser guildUser = this.CreateGuildUser(secondUserId); await commandHandler.AddTournamentDirectorAsync(guildUser, DefaultTournamentName); string expectedMessage = BotStrings.AddTournamentDirectorSuccessful( DefaultTournamentName, DefaultGuildName); messageStore.VerifyChannelMessages(expectedMessage); TournamentsManager manager = globalManager.GetOrAdd(DefaultGuildId, id => new TournamentsManager()); Assert.IsTrue( manager.TryGetTournament(DefaultTournamentName, out ITournamentState state), "Could not find tournament."); Assert.IsTrue(state.IsDirector(firstUserId), "First director was not added."); Assert.IsTrue(state.IsDirector(secondUserId), "Second director was not added."); }
public Bot(BotConfiguration configuration) { DiscordSocketConfig clientConfig = new DiscordSocketConfig() { // 16 kb? MessageCacheSize = 1024 * 16 }; this.Client = new DiscordSocketClient(clientConfig); this.Configuration = configuration; this.CommandService = new CommandService(new CommandServiceConfig() { CaseSensitiveCommands = false, LogLevel = LogSeverity.Info }); this.Logger = Log.ForContext(this.GetType()); GlobalTournamentsManager globalManager = new GlobalTournamentsManager(); IServiceCollection serviceCollection = new ServiceCollection(); serviceCollection.AddSingleton(this.Client); serviceCollection.AddSingleton(globalManager); serviceCollection.AddSingleton(this.Configuration); this.ServiceProvider = serviceCollection.BuildServiceProvider(); this.EventHandler = new BotEventHandler(this.Client, globalManager); // TODO: If we want to split up BotCommands, use Assembly.GetEntryAssembly. Task.WaitAll(this.CommandService.AddModulesAsync(Assembly.GetExecutingAssembly(), this.ServiceProvider)); }
public async Task ScheduleRequiresMultipleEmbeds() { const int teamsCount = 50; const int readersCount = teamsCount / 2; MessageStore messageStore = new MessageStore(); ICommandContext context = this.CreateCommandContext(messageStore, guildId: DefaultGuildId); GlobalTournamentsManager globalManager = new GlobalTournamentsManager(); TournamentsManager manager = globalManager.GetOrAdd(DefaultGuildId, id => new TournamentsManager()); HashSet <Team> teams = new HashSet <Team>( Enumerable.Range(1, teamsCount).Select(id => new Team() { Name = $"#Team{id}" })); HashSet <Reader> readers = new HashSet <Reader>( Enumerable.Range(1, readersCount).Select(id => new Reader() { Id = (ulong)id, Name = $"#Reader{id}" })); RoundRobinScheduleFactory factory = new RoundRobinScheduleFactory(1, 0); Schedule schedule = factory.Generate(teams, readers); ITournamentState state = new TournamentState(DefaultGuildId, "T"); state.Schedule = schedule; manager.AddOrUpdateTournament(state.Name, state, (name, oldState) => oldState); Assert.IsTrue( manager.TrySetCurrentTournament(state.Name, out string errorMessage), $"Failed to set the tournament: '{errorMessage}'"); globalManager.GetOrAdd(DefaultGuildId, id => manager); BotCommandHandler commandHandler = new BotCommandHandler(context, globalManager); await commandHandler.GetScheduleAsync(); Assert.IsTrue( messageStore.ChannelEmbeds.Count > 1, $"Expected more than 1 embed, got {messageStore.ChannelEmbeds.Count}"); string allEmbeds = string.Join('\n', messageStore.ChannelEmbeds); for (int round = 0; round < schedule.Rounds.Count; round++) { Assert.IsTrue( allEmbeds.Contains(BotStrings.RoundNumber(round + 1)), $"Round {round + 1} not found in the embeds. Embeds: '{allEmbeds}'"); foreach (Game game in schedule.Rounds[round].Games) { string expectedGame = BotStrings.ScheduleLine( game.Reader.Name, game.Teams.Select(team => team.Name).ToArray()); Assert.IsTrue( allEmbeds.Contains(expectedGame), $"Game '{expectedGame}' not foudn in embed. Embed: '{allEmbeds}'"); } } }
public BotCommandHandler(ICommandContext context, GlobalTournamentsManager globalManager) { Verify.IsNotNull(context, nameof(context)); Verify.IsNotNull(globalManager, nameof(globalManager)); this.ChannelManager = new TournamentChannelManager(context.Guild); this.Context = context; this.GlobalManager = globalManager; this.Logger = Log .ForContext <BotCommandHandler>() .ForContext("guildId", this.Context.Guild?.Id); }
public async Task NoCurrentTournament() { MessageStore messageStore = new MessageStore(); ICommandContext context = this.CreateCommandContext(messageStore); GlobalTournamentsManager globalManager = new GlobalTournamentsManager(); BotCommandHandler commandHandler = new BotCommandHandler(context, globalManager); await commandHandler.GetCurrentTournamentAsync(); string expectedMessage = BotStrings.UnableToPerformCommand(TournamentStrings.NoCurrentTournamentRunning); messageStore.VerifyDirectMessages(expectedMessage); }
// TODO: Add wrapper class/interface for the client to let us test the event handlers. // The events themselves pass in SocketMessages, so perhaps grab some fields and abstract the logic. Let's do a // straight transfer first. public BotEventHandler(DiscordSocketClient client, GlobalTournamentsManager globalManager) { Verify.IsNotNull(client, nameof(client)); this.IsDisposed = false; this.Client = client; this.GlobalManager = globalManager; this.Client.MessageReceived += this.OnMessageReceived; this.Client.ReactionAdded += this.OnReactionAdded; this.Client.ReactionRemoved += this.OnReactionRemoved; this.Logger = Log.ForContext <BotEventHandler>(); }
protected ITournamentState AddCurrentTournament( GlobalTournamentsManager globalManager, ulong guildId = DefaultGuildId, string tournamentName = DefaultTournamentName) { TournamentsManager manager = globalManager.GetOrAdd(guildId, id => new TournamentsManager()); ITournamentState state = new TournamentState(guildId, tournamentName); state = manager.AddOrUpdateTournament(tournamentName, state, (name, oldState) => state); Assert.IsTrue( manager.TrySetCurrentTournament(tournamentName, out string errorMessage), "We should be able to set the current tournament."); return(state); }
public async Task GetCurrentTournament() { MessageStore messageStore = new MessageStore(); ICommandContext context = this.CreateCommandContext(messageStore); GlobalTournamentsManager globalManager = new GlobalTournamentsManager(); this.AddCurrentTournament(globalManager); BotCommandHandler commandHandler = new BotCommandHandler(context, globalManager); await commandHandler.GetCurrentTournamentAsync(); string expectedMessage = BotStrings.CurrentTournamentInGuild(DefaultGuildName, DefaultTournamentName); messageStore.VerifyDirectMessages(expectedMessage); }
// TODO: Add test for ClearAll that checks that all artifacts are cleared. private static void AddTournamentDirectorDirectly(GlobalTournamentsManager globalManager, ulong userId) { TournamentsManager manager = globalManager.GetOrAdd( DefaultGuildId, id => new TournamentsManager() { GuildId = id }); ITournamentState state = manager.AddOrUpdateTournament( DefaultTournamentName, new TournamentState(DefaultGuildId, DefaultTournamentName), (name, oldState) => oldState); Assert.IsTrue(state.TryAddDirector(userId), "First TD added should occur."); }
public async Task RemoveFromNonexistentTournament() { const ulong otherId = DefaultUserId + 1; MessageStore messageStore = new MessageStore(); ICommandContext context = this.CreateCommandContext(messageStore); GlobalTournamentsManager globalManager = new GlobalTournamentsManager(); BotCommandHandler commandHandler = new BotCommandHandler(context, globalManager); IGuildUser guildUser = this.CreateGuildUser(otherId); await commandHandler.RemoveTournamentDirectorAsync(guildUser, DefaultTournamentName); string expectedMessage = BotStrings.TournamentDoesNotExist(DefaultTournamentName, DefaultGuildName); messageStore.VerifyChannelMessages(expectedMessage); }
public async Task RemoveNonexistentTournamentDirector() { const ulong otherId = DefaultUserId + 1; MessageStore messageStore = new MessageStore(); ICommandContext context = this.CreateCommandContext(messageStore); GlobalTournamentsManager globalManager = new GlobalTournamentsManager(); BotCommandHandler commandHandler = new BotCommandHandler(context, globalManager); AddTournamentDirectorDirectly(globalManager, DefaultUserId); IGuildUser guildUser = this.CreateGuildUser(otherId); await commandHandler.RemoveTournamentDirectorAsync(guildUser, DefaultTournamentName); string expectedMessage = BotStrings.UserNotTournamentDirector(DefaultTournamentName, DefaultGuildName); messageStore.VerifyChannelMessages(expectedMessage); TournamentsManager manager = globalManager.GetOrAdd(DefaultGuildId, id => new TournamentsManager()); Assert.IsTrue( manager.TryGetTournament(DefaultTournamentName, out ITournamentState state), "Could not find tournament."); Assert.IsFalse(state.IsDirector(otherId), "Director should not have been added."); }
public async Task AddSameTournamentDirectors() { MessageStore messageStore = new MessageStore(); ICommandContext context = this.CreateCommandContext(messageStore); GlobalTournamentsManager globalManager = new GlobalTournamentsManager(); AddTournamentDirectorDirectly(globalManager, DefaultUserId); BotCommandHandler commandHandler = new BotCommandHandler(context, globalManager); IGuildUser guildUser = this.CreateGuildUser(DefaultUserId); await commandHandler.AddTournamentDirectorAsync(guildUser, DefaultTournamentName); string expectedMessage = BotStrings.UserAlreadyTournamentDirector(DefaultTournamentName, DefaultGuildName); messageStore.VerifyChannelMessages(expectedMessage); TournamentsManager manager = globalManager.GetOrAdd(DefaultGuildId, id => new TournamentsManager()); Assert.IsTrue( manager.TryGetTournament(DefaultTournamentName, out ITournamentState state), "Could not find tournament."); Assert.IsTrue(state.IsDirector(DefaultUserId), "User should still be a director."); }
public TournamentDirectorBotCommands(GlobalTournamentsManager globalManager) : base(globalManager) { }
public async Task SimplestSchedule() { const string readerName = "#Reader"; const string firstTeamName = "#TeamA"; const string secondTeamName = "#TeamB"; MessageStore messageStore = new MessageStore(); ICommandContext context = this.CreateCommandContext(messageStore, guildId: DefaultGuildId); GlobalTournamentsManager globalManager = new GlobalTournamentsManager(); TournamentsManager manager = globalManager.GetOrAdd(DefaultGuildId, id => new TournamentsManager()); HashSet <Team> teams = new HashSet <Team>() { new Team() { Name = firstTeamName }, new Team() { Name = secondTeamName } }; HashSet <Reader> readers = new HashSet <Reader>() { new Reader() { Id = 0, Name = readerName } }; RoundRobinScheduleFactory factory = new RoundRobinScheduleFactory(2, 0); Schedule schedule = factory.Generate(teams, readers); ITournamentState state = new TournamentState(DefaultGuildId, "T"); state.Schedule = schedule; manager.AddOrUpdateTournament(state.Name, state, (name, oldState) => oldState); Assert.IsTrue( manager.TrySetCurrentTournament(state.Name, out string errorMessage), $"Failed to set the tournament: '{errorMessage}'"); globalManager.GetOrAdd(DefaultGuildId, id => manager); BotCommandHandler commandHandler = new BotCommandHandler(context, globalManager); await commandHandler.GetScheduleAsync(); Assert.AreEqual(1, messageStore.ChannelEmbeds.Count, "Unexpected number of embeds"); string embed = messageStore.ChannelEmbeds[0]; for (int round = 0; round < schedule.Rounds.Count; round++) { Assert.IsTrue( embed.Contains(BotStrings.RoundNumber(round + 1)), $"Round {round + 1} not found in embed. Embed: '{embed}'"); string expectedGame = BotStrings.ScheduleLine( readerName, schedule.Rounds[round].Games[0].Teams.Select(team => team.Name).ToArray()); Assert.IsTrue( embed.Contains(expectedGame), $"Game '{expectedGame}' not foudn in embed. Embed: '{embed}'"); } }
public GuildBotCommands(GlobalTournamentsManager globalManager) : base(globalManager) { }
public AdminBotCommands(GlobalTournamentsManager globalManager) : base(globalManager) { }
public BotCommandsBase(GlobalTournamentsManager globalManager) { this.GlobalManager = globalManager; this.Logger = Log.ForContext(this.GetType()); }
public GeneralBotCommands(GlobalTournamentsManager globalManager) : base(globalManager) { }