From 794816dcee8cb614905ce0100d0c8a2972cd0e6e Mon Sep 17 00:00:00 2001 From: FiniteReality Date: Wed, 21 Jun 2017 17:09:53 +0100 Subject: [PATCH] Fix log pagination, implement some change types I still need to implement a bunch of stuff: - Move IAuditLogOptions into IAuditLogChanges (I initially misunderstood the purpose of options, but now I know) - Implement the rest of the change types - Debug and get API feedback --- ...IAuditLogChange.cs => IAuditLogChanges.cs} | 6 +- .../Entities/AuditLogs/IAuditLogEntry.cs | 6 +- .../API/Common/AuditLogEntry.cs | 2 +- .../API/Rest/GetAuditLogsParams.cs | 2 +- src/Discord.Net.Rest/DiscordRestApiClient.cs | 9 ++- .../Entities/AuditLogs/AuditLogHelper.cs | 67 ++++++++++++++++--- .../AuditLogs/Changes/ChannelDeleteChanges.cs | 40 +++++++++++ .../AuditLogs/Changes/EmoteCreateChanges.cs | 29 ++++++++ .../AuditLogs/Changes/EmoteDeleteChanges.cs | 23 +++++++ .../AuditLogs/Changes/EmoteUpdateChanges.cs | 33 +++++++++ .../AuditLogs/Changes/InviteCreateChanges.cs | 54 +++++++++++++++ .../Changes/MemberRoleAuditLogChange.cs | 19 ------ .../AuditLogs/Changes/MemberRoleChanges.cs | 51 ++++++++++++++ .../AuditLogs/Changes/MemberUpdateChanges.cs | 33 +++++++++ .../Changes/OverwriteDeleteChanges.cs | 45 +++++++++++++ .../Entities/AuditLogs/RestAuditLogEntry.cs | 39 ++++++----- .../Entities/Guilds/GuildHelper.cs | 4 +- 17 files changed, 401 insertions(+), 61 deletions(-) rename src/Discord.Net.Core/Entities/AuditLogs/{IAuditLogChange.cs => IAuditLogChanges.cs} (83%) create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/Changes/ChannelDeleteChanges.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/Changes/EmoteCreateChanges.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/Changes/EmoteDeleteChanges.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/Changes/EmoteUpdateChanges.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/Changes/InviteCreateChanges.cs delete mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/Changes/MemberRoleAuditLogChange.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/Changes/MemberRoleChanges.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/Changes/MemberUpdateChanges.cs create mode 100644 src/Discord.Net.Rest/Entities/AuditLogs/Changes/OverwriteDeleteChanges.cs diff --git a/src/Discord.Net.Core/Entities/AuditLogs/IAuditLogChange.cs b/src/Discord.Net.Core/Entities/AuditLogs/IAuditLogChanges.cs similarity index 83% rename from src/Discord.Net.Core/Entities/AuditLogs/IAuditLogChange.cs rename to src/Discord.Net.Core/Entities/AuditLogs/IAuditLogChanges.cs index 0c36b53b2..2be25a13e 100644 --- a/src/Discord.Net.Core/Entities/AuditLogs/IAuditLogChange.cs +++ b/src/Discord.Net.Core/Entities/AuditLogs/IAuditLogChanges.cs @@ -9,8 +9,6 @@ namespace Discord /// /// Represents changes which may occur within a /// - public interface IAuditLogChange - { - - } + public interface IAuditLogChanges + { } } diff --git a/src/Discord.Net.Core/Entities/AuditLogs/IAuditLogEntry.cs b/src/Discord.Net.Core/Entities/AuditLogs/IAuditLogEntry.cs index 0569f5fff..b3cf6d4af 100644 --- a/src/Discord.Net.Core/Entities/AuditLogs/IAuditLogEntry.cs +++ b/src/Discord.Net.Core/Entities/AuditLogs/IAuditLogEntry.cs @@ -19,7 +19,7 @@ namespace Discord /// /// The changes which occured within this entry. May be empty if no changes occured. /// - IReadOnlyCollection Changes { get; } + IAuditLogChanges Changes { get; } /// /// Any options which apply to this entry. If no options were provided, this may be . @@ -27,9 +27,9 @@ namespace Discord IAuditLogOptions Options { get; } /// - /// The id which the target applies to + /// The id which the target applies to, or null if it does not apply to anything specific. /// - ulong TargetId { get; } + ulong? TargetId { get; } /// /// The user responsible for causing the changes diff --git a/src/Discord.Net.Rest/API/Common/AuditLogEntry.cs b/src/Discord.Net.Rest/API/Common/AuditLogEntry.cs index ecdb12650..80d9a9e97 100644 --- a/src/Discord.Net.Rest/API/Common/AuditLogEntry.cs +++ b/src/Discord.Net.Rest/API/Common/AuditLogEntry.cs @@ -5,7 +5,7 @@ namespace Discord.API internal class AuditLogEntry { [JsonProperty("target_id")] - public ulong TargetId { get; set; } + public ulong? TargetId { get; set; } [JsonProperty("user_id")] public ulong UserId { get; set; } diff --git a/src/Discord.Net.Rest/API/Rest/GetAuditLogsParams.cs b/src/Discord.Net.Rest/API/Rest/GetAuditLogsParams.cs index fc3e0d9f3..ceabccbc8 100644 --- a/src/Discord.Net.Rest/API/Rest/GetAuditLogsParams.cs +++ b/src/Discord.Net.Rest/API/Rest/GetAuditLogsParams.cs @@ -3,6 +3,6 @@ class GetAuditLogsParams { public Optional Limit { get; set; } - public Optional AfterEntryId { get; set; } + public Optional BeforeEntryId { get; set; } } } diff --git a/src/Discord.Net.Rest/DiscordRestApiClient.cs b/src/Discord.Net.Rest/DiscordRestApiClient.cs index c7b1b23c5..6ab6bd334 100644 --- a/src/Discord.Net.Rest/DiscordRestApiClient.cs +++ b/src/Discord.Net.Rest/DiscordRestApiClient.cs @@ -1067,10 +1067,15 @@ namespace Discord.API options = RequestOptions.CreateOrClone(options); int limit = args.Limit.GetValueOrDefault(int.MaxValue); - ulong afterEntryId = args.AfterEntryId.GetValueOrDefault(0); var ids = new BucketIds(guildId: guildId); - Expression> endpoint = () => $"guilds/{guildId}/audit-logs?limit={limit}&after={afterEntryId}"; + Expression> endpoint; + + if (args.BeforeEntryId.IsSpecified) + endpoint = () => $"guilds/{guildId}/audit-logs?limit={limit}&before={args.BeforeEntryId.Value}"; + else + endpoint = () => $"guilds/{guildId}/audit-logs?limit={limit}"; + return await SendAsync("GET", endpoint, ids, options: options).ConfigureAwait(false); } diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/AuditLogHelper.cs b/src/Discord.Net.Rest/Entities/AuditLogs/AuditLogHelper.cs index 7e349e110..01855267a 100644 --- a/src/Discord.Net.Rest/Entities/AuditLogs/AuditLogHelper.cs +++ b/src/Discord.Net.Rest/Entities/AuditLogs/AuditLogHelper.cs @@ -1,9 +1,7 @@ using System; -using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; +using Model = Discord.API.AuditLog; using EntryModel = Discord.API.AuditLogEntry; using ChangeModel = Discord.API.AuditLogChange; using OptionModel = Discord.API.AuditLogOptions; @@ -12,25 +10,76 @@ namespace Discord.Rest { internal static class AuditLogHelper { - public static IAuditLogChange CreateChange(BaseDiscordClient discord, EntryModel entryModel, ChangeModel model) + public static IAuditLogChanges CreateChange(BaseDiscordClient discord, Model log, EntryModel entry, ChangeModel[] models) { - switch (entryModel.Action) + switch (entry.Action) { + case ActionType.GuildUpdated: + break; + case ActionType.ChannelCreated: + break; + case ActionType.ChannelUpdated: + break; + case ActionType.ChannelDeleted: + return ChannelDeleteChanges.Create(discord, models); + case ActionType.OverwriteCreated: + break; + case ActionType.OverwriteUpdated: + break; + case ActionType.OverwriteDeleted: + return OverwriteDeleteChanges.Create(discord, log, entry, models); + case ActionType.Prune: + break; + case ActionType.Ban: + break; + case ActionType.Unban: + break; + case ActionType.MemberUpdated: + return MemberUpdateChanges.Create(discord, log, entry, models.FirstOrDefault()); case ActionType.MemberRoleUpdated: - return new MemberRoleAuditLogChange(discord, model); + return MemberRoleChanges.Create(discord, log, entry, models); + case ActionType.RoleCreated: + break; + case ActionType.RoleUpdated: + break; + case ActionType.RoleDeleted: + break; + case ActionType.InviteCreated: + return InviteCreateChanges.Create(discord, log, models); + case ActionType.InviteUpdated: + break; + case ActionType.InviteDeleted: + break; + case ActionType.WebhookCreated: + break; + case ActionType.WebhookUpdated: + break; + case ActionType.WebhookDeleted: + break; + case ActionType.EmojiCreated: + return EmoteCreateChanges.Create(discord, entry, models.FirstOrDefault()); + case ActionType.EmojiUpdated: + return EmoteUpdateChanges.Create(discord, entry, models.FirstOrDefault()); + case ActionType.EmojiDeleted: + return EmoteDeleteChanges.Create(discord, entry, models.FirstOrDefault()); + case ActionType.MessageDeleted: + case ActionType.Kick: default: - throw new NotImplementedException($"{nameof(AuditLogHelper)} does not implement the {entryModel.Action} audit log action."); + return null; } + return null; + //throw new NotImplementedException($"{nameof(AuditLogHelper)} does not implement the {entry.Action} audit log changeset."); } - public static IAuditLogOptions CreateOptions(BaseDiscordClient discord, EntryModel entryModel, OptionModel model) + public static IAuditLogOptions CreateOptions(BaseDiscordClient discord, Model fullModel, EntryModel entryModel, OptionModel model) { switch (entryModel.Action) { case ActionType.MessageDeleted: return new MessageDeleteAuditLogOptions(discord, model); default: - throw new NotImplementedException($"{nameof(AuditLogHelper)} does not implement the {entryModel.Action} audit log action."); + return null; + //throw new NotImplementedException($"{nameof(AuditLogHelper)} does not implement the {entryModel.Action} audit log action."); } } } diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/Changes/ChannelDeleteChanges.cs b/src/Discord.Net.Rest/Entities/AuditLogs/Changes/ChannelDeleteChanges.cs new file mode 100644 index 000000000..ad2a2cd67 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/Changes/ChannelDeleteChanges.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using ChangeModel = Discord.API.AuditLogChange; + +namespace Discord.Rest +{ + public class ChannelDeleteChanges : IAuditLogChanges + { + private ChannelDeleteChanges(string name, ChannelType type, IReadOnlyCollection overwrites) + { + ChannelName = name; + ChannelType = type; + Overwrites = overwrites; + } + + internal static ChannelDeleteChanges Create(BaseDiscordClient discord, ChangeModel[] models) + { + //Use FirstOrDefault here in case the order ever changes + var overwritesModel = models.FirstOrDefault(x => x.ChangedProperty == "permission_overwrites"); + var typeModel = models.FirstOrDefault(x => x.ChangedProperty == "type"); + var nameModel = models.FirstOrDefault(x => x.ChangedProperty == "name"); + + var overwrites = overwritesModel.OldValue.ToObject() + .Select(x => new Overwrite(x.TargetId, x.TargetType, new OverwritePermissions(x.Allow, x.Deny))) + .ToList(); + var type = typeModel.OldValue.ToObject(); + var name = nameModel.OldValue.ToObject(); + + return new ChannelDeleteChanges(name, type, overwrites.ToReadOnlyCollection()); + } + + public string ChannelName { get; } + public ChannelType ChannelType { get; } + public IReadOnlyCollection Overwrites { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/Changes/EmoteCreateChanges.cs b/src/Discord.Net.Rest/Entities/AuditLogs/Changes/EmoteCreateChanges.cs new file mode 100644 index 000000000..e6e7e3b64 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/Changes/EmoteCreateChanges.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using EntryModel = Discord.API.AuditLogEntry; +using ChangeModel = Discord.API.AuditLogChange; + +namespace Discord.Rest +{ + public class EmoteCreateChanges : IAuditLogChanges + { + private EmoteCreateChanges(Emote emote) + { + Emote = emote; + } + + internal static EmoteCreateChanges Create(BaseDiscordClient discord, EntryModel entry, ChangeModel model) + { + var emoteName = model.NewValue.ToObject(); + var emote = new Emote(entry.TargetId.Value, emoteName); + + return new EmoteCreateChanges(emote); + } + + public Emote Emote { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/Changes/EmoteDeleteChanges.cs b/src/Discord.Net.Rest/Entities/AuditLogs/Changes/EmoteDeleteChanges.cs new file mode 100644 index 000000000..7e876eff7 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/Changes/EmoteDeleteChanges.cs @@ -0,0 +1,23 @@ +using EntryModel = Discord.API.AuditLogEntry; +using ChangeModel = Discord.API.AuditLogChange; + +namespace Discord.Rest +{ + public class EmoteDeleteChanges : IAuditLogChanges + { + private EmoteDeleteChanges(Emote emote) + { + Emote = emote; + } + + internal static EmoteDeleteChanges Create(BaseDiscordClient discord, EntryModel entry, ChangeModel model) + { + var emoteName = model.OldValue.ToObject(); + var emote = new Emote(entry.TargetId.Value, emoteName); + + return new EmoteDeleteChanges(emote); + } + + public Emote Emote { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/Changes/EmoteUpdateChanges.cs b/src/Discord.Net.Rest/Entities/AuditLogs/Changes/EmoteUpdateChanges.cs new file mode 100644 index 000000000..73b174f8b --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/Changes/EmoteUpdateChanges.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using EntryModel = Discord.API.AuditLogEntry; +using ChangeModel = Discord.API.AuditLogChange; + +namespace Discord.Rest +{ + public class EmoteUpdateChanges : IAuditLogChanges + { + private EmoteUpdateChanges(Emote emote, string oldName) + { + Emote = emote; + PreviousName = oldName; + } + + internal static EmoteUpdateChanges Create(BaseDiscordClient discord, EntryModel entry, ChangeModel model) + { + var emoteName = model.NewValue.ToObject(); + var emote = new Emote(entry.TargetId.Value, emoteName); + + var oldName = model.OldValue.ToObject(); + + return new EmoteUpdateChanges(emote, oldName); + } + + public Emote Emote { get; } + public string PreviousName { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/Changes/InviteCreateChanges.cs b/src/Discord.Net.Rest/Entities/AuditLogs/Changes/InviteCreateChanges.cs new file mode 100644 index 000000000..9d0e4419d --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/Changes/InviteCreateChanges.cs @@ -0,0 +1,54 @@ +using System.Linq; + +using Model = Discord.API.AuditLog; +using ChangeModel = Discord.API.AuditLogChange; + +namespace Discord.Rest +{ + public class InviteCreateChanges : IAuditLogChanges + { + private InviteCreateChanges(int maxAge, string code, bool temporary, IUser inviter, ulong channelId, int uses, int maxUses) + { + MaxAge = maxAge; + Code = code; + Temporary = temporary; + Creator = inviter; + ChannelId = channelId; + Uses = uses; + MaxUses = maxUses; + } + + internal static InviteCreateChanges Create(BaseDiscordClient discord, Model log, ChangeModel[] models) + { + //Again, FirstOrDefault to protect against ordering changes + var maxAgeModel = models.FirstOrDefault(x => x.ChangedProperty == "max_age"); + var codeModel = models.FirstOrDefault(x => x.ChangedProperty == "code"); + var temporaryModel = models.FirstOrDefault(x => x.ChangedProperty == "temporary"); + var inviterIdModel = models.FirstOrDefault(x => x.ChangedProperty == "inviter_id"); + var channelIdModel = models.FirstOrDefault(x => x.ChangedProperty == "channel_id"); + var usesModel = models.FirstOrDefault(x => x.ChangedProperty == "uses"); + var maxUsesModel = models.FirstOrDefault(x => x.ChangedProperty == "max_uses"); + + var maxAge = maxAgeModel.NewValue.ToObject(); + var code = codeModel.NewValue.ToObject(); + var temporary = temporaryModel.NewValue.ToObject(); + var inviterId = inviterIdModel.NewValue.ToObject(); + var channelId = channelIdModel.NewValue.ToObject(); + var uses = usesModel.NewValue.ToObject(); + var maxUses = maxUsesModel.NewValue.ToObject(); + + var inviterInfo = log.Users.FirstOrDefault(x => x.Id == inviterId); + var inviter = RestUser.Create(discord, inviterInfo); + + return new InviteCreateChanges(maxAge, code, temporary, inviter, channelId, uses, maxUses); + } + + public int MaxAge { get; } + public string Code { get; } + public bool Temporary { get; } + public IUser Creator { get; } + public ulong ChannelId { get; } //TODO: IChannel-ify + public int Uses { get; } + public int MaxUses { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/Changes/MemberRoleAuditLogChange.cs b/src/Discord.Net.Rest/Entities/AuditLogs/Changes/MemberRoleAuditLogChange.cs deleted file mode 100644 index c5f167d6f..000000000 --- a/src/Discord.Net.Rest/Entities/AuditLogs/Changes/MemberRoleAuditLogChange.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Newtonsoft.Json; - -using Model = Discord.API.AuditLogChange; - -namespace Discord.Rest -{ - public class MemberRoleAuditLogChange : IAuditLogChange - { - internal MemberRoleAuditLogChange(BaseDiscordClient discord, Model model) - { - RoleAdded = model.ChangedProperty == "$add"; - RoleId = model.NewValue.Value("id"); - } - - public bool RoleAdded { get; set; } - //TODO: convert to IRole - public ulong RoleId { get; set; } - } -} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/Changes/MemberRoleChanges.cs b/src/Discord.Net.Rest/Entities/AuditLogs/Changes/MemberRoleChanges.cs new file mode 100644 index 000000000..9abf5be79 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/Changes/MemberRoleChanges.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; +using ChangeModel = Discord.API.AuditLogChange; + +namespace Discord.Rest +{ + public class MemberRoleChanges : IAuditLogChanges + { + private MemberRoleChanges(IReadOnlyCollection roles, IUser target) + { + Roles = roles; + TargetUser = target; + } + + internal static MemberRoleChanges Create(BaseDiscordClient discord, Model log, EntryModel entry, ChangeModel[] models) + { + var roleInfos = models.SelectMany(x => x.NewValue.ToObject(), + (model, role) => new { model.ChangedProperty, Role = role }) + .Select(x => new RoleInfo(x.Role.Name, x.Role.Id, x.ChangedProperty == "$add")) + .ToList(); + + var userInfo = log.Users.FirstOrDefault(x => x.Id == entry.TargetId); + var user = RestUser.Create(discord, userInfo); + + return new MemberRoleChanges(roleInfos.ToReadOnlyCollection(), user); + } + + public IReadOnlyCollection Roles { get; } + public IUser TargetUser { get; } + + public struct RoleInfo + { + internal RoleInfo(string name, ulong roleId, bool added) + { + Name = name; + RoleId = roleId; + Added = added; + } + + string Name { get; } + ulong RoleId { get; } + bool Added { get; } + } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/Changes/MemberUpdateChanges.cs b/src/Discord.Net.Rest/Entities/AuditLogs/Changes/MemberUpdateChanges.cs new file mode 100644 index 000000000..4097a6d9b --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/Changes/MemberUpdateChanges.cs @@ -0,0 +1,33 @@ +using System.Linq; + +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; +using ChangeModel = Discord.API.AuditLogChange; + +namespace Discord.Rest +{ + public class MemberUpdateChanges : IAuditLogChanges + { + private MemberUpdateChanges(IUser user, string newNick, string oldNick) + { + User = user; + NewNick = newNick; + OldNick = oldNick; + } + + internal static MemberUpdateChanges Create(BaseDiscordClient discord, Model log, EntryModel entry, ChangeModel model) + { + var newNick = model.NewValue?.ToObject(); + var oldNick = model.OldValue?.ToObject(); + + var targetInfo = log.Users.FirstOrDefault(x => x.Id == entry.TargetId); + var user = RestUser.Create(discord, targetInfo); + + return new MemberUpdateChanges(user, newNick, oldNick); + } + + public IUser User { get; } + public string NewNick { get; } + public string OldNick { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/Changes/OverwriteDeleteChanges.cs b/src/Discord.Net.Rest/Entities/AuditLogs/Changes/OverwriteDeleteChanges.cs new file mode 100644 index 000000000..7fe4ca475 --- /dev/null +++ b/src/Discord.Net.Rest/Entities/AuditLogs/Changes/OverwriteDeleteChanges.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; +using ChangeModel = Discord.API.AuditLogChange; +using OptionModel = Discord.API.AuditLogOptions; + +namespace Discord.Rest +{ + public class OverwriteDeleteChanges : IAuditLogChanges + { + private OverwriteDeleteChanges(Overwrite deletedOverwrite) + { + Overwrite = deletedOverwrite; + } + + internal static OverwriteDeleteChanges Create(BaseDiscordClient discord, Model log, EntryModel entry, ChangeModel[] models) + { + var denyModel = models.FirstOrDefault(x => x.ChangedProperty == "deny"); + var typeModel = models.FirstOrDefault(x => x.ChangedProperty == "type"); + var idModel = models.FirstOrDefault(x => x.ChangedProperty == "id"); + var allowModel = models.FirstOrDefault(x => x.ChangedProperty == "allow"); + + var deny = denyModel.OldValue.ToObject(); + var type = typeModel.OldValue.ToObject(); //'role' or 'member', can't use PermissionsTarget :( + var id = idModel.OldValue.ToObject(); + var allow = allowModel.OldValue.ToObject(); + + PermissionTarget target; + + if (type == "member") + target = PermissionTarget.User; + else + target = PermissionTarget.Role; + + return new OverwriteDeleteChanges(new Overwrite(id, target, new OverwritePermissions(allow, deny))); + } + + public Overwrite Overwrite { get; } + } +} diff --git a/src/Discord.Net.Rest/Entities/AuditLogs/RestAuditLogEntry.cs b/src/Discord.Net.Rest/Entities/AuditLogs/RestAuditLogEntry.cs index 6efe4e88e..6f4de2e82 100644 --- a/src/Discord.Net.Rest/Entities/AuditLogs/RestAuditLogEntry.cs +++ b/src/Discord.Net.Rest/Entities/AuditLogs/RestAuditLogEntry.cs @@ -1,47 +1,46 @@ -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; +using System.Linq; -using FullModel = Discord.API.AuditLog; -using Model = Discord.API.AuditLogEntry; +using Model = Discord.API.AuditLog; +using EntryModel = Discord.API.AuditLogEntry; namespace Discord.Rest { public class RestAuditLogEntry : RestEntity, IAuditLogEntry { - internal RestAuditLogEntry(BaseDiscordClient discord, Model model, API.User user) + private RestAuditLogEntry(BaseDiscordClient discord, Model fullLog, EntryModel model, IUser user) : base(discord, model.Id) { Action = model.Action; - if (model.Changes != null) - Changes = model.Changes - .Select(x => AuditLogHelper.CreateChange(discord, model, x)) - .ToReadOnlyCollection(() => model.Changes.Length); - else - Changes = ImmutableArray.Create(); + if (model.Changes != null) + Changes = AuditLogHelper.CreateChange(discord, fullLog, model, model.Changes); if (model.Options != null) - Options = AuditLogHelper.CreateOptions(discord, model, model.Options); + Options = AuditLogHelper.CreateOptions(discord, fullLog, model, model.Options); TargetId = model.TargetId; - User = RestUser.Create(discord, user); + User = user; Reason = model.Reason; } - internal static RestAuditLogEntry Create(BaseDiscordClient discord, FullModel fullLog, Model model) + internal static RestAuditLogEntry Create(BaseDiscordClient discord, Model fullLog, EntryModel model) { - var user = fullLog.Users.FirstOrDefault(x => x.Id == model.UserId); + var userInfo = fullLog.Users.FirstOrDefault(x => x.Id == model.UserId); + IUser user = null; + if (userInfo != null) + user = RestUser.Create(discord, userInfo); - return new RestAuditLogEntry(discord, model, user); + return new RestAuditLogEntry(discord, fullLog, model, user); } public ActionType Action { get; } - public IReadOnlyCollection Changes { get; } + + public IAuditLogChanges Changes { get; } public IAuditLogOptions Options { get; } - public ulong TargetId { get; } + + public ulong? TargetId { get; } //TODO: if we're exposing this on the changes instead, do we need this? public IUser User { get; } + public string Reason { get; } } } diff --git a/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs b/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs index e568bf402..de7512fa3 100644 --- a/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs +++ b/src/Discord.Net.Rest/Entities/Guilds/GuildHelper.cs @@ -260,7 +260,7 @@ namespace Discord.Rest Limit = info.PageSize }; if (info.Position != null) - args.AfterEntryId = info.Position.Value; + args.BeforeEntryId = info.Position.Value; var model = await client.ApiClient.GetAuditLogsAsync(guild.Id, args, options); return model.Entries.Select((x) => RestAuditLogEntry.Create(client, model, x)).ToImmutableArray(); }, @@ -268,7 +268,7 @@ namespace Discord.Rest { if (lastPage.Count != DiscordConfig.MaxAuditLogEntriesPerBatch) return false; - info.Position = lastPage.Max(x => x.Id); + info.Position = lastPage.Min(x => x.Id); return true; }, start: from,