Browse Source

Implement most audit log action types

Missing at the moment:
- GuildUpdateAuditLogData
- UnbanAuditLogData
- InviteUpdateAuditLogData
- InviteDeleteAuditLogData
- WebhookCreateAuditLogData
- WebhookUpdateAuditLogData
- WebhookDeleteAuditLogData
pull/719/head
FiniteReality 8 years ago
parent
commit
94ea9c3189
31 changed files with 769 additions and 269 deletions
  1. +2
    -2
      src/Discord.Net.Core/Entities/AuditLogs/IAuditLogData.cs
  2. +2
    -12
      src/Discord.Net.Core/Entities/AuditLogs/IAuditLogEntry.cs
  3. +0
    -16
      src/Discord.Net.Core/Entities/AuditLogs/IAuditLogOptions.cs
  4. +18
    -4
      src/Discord.Net.Rest/API/Common/AuditLogOptions.cs
  5. +37
    -42
      src/Discord.Net.Rest/Entities/AuditLogs/AuditLogHelper.cs
  6. +0
    -40
      src/Discord.Net.Rest/Entities/AuditLogs/Changes/ChannelDeleteChanges.cs
  7. +0
    -29
      src/Discord.Net.Rest/Entities/AuditLogs/Changes/EmoteCreateChanges.cs
  8. +0
    -23
      src/Discord.Net.Rest/Entities/AuditLogs/Changes/EmoteDeleteChanges.cs
  9. +0
    -33
      src/Discord.Net.Rest/Entities/AuditLogs/Changes/EmoteUpdateChanges.cs
  10. +23
    -0
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/BanAuditLogData.cs
  11. +56
    -0
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelCreateAuditLogData.cs
  12. +45
    -0
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelDeleteAuditLogData.cs
  13. +67
    -0
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelUpdateAuditLogData.cs
  14. +31
    -0
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteCreateAuditLogData.cs
  15. +27
    -0
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteDeleteAuditLogData.cs
  16. +31
    -0
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteUpdateAuditLogData.cs
  17. +58
    -0
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/GuildUpdateAuditLogData.cs
  18. +14
    -13
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteCreateAuditLogData.cs
  19. +23
    -0
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/KickAuditLogData.cs
  20. +7
    -8
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MemberRoleAuditLogData.cs
  21. +8
    -6
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MemberUpdateAuditLogData.cs
  22. +22
    -0
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MessageDeleteAuditLogData.cs
  23. +41
    -0
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteCreateAuditLogData.cs
  24. +10
    -8
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteDeleteAuditLogData.cs
  25. +50
    -0
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteUpdateAuditLogData.cs
  26. +22
    -0
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/PruneAuditLogData.cs
  27. +52
    -0
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleCreateAuditLogData.cs
  28. +52
    -0
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleDeleteAuditLogData.cs
  29. +65
    -0
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleUpdateAuditLogData.cs
  30. +0
    -23
      src/Discord.Net.Rest/Entities/AuditLogs/Options/MessageDeleteAuditLogOptions.cs
  31. +6
    -10
      src/Discord.Net.Rest/Entities/AuditLogs/RestAuditLogEntry.cs

src/Discord.Net.Core/Entities/AuditLogs/IAuditLogChanges.cs → src/Discord.Net.Core/Entities/AuditLogs/IAuditLogData.cs View File

@@ -7,8 +7,8 @@ using System.Threading.Tasks;
namespace Discord
{
/// <summary>
/// Represents changes which may occur within a <see cref="IAuditLogEntry"/>
/// Represents data applied to an <see cref="IAuditLogEntry"/>
/// </summary>
public interface IAuditLogChanges
public interface IAuditLogData
{ }
}

+ 2
- 12
src/Discord.Net.Core/Entities/AuditLogs/IAuditLogEntry.cs View File

@@ -17,19 +17,9 @@ namespace Discord
ActionType Action { get; }

/// <summary>
/// The changes which occured within this entry. May be empty if no changes occured.
/// The data for this entry. May be <see cref="null"/> if no data was available.
/// </summary>
IAuditLogChanges Changes { get; }

/// <summary>
/// Any options which apply to this entry. If no options were provided, this may be <see cref="null"/>.
/// </summary>
IAuditLogOptions Options { get; }

/// <summary>
/// The id which the target applies to, or null if it does not apply to anything specific.
/// </summary>
ulong? TargetId { get; }
IAuditLogData Data { get; }

/// <summary>
/// The user responsible for causing the changes


+ 0
- 16
src/Discord.Net.Core/Entities/AuditLogs/IAuditLogOptions.cs View File

@@ -1,16 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord
{
/// <summary>
/// Represents options which may be applied to an <see cref="IAuditLogEntry"/>
/// </summary>
public interface IAuditLogOptions
{

}
}

+ 18
- 4
src/Discord.Net.Rest/API/Common/AuditLogOptions.cs View File

@@ -2,13 +2,27 @@

