Inital bot commit

This commit is contained in:
Karolis2011
2019-06-18 19:17:06 +03:00
commit 81a82cbb5b
25 changed files with 1346 additions and 0 deletions

View File

@@ -0,0 +1,84 @@
using Discord;
using Discord.Commands;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Linq;
using EventBot.Attributes;
using EventBot.Services;
namespace EventBot.Modules
{
public class BasicModule : ModuleBase<SocketCommandContext>
{
private readonly DatabaseService _database;
public BasicModule(DatabaseService database)
{
_database = database;
}
[RequireUserPermission(GuildPermission.Administrator, Group = "Permission")]
[RequireOwner(Group = "Permission")]
[RequireContext(ContextType.Guild)]
[Command("prefix")]
[Summary("Gets prefix.")]
public async Task PrefixCommand()
{
var guildConfig = _database.GuildConfigs.FirstOrDefault(g => g.GuildId == Context.Guild.Id);
if (guildConfig == null)
throw new Exception("No guild config was foumd.");
if(guildConfig.Prefix != null)
await ReplyAsync($"Current prefix is `{guildConfig.Prefix}`");
else
await ReplyAsync($"There is no prefix set for this guild.");
}
[RequireUserPermission(GuildPermission.Administrator, Group = "Permission")]
[RequireOwner(Group = "Permission")]
[RequireContext(ContextType.Guild)]
[Command("prefix")]
[Summary("Sets prefix.")]
public async Task PrefixCommand(
[Summary("New prefix to set")] string newPrefix)
{
var guildConfig = _database.GuildConfigs.FirstOrDefault(g => g.GuildId == Context.Guild.Id);
if (guildConfig == null)
throw new Exception("No guild config was foumd.");
guildConfig.Prefix = newPrefix;
await _database.SaveChangesAsync();
await ReplyAsync($"Prefix has been set to `{guildConfig.Prefix}`");
}
[Group("help")]
public class HelpModule : ModuleBase<SocketCommandContext>
{
private readonly CommandService _commands;
public HelpModule(CommandService commands)
{
_commands = commands;
}
[Command]
[Summary("Lists all commands with there descriptions.")]
public async Task DefaultHelpAsync()
{
var embed = new EmbedBuilder()
.WithTitle("Command list")
.WithColor(Color.DarkBlue)
.WithCurrentTimestamp()
.WithFields(_commands.Commands
.Where(c => c.Attributes.Where(a => a is NoHelpAttribute || (a is RequireContextAttribute requireContext)).Count() == 0)
.Select(c =>
new EmbedFieldBuilder()
{
Name = $"`{string.Join(", ", c.Aliases)} {string.Join(" ", c.Parameters.Select(p => p.IsOptional ? $"[{p.Name}]" : $"<{p.Name}>"))}`",
Value = c.Summary
})
);
await Context.User.SendMessageAsync(embed: embed.Build());
}
}
}
}

View File

