using System; using System.Threading.Tasks; using Discord.Net; using Discord.WebSocket; using static Kerobot.Kerobot; namespace Kerobot.Services.CommonFunctions { /// /// Implements certain common actions that modules may want to perform. Using this service to perform those /// functions may help enforce a sense of consistency across modules when performing common actions, and may /// inform services which provide any additional features the ability to respond to those actions ahead of time. /// /// This is currently an experimental section. If it turns out to not be necessary, this service will be removed and /// modules may resume executing common actions on their own. /// internal class CommonFunctionsService : Service { public CommonFunctionsService(Kerobot kb) : base(kb) { } #region Guild member removal /// /// Common processing for kicks and bans. Called by DoKickAsync and DoBanAsync. /// /// The reason to insert into the Audit Log. internal async Task BanOrKickAsync( RemovalType t, SocketGuild guild, string source, ulong target, int banPurgeDays, string logReason, bool sendDmToTarget) { if (t == RemovalType.None) throw new ArgumentException("Removal type must be 'ban' or 'kick'."); if (string.IsNullOrWhiteSpace(logReason)) logReason = "Reason not specified."; var dmSuccess = true; SocketGuildUser utarget = guild.GetUser(target); // Can't kick without obtaining user object. Quit here. if (t == RemovalType.Kick && utarget == null) return new BanKickResult(null, false, true); #if DEBUG #warning "Services are NOT NOTIFIED" of bans/kicks during debug." #else // TODO notify services here as soon as we get some who will want to listen to this #endif // Send DM notification if (sendDmToTarget) { if (utarget != null) dmSuccess = await BanKickSendNotificationAsync(utarget, t, logReason); else dmSuccess = false; } // Perform the action try { #if DEBUG #warning "Actual kick/ban is DISABLED during debug." #else if (t == RemovalType.Ban) await guild.AddBanAsync(target, banPurgeDays); else await utarget.KickAsync(logReason); // TODO !! Insert ban reason! For kick also: Figure out a way to specify invoker. #endif } catch (HttpException ex) { return new BanKickResult(ex, dmSuccess, false); } return new BanKickResult(null, dmSuccess, false); } private async Task BanKickSendNotificationAsync(SocketGuildUser target, Kerobot.RemovalType action, string reason) { const string DMTemplate = "You have been {0} from {1} for the following reason:\n{2}"; var dch = await target.GetOrCreateDMChannelAsync(); // TODO can this throw an exception? var output = string.Format(DMTemplate, action == RemovalType.Ban ? "banned" : "kicked", target.Guild.Name, reason); try { await dch.SendMessageAsync(output); } catch (HttpException) { return false; } return true; } #endregion } }