namespace Discord.API
{
// TODO: Complete this with all possible values for options
//TODO: Complete this with all possible values for options
internal class AuditLogOptions
{
//Message delete
[JsonProperty("count")]
public int Count { get; set; }

public int? MessageDeleteCount { get; set; } //TODO: what type of int? (returned as string)
[JsonProperty("channel_id")]
public ulong ChannelId { get; set; }
public ulong? MessageDeleteChannelId { get; set; }

//Prune
[JsonProperty("delete_member_days")]
public int? PruneDeleteMemberDays { get; set; } //TODO: what type of int? (returned as string)
[JsonProperty("members_removed")]
public int? PruneMembersRemoved { get; set; } //TODO: what type of int? (returned as string)

//Overwrite Update
[JsonProperty("role_name")]
public string OverwriteRoleName { get; set; }
[JsonProperty("type")]
public string OverwriteType { get; set; }
[JsonProperty("id")]
public ulong? OverwriteTargetId { get; set; }
}
}

+ 37
- 42
src/Discord.Net.Rest/Entities/AuditLogs/AuditLogHelper.cs View File

@@ -3,84 +3,79 @@ using System.Linq;

using Model = Discord.API.AuditLog;
using EntryModel = Discord.API.AuditLogEntry;
using ChangeModel = Discord.API.AuditLogChange;
using OptionModel = Discord.API.AuditLogOptions;

namespace Discord.Rest
{
internal static class AuditLogHelper
{
public static IAuditLogChanges CreateChange(BaseDiscordClient discord, Model log, EntryModel entry, ChangeModel[] models)
public static IAuditLogData CreateData(BaseDiscordClient discord, Model log, EntryModel entry)
{
switch (entry.Action)
{
case ActionType.GuildUpdated:
break;
case ActionType.ChannelCreated:
break;
case ActionType.GuildUpdated: //1
return GuildUpdateAuditLogData.Create(discord, log, entry);

case ActionType.ChannelCreated: //10
return ChannelCreateAuditLogData.Create(discord, log, entry);
case ActionType.ChannelUpdated:
break;
return ChannelUpdateAuditLogData.Create(discord, log, entry);
case ActionType.ChannelDeleted:
return ChannelDeleteChanges.Create(discord, models);
return ChannelDeleteAuditLogData.Create(discord, log, entry);
case ActionType.OverwriteCreated:
break;
return OverwriteCreateAuditLogData.Create(discord, log, entry);
case ActionType.OverwriteUpdated:
break;
return OverwriteUpdateAuditLogData.Create(discord, log, entry);
case ActionType.OverwriteDeleted:
return OverwriteDeleteChanges.Create(discord, log, entry, models);
return OverwriteDeleteAuditLogData.Create(discord, log, entry);

case ActionType.Kick: //20
return KickAuditLogData.Create(discord, log, entry);
case ActionType.Prune:
break;
return PruneAuditLogData.Create(discord, log, entry);
case ActionType.Ban:
break;
return BanAuditLogData.Create(discord, log, entry);
case ActionType.Unban:
break;
case ActionType.MemberUpdated:
return MemberUpdateChanges.Create(discord, log, entry, models.FirstOrDefault());
return MemberUpdateAuditLogData.Create(discord, log, entry);
case ActionType.MemberRoleUpdated:
return MemberRoleChanges.Create(discord, log, entry, models);
case ActionType.RoleCreated:
break;
return MemberRoleAuditLogData.Create(discord, log, entry);

case ActionType.RoleCreated: //30
return RoleCreateAuditLogData.Create(discord, log, entry);
case ActionType.RoleUpdated:
break;
return RoleUpdateAuditLogData.Create(discord, log, entry);
case ActionType.RoleDeleted:
break;
case ActionType.InviteCreated:
return InviteCreateChanges.Create(discord, log, models);
return RoleDeleteAuditLogData.Create(discord, log, entry);

case ActionType.InviteCreated: //40
return InviteCreateAuditLogData.Create(discord, log, entry);
case ActionType.InviteUpdated:
break;
case ActionType.InviteDeleted:
break;
case ActionType.WebhookCreated:

case ActionType.WebhookCreated: //50
break;
case ActionType.WebhookUpdated:
break;
case ActionType.WebhookDeleted:
break;
case ActionType.EmojiCreated:
return EmoteCreateChanges.Create(discord, entry, models.FirstOrDefault());

case ActionType.EmojiCreated: //60
return EmoteCreateAuditLogData.Create(discord, log, entry);
case ActionType.EmojiUpdated:
return EmoteUpdateChanges.Create(discord, entry, models.FirstOrDefault());
return EmoteUpdateAuditLogData.Create(discord, log, entry);
case ActionType.EmojiDeleted:
return EmoteDeleteChanges.Create(discord, entry, models.FirstOrDefault());
case ActionType.MessageDeleted:
case ActionType.Kick:
default:
return null;
}
return null;
//throw new NotImplementedException($"{nameof(AuditLogHelper)} does not implement the {entry.Action} audit log changeset.");
}
return EmoteDeleteAuditLogData.Create(discord, log, entry);

public static IAuditLogOptions CreateOptions(BaseDiscordClient discord, Model fullModel, EntryModel entryModel, OptionModel model)
{
switch (entryModel.Action)
{
case ActionType.MessageDeleted:
return new MessageDeleteAuditLogOptions(discord, model);
case ActionType.MessageDeleted: //72
return MessageDeleteAuditLogData.Create(discord, log, entry);
default:
return null;
//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 {entry.Action} audit log event.");
}
}
}

+ 0
- 40
src/Discord.Net.Rest/Entities/AuditLogs/Changes/ChannelDeleteChanges.cs View File

@@ -1,40 +0,0 @@
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<Overwrite> 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<API.Overwrite[]>()
.Select(x => new Overwrite(x.TargetId, x.TargetType, new OverwritePermissions(x.Allow, x.Deny)))
.ToList();
var type = typeModel.OldValue.ToObject<ChannelType>();
var name = nameModel.OldValue.ToObject<string>();

return new ChannelDeleteChanges(name, type, overwrites.ToReadOnlyCollection());
}