@@ -0,0 +1,413 @@
using Discord;
using Discord.Commands;
using EventBot.Services;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Linq;
using EventBot.Entities;
using Discord.WebSocket;
using NeoSmart.Unicode;
namespace EventBot.Modules
{
[RequireContext(ContextType.Guild)]
public class EventModule : ModuleBase<SocketCommandContext>
{
private readonly EventManagementService _events;
private readonly DatabaseService _database;
public EventModule(EventManagementService events, DatabaseService database)
{
_events = events;
_database = database;
}
[Command("join")]
[Summary("Joins latest or specified event with specified event role.")]
public async Task JoinAsync(
[Summary("Role emote or role id to join.")] string emoteOrId,
[Summary("Extra information that migth be needed by organizers.")] string extraInformation = null,
[Summary("Optional event ID for joining event that is not most recent one.")] Event @event = null)
{
EventRole er;
if (!(Context.User is SocketGuildUser guildUser))
throw new Exception("This command must be executed inside guild.");
if (@event == null)
@event = _events.FindEventBy(Context.Guild);
if (@event == null & !(int.TryParse(emoteOrId, out int roleId)))
throw new Exception("Unable to locate any events for this guild.");
else if (@event == null)
er = _database.EventRoles.FirstOrDefault(r => r.Id == roleId);
else
er = @event.Roles.FirstOrDefault(r => r.Emote == emoteOrId);
if (er == null)
throw new ArgumentException("Invalid emote or event id specified");
if (@event.MessageId == 0)
throw new Exception("You can't join not opened event.");
await _events.TryJoinEvent(guildUser, er, extraInformation);
await Context.Message.DeleteAsync(); // Protect somewhat sensitive data.
}
[RequireUserPermission(GuildPermission.Administrator, Group = "Permission")]
[RequireOwner(Group = "Permission")]
[Group("event")]
public class EventManagementModule : ModuleBase<SocketCommandContext>
{
private readonly EventManagementService _events;
private readonly DatabaseService _database;
private readonly EmoteService _emotes;
public EventManagementModule(EventManagementService events, DatabaseService database, EmoteService emotes)
{
_events = events;
_database = database;
_emotes = emotes;
}
[Command("config logchannel")]
[Summary("Sets logging channel for role changes.")]
public async Task SetRoleChannelAsync(
[Summary("Channel to use for logging.")] IChannel channel)
{
var guild = _database.GuildConfigs.FirstOrDefault(g => g.GuildId == Context.Guild.Id);
if (guild == null)
throw new Exception("This command must be executed inside guild.");
guild.EventRoleConfirmationChannelId = channel.Id;
var s = _database.SaveChangesAsync();
await ReplyAsync($"Event role changes now will be logged to `{channel.Name}` channel.");
await s;
}
[Command("config partrole")]
[Summary("Sets role to assign when they selelct role.")]
public async Task SetParticipationRole(
[Summary("Role to assign.")] IRole role)
{
var guild = _database.GuildConfigs.FirstOrDefault(g => g.GuildId == Context.Guild.Id);
if (guild == null)
throw new Exception("This command must be executed inside guild.");
guild.ParticipantRoleId = role.Id;
var s = _database.SaveChangesAsync();
await ReplyAsync($"Event participants will be given `{role.Name}` role.");
await s;
}
[Command("new")]
[Summary("Creates new event.")]
public async Task NewEvent(
[Summary("Title for the event.")] string title,
[Summary("Description for the event.")] string description,
[Summary("Type of event registration.")] Event.EventParticipactionType type = Event.EventParticipactionType.Quick)
{
var guild = _database.GuildConfigs.FirstOrDefault(g => g.GuildId == Context.Guild.Id);
if (guild == null)
throw new Exception("This command must be executed inside guild.");
var @event = new Event()
{
Title = title,
Description = description,
Type = type,
Guild = guild
};
_database.Add(@event);
await _database.SaveChangesAsync();
await ReplyAsync($"Created new {@event.Type} event `{title}`, with description of `{description}`. It's ID is `{@event.Id}`.");
}
[Command("update title")]
[Summary("Updates event title.")]
public async Task UpdateEventTitle(
[Summary("Title for the event.")] string title,
[Summary("Event to update, if not specified, updates latest event.")] Event @event = null)
{
if (@event == null)
@event = _events.FindEventBy(Context.Guild);
if (@event == null)
throw new Exception("Unable to locate any events for this guild.");
@event.Title = title;
await _database.SaveChangesAsync();
await ReplyAsync($"Updated event(`{@event.Id}`) title to `{@event.Title}`");
await _events.UpdateEventMessage(@event);
}
[Command("update description")]
[Summary("Updates event description.")]
public async Task UpdateEventDescription(
[Summary("Description for the event.")] string description,
[Summary("Event to update, if not specified, updates latest event.")] Event @event = null)
{
if (@event == null)
@event = _events.FindEventBy(Context.Guild);
if (@event == null)
throw new Exception("Unable to locate any events for this guild.");
@event.Description = description;
await _database.SaveChangesAsync();
await ReplyAsync($"Updated event(`{@event.Id}`) description to `{@event.Description}`");
await _events.UpdateEventMessage(@event);
}
[Command("update type")]
[Summary("Updates event type.")]
public async Task UpdateEventType(
[Summary("Type of event registration.")] Event.EventParticipactionType type,
[Summary("Event to update, if not specified, updates latest event.")] Event @event = null)
{
if (type == Event.EventParticipactionType.Unspecified)
return;
if (@event == null)
@event = _events.FindEventBy(Context.Guild);
if (@event == null)
throw new Exception("Unable to locate any events for this guild.");
if (@event.MessageId != 0 && @event.Type != type)
throw new Exception("Can't change event registration type when it's open for registration. Maube you meant to set type to `Unspecified` (-1)");
if(@event.Type != type)
@event.Type = type;
await _database.SaveChangesAsync();
await ReplyAsync($"Updated event(`{@event.Id}`) type to `{@event.Type}`");
}
[Command("role new")]
[Summary("Adds new role to the event.")]
public async Task NewEventRole(
[Summary("Title for the role.")] string title,
[Summary("Description for the role.")] string description,
[Summary("Emote for the role.")] string emote,
[Summary("Max openings, if number is negative, opening count is unlimited.")] int maxOpenings = -1,
[Summary("Event to that role is meant for.")] Event @event = null)
{
if (@event == null)
@event = _events.FindEventBy(Context.Guild);
if (@event == null)
throw new Exception("Unable to locate any events for this guild.");
if(@event.Roles != null && @event.Roles.Count >= 20)
throw new Exception("There are too many roles for this event.");
if(@event.MessageId != 0)
throw new Exception("Can't add new roles to event with open reigstration.");
if (!_emotes.TryParse(emote, out IEmote parsedEmote))
throw new ArgumentException("Invalid emote provided.");
if(@event.Roles != null && @event.Roles.Count(r => r.Emote == parsedEmote.ToString()) > 0)
throw new ArgumentException("This emote is already used by other role.");
var er = new EventRole()
{
Title = title,
Description = description,
MaxParticipants = maxOpenings,
Emote = parsedEmote.ToString(),
Event = @event
};
_database.Add(er);
await _database.SaveChangesAsync();
await ReplyAsync($"Added event role `{er.Id}` for event `{er.Event.Id}`, title: `{er.Title}`, description: `{er.Description}`, maxPart: `{er.MaxParticipants}`, emote: {er.Emote}");
}
[Command("role update title")]
[Summary("Updates role's title")]
public async Task UpdateEventRoleTitle(
[Summary("Role witch to update.")] EventRole eventRole,
[Summary("New title for role.")][Remainder] string title)
{
if(eventRole == null)
throw new Exception("Please provide correct role.");
eventRole.Title = title;
var s = _database.SaveChangesAsync();
await ReplyAsync($"Updated event role `{eventRole.Id}` title to `{eventRole.Title}`");
await s;
await _events.UpdateEventMessage(eventRole.Event);
}
[Command("role update desc")]
[Summary("Updates role's description.")]
public async Task UpdateEventRoleDescription(
[Summary("Role witch to update.")] EventRole eventRole,
[Summary("New description for role.")][Remainder] string description)
{
if (eventRole == null)
throw new Exception("Please provide correct role.");
eventRole.Description = description;
var s = _database.SaveChangesAsync();
await ReplyAsync($"Updated event role `{eventRole.Id}` description to `{eventRole.Description}`");
await s;
await _events.UpdateEventMessage(eventRole.Event);
}
[Command("role update slots")]
[Summary("Updates role's maximum participants count.")]
public async Task UpdateEventRoleMaxParticipants(
[Summary("Role witch to update.")] EventRole eventRole,
[Summary("New maximum participant count for role.")] int maxParticipants)
{
if (eventRole == null)
throw new Exception("Please provide correct role.");
eventRole.MaxParticipants = maxParticipants;
var s = _database.SaveChangesAsync();
await ReplyAsync($"Updated event role `{eventRole.Id}` maximum participant count to `{eventRole.MaxParticipants}`");
await s;
await _events.UpdateEventMessage(eventRole.Event);
}
[Command("role update emote")]
[Summary("Updates role's emote.")]
public async Task UpdateEventRoleEmote(
[Summary("Role witch to update.")] EventRole eventRole,
[Summary("New emote for the role.")] string emote)
{
if (eventRole == null)
throw new Exception("Please provide correct role.");
if (!_emotes.TryParse(emote, out IEmote parsedEmote))
throw new ArgumentException("Invalid emote provided.");
if (eventRole.Event.Roles.Count(r => r.Emote == parsedEmote.ToString()) > 0)
throw new ArgumentException("This emote is already used by other role.");
eventRole.Emote = parsedEmote.ToString();
var s = _database.SaveChangesAsync();
await ReplyAsync($"Updated event role `{eventRole.Id}` emote to {eventRole.Emote}");
await s;
}
[Command()]
[Summary("Get info about event.")]
public async Task EventInfo(
[Summary("Event about witch info is wanted.")] Event @event = null)
{
if (@event == null)
@event = _events.FindEventBy(Context.Guild);
if (@event == null)
throw new Exception("No events were found for this guild.");
var embed = new EmbedBuilder()
.WithTitle(@event.Title)
.WithDescription(@event.Description)
.WithTimestamp(@event.Opened)
.WithFooter($"EventId: {@event.Id}; MessageId: {@event.MessageId}; MessageChannelId: {@event.MessageChannelId}")
.AddField("Active", @event.Active ? "Yes" : "No", true)
.AddField("Type", @event.Type, true)
.AddField("Participants", @event.ParticipantCount, true);
if (@event.Roles != null)
embed.WithFields(@event.Roles.OrderBy(e => e.SortNumber).Select(r => new EmbedFieldBuilder()
.WithName($"Id: `{r.Id}` {r.Emote} `{r.Title}` - {r.ParticipantCount} participants; {(r.MaxParticipants < 0 ? "infinite" : r.MaxParticipants.ToString())} max slots.")
.WithValue(r.ParticipantCount == 0 ? "There are no participants" : string.Join("\r\n", r.Participants
.Select(p => new { Participant = p, User = Context.Guild.GetUser(p.UserId) })
.OrderBy(o => o.User.ToString())
.Select(o => $"{o.User}{(o.Participant.UserData != null ? $" - `{o.Participant.UserData}`" : "")}")
))
));
await ReplyAsync(embed: embed.Build());
}
[Priority(1)]
[Command("role")]
[Summary("Gets role info.")]
public async Task EventRoleInfo(
[Summary("Role about witch info is wanted.")] EventRole eventRole)
{
if (eventRole == null)
throw new Exception("Please provide correct role.");
var embed = new EmbedBuilder()
.WithTitle($"{eventRole.Emote} {eventRole.Title}")
.WithDescription($"{eventRole.Description}")
.WithFooter($"EventRoleId: {eventRole.Id}, EventId: {eventRole.Event.Id}")
.AddField("Max participants", eventRole.MaxParticipants < 0 ? "infinite" : eventRole.MaxParticipants.ToString(), true)
.AddField("Participants", eventRole.ParticipantCount, true);
var msg = await ReplyAsync(embed: embed.Build());
if (eventRole.Participants != null && eventRole.Participants.Count > 0)
{
embed.AddField("Participants", string.Join("\r\n", eventRole.Participants.Select(p => $"id: `{p.Id}` <@{p.UserId}>{(p.UserData != null ? $" - {p.UserData}" : "")}")));
await msg.ModifyAsync(m => m.Embed = embed.Build());
}
}
[Command("open")]
[Summary("Open registration for event here.")]
public async Task EventOpen(
[Summary("Event to open")] Event @event = null)
{
if (@event == null)
@event = _events.FindEventBy(Context.Guild);
if (@event == null)
throw new Exception("No events were found for this guild.");
await Context.Message.DeleteAsync();
var message = await ReplyAsync(embed: _events.GenerateEventEmbed(@event).Build());
@event.MessageId = message.Id;
@event.MessageChannelId = message.Channel.Id;
await _database.SaveChangesAsync();
switch (@event.Type)
{
case Event.EventParticipactionType.Unspecified:
throw new Exception("Event type was unspecified.");
case Event.EventParticipactionType.Quick:
await message.AddReactionsAsync(@event.Roles.OrderBy(e => e.SortNumber).Select(r => _emotes.Parse(r.Emote)).ToArray());
break;
case Event.EventParticipactionType.Detailed:
break;
default:
throw new Exception("Event type in not implemented.");
}
}
[Command("participant add")]
[Summary("Add user to event role. Acts like join command.")]
public async Task EventParticipantAdd(
[Summary("User id or mention")] IUser user,
[Summary("Role emote or role id to join.")] string emoteOrId,
[Summary("Extra information that migth be needed by organizers.")] string extraInformation = null,
[Summary("Optional event ID for joining event that is not most recent one.")] Event @event = null)
{
EventRole er;
if (!(user is SocketGuildUser guildUser))
throw new Exception("This command must be executed inside guild.");
if (@event == null)
@event = _events.FindEventBy(Context.Guild);
if (@event == null & !(int.TryParse(emoteOrId, out int roleId)))
throw new Exception("Unable to locate any events for this guild.");
else if (@event == null)
er = _database.EventRoles.FirstOrDefault(r => r.Id == roleId);
else
er = @event.Roles.FirstOrDefault(r => r.Emote == emoteOrId);
if (er == null)
throw new ArgumentException("Invalid emote or event id specified");
await _events.TryJoinEvent(guildUser, er, extraInformation, false);
await Context.Message.DeleteAsync(); // Protect somewhat sensitive data.
}
[Command("participant remove")]
[Summary("Remove participant from event role.")]
public async Task EventParticipantRemove(
[Summary("User that is participanting id or mention")] IUser user,
[Summary("Event to romove participant from")] Event @event = null)
{
if (@event == null)
@event = _events.FindEventBy(Context.Guild);
if (@event == null)
throw new Exception("No events were found for this guild.");
if (!(user is IGuildUser guildUser))
throw new Exception("This command must be executed inside guild.");
var participant = @event.Participants.FirstOrDefault(p => p.UserId == guildUser.Id);
_database.Remove(participant);
var embed = new EmbedBuilder()
.WithTitle($"{user} been removed from event `{@event.Title}`, by {Context.User}")
.WithDescription($"They were in `{participant.Role.Title}` role")
.WithColor(Color.Red);
if (participant.UserData != null)
embed.AddField("Provided details", $"`{participant.UserData}`");
await _database.SaveChangesAsync();
await _events.UpdateEventMessage(@event);
if (@event.Guild.EventRoleConfirmationChannelId != 0)
await (await ((IGuild)Context.Guild).GetTextChannelAsync(@event.Guild.EventRoleConfirmationChannelId)).SendMessageAsync(embed: embed.Build());
if (@event.Guild.ParticipantRoleId != 0)
await guildUser.RemoveRoleAsync(Context.Guild.GetRole(@event.Guild.ParticipantRoleId));
}
}
}
}

View File

@@ -0,0 +1,18 @@
using Discord.Commands;
using EventBot.Attributes;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace EventBot.Modules
{
public class TestingModule: ModuleBase<SocketCommandContext>
{
[Command("ping")]
[Summary("Test if bot is working.")]
[NoHelp]
public Task SayAsync()
=> ReplyAsync("Pong!");
}
}