public string ChannelName { get; }
public ChannelType ChannelType { get; }
public IReadOnlyCollection<Overwrite> Overwrites { get; }
}
}

+ 0
- 29
src/Discord.Net.Rest/Entities/AuditLogs/Changes/EmoteCreateChanges.cs View File

@@ -1,29 +0,0 @@
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<string>();
var emote = new Emote(entry.TargetId.Value, emoteName);

return new EmoteCreateChanges(emote);
}

public Emote Emote { get; }
}
}

+ 0
- 23
src/Discord.Net.Rest/Entities/AuditLogs/Changes/EmoteDeleteChanges.cs View File

@@ -1,23 +0,0 @@
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<string>();
var emote = new Emote(entry.TargetId.Value, emoteName);
return new EmoteDeleteChanges(emote);
}

public Emote Emote { get; }
}
}

+ 0
- 33
src/Discord.Net.Rest/Entities/AuditLogs/Changes/EmoteUpdateChanges.cs View File

@@ -1,33 +0,0 @@
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<string>();
var emote = new Emote(entry.TargetId.Value, emoteName);

var oldName = model.OldValue.ToObject<string>();

return new EmoteUpdateChanges(emote, oldName);
}

public Emote Emote { get; }
public string PreviousName { get; }
}
}

+ 23
- 0
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/BanAuditLogData.cs View File

@@ -0,0 +1,23 @@
using System.Linq;

using Model = Discord.API.AuditLog;
using EntryModel = Discord.API.AuditLogEntry;

namespace Discord.Rest
{
public class BanAuditLogData : IAuditLogData
{
private BanAuditLogData(IUser user)
{
Target = user;
}

internal static BanAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry)
{
var userInfo = log.Users.FirstOrDefault(x => x.Id == entry.TargetId);
return new BanAuditLogData(RestUser.Create(discord, userInfo));
}

public IUser Target { get; }
}
}

+ 56
- 0
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelCreateAuditLogData.cs View File

@@ -0,0 +1,56 @@
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Linq;

using Model = Discord.API.AuditLog;
using EntryModel = Discord.API.AuditLogEntry;

namespace Discord.Rest
{
public class ChannelCreateAuditLogData : IAuditLogData
{
private ChannelCreateAuditLogData(ulong id, string name, ChannelType type, IReadOnlyCollection<Overwrite> overwrites)
{
ChannelId = id;
ChannelName = name;
ChannelType = type;
Overwrites = overwrites;
}

internal static ChannelCreateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry)
{
var changes = entry.Changes;
var overwrites = new List<Overwrite>();

var overwritesModel = changes.FirstOrDefault(x => x.ChangedProperty == "permission_overwrites");
var typeModel = changes.FirstOrDefault(x => x.ChangedProperty == "type");
var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name");

var type = typeModel.NewValue.ToObject<ChannelType>();
var name = nameModel.NewValue.ToObject<string>();

foreach (var overwrite in overwritesModel.NewValue)
{
var deny = overwrite.Value<ulong>("deny");
var _type = overwrite.Value<string>("type");
var id = overwrite.Value<ulong>("id");
var allow = overwrite.Value<ulong>("allow");

PermissionTarget permType;
if (_type == "member")
permType = PermissionTarget.User;
else
permType = PermissionTarget.Role;

overwrites.Add(new Overwrite(id, permType, new OverwritePermissions(allow, deny)));
}

return new ChannelCreateAuditLogData(entry.TargetId.Value, name, type, overwrites.ToReadOnlyCollection());
}

public ulong ChannelId { get; } //TODO: IChannel
public string ChannelName { get; }
public ChannelType ChannelType { get; }
public IReadOnlyCollection<Overwrite> Overwrites { get; }
}
}

+ 45
- 0
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelDeleteAuditLogData.cs View File

@@ -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;

namespace Discord.Rest
{
public class ChannelDeleteAuditLogData : IAuditLogData
{
private ChannelDeleteAuditLogData(ulong id, string name, ChannelType type, IReadOnlyCollection<Overwrite> overwrites)
{
ChannelId = id;
ChannelName = name;
ChannelType = type;
Overwrites = overwrites;
}

internal static ChannelDeleteAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry)
{
var changes = entry.Changes;

var overwritesModel = changes.FirstOrDefault(x => x.ChangedProperty == "permission_overwrites");
var typeModel = changes.FirstOrDefault(x => x.ChangedProperty == "type");
var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name");

var overwrites = overwritesModel.OldValue.ToObject<API.Overwrite[]>()
.Select(x => new Overwrite(x.TargetId, x.TargetType, new OverwritePermissions(x.Allow, x.Deny)))
.ToList();
var type = typeModel.OldValue.ToObject<ChannelType>();
var name = nameModel.OldValue.ToObject<string>();
var id = entry.TargetId.Value; //NOTE: assuming this is the channel id here

return new ChannelDeleteAuditLogData(id, name, type, overwrites.ToReadOnlyCollection());
}

public ulong ChannelId { get; } //TODO: IChannel
public string ChannelName { get; }
public ChannelType ChannelType { get; }
public IReadOnlyCollection<Overwrite> Overwrites { get; }
}
}

+ 67
- 0
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelUpdateAuditLogData.cs View File

@@ -0,0 +1,67 @@
using System.Linq;

using Model = Discord.API.AuditLog;
using EntryModel = Discord.API.AuditLogEntry;

namespace Discord.Rest
{
public class ChannelUpdateAuditLogData : IAuditLogData
{
private ChannelUpdateAuditLogData(GuildChannelProperties before, GuildChannelProperties after)
{
Before = before;
After = after;
}

internal static ChannelUpdateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry)
{
var changes = entry.Changes;

var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name");
var topicModel = changes.FirstOrDefault(x => x.ChangedProperty == "topic");
var bitrateModel = changes.FirstOrDefault(x => x.ChangedProperty == "bitrate");
var userLimitModel = changes.FirstOrDefault(x => x.ChangedProperty == "user_limit");

if (topicModel != null) //If topic is supplied, we must be a text channel
{
var before = new TextChannelProperties
{
Name = nameModel?.OldValue?.ToObject<string>(),
Topic = topicModel.OldValue?.ToObject<string>()
};
var after = new TextChannelProperties
{
Name = nameModel?.NewValue?.ToObject<string>(),
Topic = topicModel.NewValue?.ToObject<string>()
};

return new ChannelUpdateAuditLogData(before, after);
}
else //By process of elimination, we must be a voice channel
{
var beforeBitrate = bitrateModel?.OldValue?.ToObject<int>();
var afterBitrate = bitrateModel?.NewValue?.ToObject<int>();
var beforeUserLimit = userLimitModel?.OldValue?.ToObject<int>();
var afterUserLimit = userLimitModel?.NewValue?.ToObject<int>();

var before = new VoiceChannelProperties
{
Name = nameModel?.OldValue?.ToObject<string>(),
Bitrate = beforeBitrate ?? Optional<int>.Unspecified,
UserLimit = beforeUserLimit
};
var after = new VoiceChannelProperties
{
Name = nameModel?.NewValue?.ToObject<string>(),
Bitrate = afterBitrate ?? Optional<int>.Unspecified,
UserLimit = afterUserLimit
};

return new ChannelUpdateAuditLogData(before, after);
}
}

public GuildChannelProperties Before { get; set; }
public GuildChannelProperties After { get; set; }
}
}

+ 31
- 0
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteCreateAuditLogData.cs View File

@@ -0,0 +1,31 @@
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;

namespace Discord.Rest
{
public class EmoteCreateAuditLogData : IAuditLogData
{
private EmoteCreateAuditLogData(Emote emote)
{
Emote = emote;
}

internal static EmoteCreateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry)
{
var change = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "name"); //TODO: only change?

var emoteName = change.NewValue?.ToObject<string>();
var emote = new Emote(entry.TargetId.Value, emoteName);

return new EmoteCreateAuditLogData(emote);
}

public Emote Emote { get; }
}
}

+ 27
- 0
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteDeleteAuditLogData.cs View File

@@ -0,0 +1,27 @@
using System.Linq;

using Model = Discord.API.AuditLog;
using EntryModel = Discord.API.AuditLogEntry;

namespace Discord.Rest
{
public class EmoteDeleteAuditLogData : IAuditLogData
{
private EmoteDeleteAuditLogData(Emote emote)
{
Emote = emote;
}

internal static EmoteDeleteAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry)
{
var change = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "name"); //TODO: only change?

var emoteName = change.OldValue?.ToObject<string>();
var emote = new Emote(entry.TargetId.Value, emoteName);

return new EmoteDeleteAuditLogData(emote);
}

public Emote Emote { get; }
}
}

+ 31
- 0
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteUpdateAuditLogData.cs View File

@@ -0,0 +1,31 @@
using System.Linq;

using Model = Discord.API.AuditLog;
using EntryModel = Discord.API.AuditLogEntry;

namespace Discord.Rest
{
public class EmoteUpdateAuditLogData : IAuditLogData
{
private EmoteUpdateAuditLogData(Emote emote, string oldName)
{
Emote = emote;
PreviousName = oldName;
}

internal static EmoteUpdateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry)
{
var change = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "name"); //TODO: only change?

var emoteName = change.NewValue?.ToObject<string>();
var emote = new Emote(entry.TargetId.Value, emoteName);

var oldName = change.OldValue?.ToObject<string>();

return new EmoteUpdateAuditLogData(emote, oldName);
}

public Emote Emote { get; }
public string PreviousName { get; }
}
}

+ 58
- 0
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/GuildUpdateAuditLogData.cs View File

@@ -0,0 +1,58 @@
using Model = Discord.API.AuditLog;
using EntryModel = Discord.API.AuditLogEntry;

namespace Discord.Rest
{
public class GuildUpdateAuditLogData : IAuditLogData
{
private GuildUpdateAuditLogData()
{ }

internal static GuildUpdateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry)
{
var changes = entry.Changes;

int? oldAfkTimeout, newAfkTimeout;
DefaultMessageNotifications? oldDefaultMessageNotifications, newDefaultMessageNotifications;
ulong? oldAfkChannelId, newAfkChannelId;
string oldName, newName;
string oldRegionId, newRegionId;
string oldIconHash, newIconHash;

foreach (var change in changes)
{
switch (change.ChangedProperty)
{
case "afk_timeout":
oldAfkTimeout = change.OldValue?.ToObject<int>();
newAfkTimeout = change.NewValue?.ToObject<int>();
break;
case "default_message_notifications":
oldDefaultMessageNotifications = change.OldValue?.ToObject<DefaultMessageNotifications>();
newDefaultMessageNotifications = change.OldValue?.ToObject<DefaultMessageNotifications>();
break;
case "afk_channel_id":
oldAfkChannelId = change.OldValue?.ToObject<ulong>();
newAfkChannelId = change.NewValue?.ToObject<ulong>();
break;
case "name":
oldName = change.OldValue?.ToObject<string>();
newName = change.NewValue?.ToObject<string>();
break;
case "region":
oldRegionId = change.OldValue?.ToObject<string>();
newRegionId = change.NewValue?.ToObject<string>();
break;
case "icon_hash":
oldIconHash = change.OldValue?.ToObject<string>();
newIconHash = change.NewValue?.ToObject<string>();
break;
//TODO: owner, verification level
}
}

//TODO: implement this
return null;
}
}
}

src/Discord.Net.Rest/Entities/AuditLogs/Changes/InviteCreateChanges.cs → src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteCreateAuditLogData.cs View File

@@ -1,13 +1,13 @@
using System.Linq;

using Model = Discord.API.AuditLog;
using ChangeModel = Discord.API.AuditLogChange;
using EntryModel = Discord.API.AuditLogEntry;

namespace Discord.Rest
{
public class InviteCreateChanges : IAuditLogChanges
public class InviteCreateAuditLogData : IAuditLogData
{
private InviteCreateChanges(int maxAge, string code, bool temporary, IUser inviter, ulong channelId, int uses, int maxUses)
private InviteCreateAuditLogData(int maxAge, string code, bool temporary, IUser inviter, ulong channelId, int uses, int maxUses)
{
MaxAge = maxAge;
Code = code;
@@ -18,16 +18,17 @@ namespace Discord.Rest
MaxUses = maxUses;
}

internal static InviteCreateChanges Create(BaseDiscordClient discord, Model log, ChangeModel[] models)
internal static InviteCreateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry)
{
//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 changes = entry.Changes;

var maxAgeModel = changes.FirstOrDefault(x => x.ChangedProperty == "max_age");
var codeModel = changes.FirstOrDefault(x => x.ChangedProperty == "code");
var temporaryModel = changes.FirstOrDefault(x => x.ChangedProperty == "temporary");
var inviterIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "inviter_id");
var channelIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "channel_id");
var usesModel = changes.FirstOrDefault(x => x.ChangedProperty == "uses");
var maxUsesModel = changes.FirstOrDefault(x => x.ChangedProperty == "max_uses");

var maxAge = maxAgeModel.NewValue.ToObject<int>();
var code = codeModel.NewValue.ToObject<string>();
@@ -40,7 +41,7 @@ namespace Discord.Rest
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);
return new InviteCreateAuditLogData(maxAge, code, temporary, inviter, channelId, uses, maxUses);
}

public int MaxAge { get; }

+ 23
- 0
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/KickAuditLogData.cs View File

@@ -0,0 +1,23 @@
using System.Linq;

using Model = Discord.API.AuditLog;
using EntryModel = Discord.API.AuditLogEntry;

namespace Discord.Rest
{
public class KickAuditLogData : IAuditLogData
{
private KickAuditLogData(RestUser user)
{
Target = user;
}

internal static KickAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry)
{
var userInfo = log.Users.FirstOrDefault(x => x.Id == entry.TargetId);
return new KickAuditLogData(RestUser.Create(discord, userInfo));
}

public IUser Target { get; }
}
}

src/Discord.Net.Rest/Entities/AuditLogs/Changes/MemberRoleChanges.cs → src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MemberRoleAuditLogData.cs View File

@@ -1,26 +1,25 @@
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
public class MemberRoleAuditLogData : IAuditLogData
{
private MemberRoleChanges(IReadOnlyCollection<RoleInfo> roles, IUser target)
private MemberRoleAuditLogData(IReadOnlyCollection<RoleInfo> roles, IUser target)
{
Roles = roles;
TargetUser = target;
}

internal static MemberRoleChanges Create(BaseDiscordClient discord, Model log, EntryModel entry, ChangeModel[] models)
internal static MemberRoleAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry)
{
var roleInfos = models.SelectMany(x => x.NewValue.ToObject<API.Role[]>(),
var changes = entry.Changes;

var roleInfos = changes.SelectMany(x => x.NewValue.ToObject<API.Role[]>(),
(model, role) => new { model.ChangedProperty, Role = role })
.Select(x => new RoleInfo(x.Role.Name, x.Role.Id, x.ChangedProperty == "$add"))
.ToList();
@@ -28,7 +27,7 @@ namespace Discord.Rest
var userInfo = log.Users.FirstOrDefault(x => x.Id == entry.TargetId);
var user = RestUser.Create(discord, userInfo);

return new MemberRoleChanges(roleInfos.ToReadOnlyCollection(), user);
return new MemberRoleAuditLogData(roleInfos.ToReadOnlyCollection(), user);
}

public IReadOnlyCollection<RoleInfo> Roles { get; }

src/Discord.Net.Rest/Entities/AuditLogs/Changes/MemberUpdateChanges.cs → src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MemberUpdateAuditLogData.cs View File

@@ -6,24 +6,26 @@ using ChangeModel = Discord.API.AuditLogChange;

namespace Discord.Rest
{
public class MemberUpdateChanges : IAuditLogChanges
public class MemberUpdateAuditLogData : IAuditLogData
{
private MemberUpdateChanges(IUser user, string newNick, string oldNick)
private MemberUpdateAuditLogData(IUser user, string newNick, string oldNick)
{
User = user;
NewNick = newNick;
OldNick = oldNick;
}

internal static MemberUpdateChanges Create(BaseDiscordClient discord, Model log, EntryModel entry, ChangeModel model)
internal static MemberUpdateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry)
{
var newNick = model.NewValue?.ToObject<string>();
var oldNick = model.OldValue?.ToObject<string>();
var changes = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "nick"); //TODO: only change?

var newNick = changes.NewValue?.ToObject<string>();
var oldNick = changes.OldValue?.ToObject<string>();

var targetInfo = log.Users.FirstOrDefault(x => x.Id == entry.TargetId);
var user = RestUser.Create(discord, targetInfo);

return new MemberUpdateChanges(user, newNick, oldNick);
return new MemberUpdateAuditLogData(user, newNick, oldNick);
}

public IUser User { get; }

+ 22
- 0
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MessageDeleteAuditLogData.cs View File

@@ -0,0 +1,22 @@
using Model = Discord.API.AuditLog;
using EntryModel = Discord.API.AuditLogEntry;

namespace Discord.Rest
{
public class MessageDeleteAuditLogData : IAuditLogData
{
private MessageDeleteAuditLogData(ulong channelId, int count)
{
ChannelId = channelId;
MessageCount = count;
}

internal static MessageDeleteAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry)
{
return new MessageDeleteAuditLogData(entry.Options.MessageDeleteChannelId.Value, entry.Options.MessageDeleteCount.Value);
}

public int MessageCount { get; }
public ulong ChannelId { get; } //TODO: IChannel
}
}

+ 41
- 0
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteCreateAuditLogData.cs View File

@@ -0,0 +1,41 @@
using System.Linq;

using Model = Discord.API.AuditLog;
using EntryModel = Discord.API.AuditLogEntry;

namespace Discord.Rest
{
public class OverwriteCreateAuditLogData : IAuditLogData
{
private OverwriteCreateAuditLogData(Overwrite overwrite)
{
Overwrite = overwrite;
}

internal static OverwriteCreateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry)
{
var changes = entry.Changes;

var denyModel = changes.FirstOrDefault(x => x.ChangedProperty == "deny");
var allowModel = changes.FirstOrDefault(x => x.ChangedProperty == "allow");

var deny = denyModel.NewValue.ToObject<ulong>();
var allow = allowModel.NewValue.ToObject<ulong>();

var permissions = new OverwritePermissions(allow, deny);

var id = entry.Options.OverwriteTargetId.Value;
var type = entry.Options.OverwriteType;

PermissionTarget target;
if (type == "member")
target = PermissionTarget.User;
else
target = PermissionTarget.Role;

return new OverwriteCreateAuditLogData(new Overwrite(id, target, permissions));
}

public Overwrite Overwrite { get; }
}
}

src/Discord.Net.Rest/Entities/AuditLogs/Changes/OverwriteDeleteChanges.cs → src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteDeleteAuditLogData.cs View File

@@ -11,19 +11,21 @@ using OptionModel = Discord.API.AuditLogOptions;

namespace Discord.Rest
{
public class OverwriteDeleteChanges : IAuditLogChanges
public class OverwriteDeleteAuditLogData : IAuditLogData
{
private OverwriteDeleteChanges(Overwrite deletedOverwrite)
private OverwriteDeleteAuditLogData(Overwrite deletedOverwrite)
{
Overwrite = deletedOverwrite;
}

internal static OverwriteDeleteChanges Create(BaseDiscordClient discord, Model log, EntryModel entry, ChangeModel[] models)
internal static OverwriteDeleteAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry)
{
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 changes = entry.Changes;

var denyModel = changes.FirstOrDefault(x => x.ChangedProperty == "deny");
var typeModel = changes.FirstOrDefault(x => x.ChangedProperty == "type");
var idModel = changes.FirstOrDefault(x => x.ChangedProperty == "id");
var allowModel = changes.FirstOrDefault(x => x.ChangedProperty == "allow");

var deny = denyModel.OldValue.ToObject<ulong>();
var type = typeModel.OldValue.ToObject<string>(); //'role' or 'member', can't use PermissionsTarget :(
@@ -37,7 +39,7 @@ namespace Discord.Rest
else
target = PermissionTarget.Role;

return new OverwriteDeleteChanges(new Overwrite(id, target, new OverwritePermissions(allow, deny)));
return new OverwriteDeleteAuditLogData(new Overwrite(id, target, new OverwritePermissions(allow, deny)));
}

public Overwrite Overwrite { get; }

+ 50
- 0
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteUpdateAuditLogData.cs View File

@@ -0,0 +1,50 @@
using System.Linq;

using Model = Discord.API.AuditLog;
using EntryModel = Discord.API.AuditLogEntry;

namespace Discord.Rest
{
public class OverwriteUpdateAuditLogData : IAuditLogData
{
private OverwriteUpdateAuditLogData(OverwritePermissions before, OverwritePermissions after, ulong targetId, PermissionTarget targetType)
{
Before = before;
After = after;
OverwriteTargetId = targetId;
OverwriteType = targetType;
}

internal static OverwriteUpdateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry)
{
var changes = entry.Changes;

var denyModel = changes.FirstOrDefault(x => x.ChangedProperty == "deny");
var allowModel = changes.FirstOrDefault(x => x.ChangedProperty == "allow");

var beforeAllow = allowModel?.OldValue?.ToObject<ulong>();
var afterAllow = allowModel?.NewValue?.ToObject<ulong>();
var beforeDeny = denyModel?.OldValue?.ToObject<ulong>();
var afterDeny = denyModel?.OldValue?.ToObject<ulong>();

var beforePermissions = new OverwritePermissions(beforeAllow ?? 0, beforeDeny ?? 0);
var afterPermissions = new OverwritePermissions(afterAllow ?? 0, afterDeny ?? 0);

PermissionTarget target;
if (entry.Options.OverwriteType == "member")
target = PermissionTarget.User;
else
target = PermissionTarget.Role;

return new OverwriteUpdateAuditLogData(beforePermissions, afterPermissions, entry.Options.OverwriteTargetId.Value, target);
}

//TODO: this is kind of janky. Should I leave it, create a custom type, or what?
public OverwritePermissions Before { get; }
public OverwritePermissions After { get; }

public ulong OverwriteTargetId { get; }
public PermissionTarget OverwriteType { get; }
//TODO: should we also include the role name if it is given?
}
}

+ 22
- 0
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/PruneAuditLogData.cs View File

@@ -0,0 +1,22 @@
using Model = Discord.API.AuditLog;
using EntryModel = Discord.API.AuditLogEntry;

namespace Discord.Rest
{
public class PruneAuditLogData : IAuditLogData
{
private PruneAuditLogData(int pruneDays, int membersRemoved)
{
PruneDays = pruneDays;
MembersRemoved = membersRemoved;
}

internal static PruneAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry)
{
return new PruneAuditLogData(entry.Options.PruneDeleteMemberDays.Value, entry.Options.PruneMembersRemoved.Value);
}

public int PruneDays { get; }
public int MembersRemoved { get; }
}
}

+ 52
- 0
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleCreateAuditLogData.cs View File

@@ -0,0 +1,52 @@
using Model = Discord.API.AuditLog;
using EntryModel = Discord.API.AuditLogEntry;

namespace Discord.Rest
{
public class RoleCreateAuditLogData : IAuditLogData
{
private RoleCreateAuditLogData(RoleProperties newProps)
{
Properties = newProps;
}

internal static RoleCreateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry)
{
var changes = entry.Changes;

var newProps = new RoleProperties();

foreach (var model in changes)
{
switch (model.ChangedProperty)
{
case "color":
if (model.NewValue != null)
newProps.Color = new Color(model.NewValue.ToObject<uint>());
break;
case "mentionable":
if (model.NewValue != null)
newProps.Mentionable = model.NewValue.ToObject<bool>();
break;
case "hoist":
if (model.NewValue != null)
newProps.Hoist = model.NewValue.ToObject<bool>();
break;
case "name":
if (model.NewValue != null)
newProps.Name = model.NewValue.ToObject<string>();
break;
case "permissions":
if (model.NewValue != null)
newProps.Permissions = new GuildPermissions(model.NewValue.ToObject<ulong>());
break;
}
}

return new RoleCreateAuditLogData(newProps);
}

//TODO: replace this with something read-only
public RoleProperties Properties { get; }
}
}

+ 52
- 0
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleDeleteAuditLogData.cs View File

@@ -0,0 +1,52 @@
using Model = Discord.API.AuditLog;
using EntryModel = Discord.API.AuditLogEntry;

namespace Discord.Rest
{
public class RoleDeleteAuditLogData : IAuditLogData
{
private RoleDeleteAuditLogData(RoleProperties properties)
{
Properties = properties;
}

internal static RoleDeleteAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry)
{
var changes = entry.Changes;

var oldProps = new RoleProperties();

foreach (var model in changes)
{
switch (model.ChangedProperty)
{
case "color":
if (model.OldValue != null)
oldProps.Color = new Color(model.OldValue.ToObject<uint>());
break;
case "mentionable":
if (model.OldValue != null)
oldProps.Mentionable = model.OldValue.ToObject<bool>();
break;
case "hoist":
if (model.OldValue != null)
oldProps.Hoist = model.OldValue.ToObject<bool>();
break;
case "name":
if (model.OldValue != null)
oldProps.Name = model.OldValue.ToObject<string>();
break;
case "permissions":
if (model.OldValue != null)
oldProps.Permissions = new GuildPermissions(model.OldValue.ToObject<ulong>());
break;
}
}

return new RoleDeleteAuditLogData(oldProps);
}

//TODO: replace this with something read-only
public RoleProperties Properties { get; }
}
}

+ 65
- 0
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleUpdateAuditLogData.cs View File

@@ -0,0 +1,65 @@
using Model = Discord.API.AuditLog;
using EntryModel = Discord.API.AuditLogEntry;

namespace Discord.Rest
{
public class RoleUpdateAuditLogData : IAuditLogData
{
private RoleUpdateAuditLogData(RoleProperties oldProps, RoleProperties newProps)
{
Before = oldProps;
After = newProps;
}

internal static RoleUpdateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry)
{
var changes = entry.Changes;

var newProps = new RoleProperties();
var oldProps = new RoleProperties();

foreach (var model in changes)
{
switch (model.ChangedProperty)
{
case "color":
if (model.NewValue != null)
newProps.Color = new Color(model.NewValue.ToObject<uint>());
if (model.OldValue != null)
oldProps.Color = new Color(model.OldValue.ToObject<uint>());
break;
case "mentionable":
if (model.NewValue != null)
newProps.Mentionable = model.NewValue.ToObject<bool>();
if (model.OldValue != null)
oldProps.Mentionable = model.OldValue.ToObject<bool>();
break;
case "hoist":
if (model.NewValue != null)
newProps.Hoist = model.NewValue.ToObject<bool>();
if (model.OldValue != null)
oldProps.Hoist = model.OldValue.ToObject<bool>();
break;
case "name":
if (model.NewValue != null)
newProps.Name = model.NewValue.ToObject<string>();
if (model.OldValue != null)
oldProps.Name = model.OldValue.ToObject<string>();
break;
case "permissions":
if (model.NewValue != null)
newProps.Permissions = new GuildPermissions(model.NewValue.ToObject<ulong>());
if (model.OldValue != null)
oldProps.Permissions = new GuildPermissions(model.OldValue.ToObject<ulong>());
break;
}
}

return new RoleUpdateAuditLogData(oldProps, newProps);
}

//TODO: replace these with something read-only
public RoleProperties Before { get; }
public RoleProperties After { get; }
}
}

+ 0
- 23
src/Discord.Net.Rest/Entities/AuditLogs/Options/MessageDeleteAuditLogOptions.cs View File

@@ -1,23 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Model = Discord.API.AuditLogOptions;

namespace Discord.Rest
{
public class MessageDeleteAuditLogOptions : IAuditLogOptions
{
internal MessageDeleteAuditLogOptions(BaseDiscordClient discord, Model model)
{
MessageCount = model.Count;
SourceChannelId = model.ChannelId;
}

//TODO: turn this into an IChannel
public ulong SourceChannelId { get; }
public int MessageCount { get; }
}
}

+ 6
- 10
src/Discord.Net.Rest/Entities/AuditLogs/RestAuditLogEntry.cs View File

@@ -13,11 +13,8 @@ namespace Discord.Rest
Action = model.Action;

if (model.Changes != null)
Changes = AuditLogHelper.CreateChange(discord, fullLog, model, model.Changes);
if (model.Options != null)
Options = AuditLogHelper.CreateOptions(discord, fullLog, model, model.Options);
Data = AuditLogHelper.CreateData(discord, fullLog, model);

TargetId = model.TargetId;
User = user;

Reason = model.Reason;
@@ -33,14 +30,13 @@ namespace Discord.Rest
return new RestAuditLogEntry(discord, fullLog, model, user);
}

/// <inheritdoc/>
public ActionType Action { get; }

public IAuditLogChanges Changes { get; }
public IAuditLogOptions Options { get; }

public ulong? TargetId { get; } //TODO: if we're exposing this on the changes instead, do we need this?
/// <inheritdoc/>
public IAuditLogData Data { get; }
/// <inheritdoc/>
public IUser User { get; }
/// <inheritdoc/>
public string Reason { get; }
}
}

Loading…
Cancel
Save