diff --git a/DisCatSharp/Entities/Guild/DiscordRole.cs b/DisCatSharp/Entities/Guild/DiscordRole.cs
index 0f23938c0..e2b6277fa 100644
--- a/DisCatSharp/Entities/Guild/DiscordRole.cs
+++ b/DisCatSharp/Entities/Guild/DiscordRole.cs
@@ -1,283 +1,292 @@
// This file is part of the DisCatSharp project, based off DSharpPlus.
//
// Copyright (c) 2021-2022 AITSYS
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
using System;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using DisCatSharp.Enums;
using DisCatSharp.Net;
using DisCatSharp.Net.Abstractions;
using DisCatSharp.Net.Models;
using Newtonsoft.Json;
namespace DisCatSharp.Entities;
///
/// Represents a discord role, to which users can be assigned.
///
public class DiscordRole : SnowflakeObject, IEquatable
{
///
/// Gets the name of this role.
///
[JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)]
public string Name { get; internal set; }
///
/// Gets the color of this role.
///
[JsonIgnore]
public DiscordColor Color
=> new(this.ColorInternal);
[JsonProperty("color", NullValueHandling = NullValueHandling.Ignore)]
internal int ColorInternal;
///
/// Gets whether this role is hoisted.
///
[JsonProperty("hoist", NullValueHandling = NullValueHandling.Ignore)]
public bool IsHoisted { get; internal set; }
///
/// Gets the position of this role in the role hierarchy.
///
[JsonProperty("position", NullValueHandling = NullValueHandling.Ignore)]
public int Position { get; internal set; }
///
/// Gets the permissions set for this role.
///
[JsonProperty("permissions", NullValueHandling = NullValueHandling.Ignore)]
public Permissions Permissions { get; internal set; }
///
/// Gets whether this role is managed by an integration.
///
[JsonProperty("managed", NullValueHandling = NullValueHandling.Ignore)]
public bool IsManaged { get; internal set; }
///
/// Gets whether this role is mentionable.
///
[JsonProperty("mentionable", NullValueHandling = NullValueHandling.Ignore)]
public bool IsMentionable { get; internal set; }
///
/// Gets the tags this role has.
///
[JsonProperty("tags", NullValueHandling = NullValueHandling.Ignore)]
public DiscordRoleTags Tags { get; internal set; }
///
/// Gets the role icon's hash.
///
[JsonProperty("icon", NullValueHandling = NullValueHandling.Ignore)]
public string IconHash { get; internal set; }
///
/// Gets the role icon's url.
///
[JsonIgnore]
public string IconUrl
=> !string.IsNullOrWhiteSpace(this.IconHash) ? $"{DiscordDomain.GetDomain(CoreDomain.DiscordCdn).Url}{Endpoints.ROLE_ICONS}/{this.Id.ToString(CultureInfo.InvariantCulture)}/{this.IconHash}.png?size=64" : null;
///
/// Gets the role unicode_emoji.
///
[JsonProperty("unicode_emoji", NullValueHandling = NullValueHandling.Ignore)]
internal string UnicodeEmojiString;
///
/// Gets the unicode emoji.
///
public DiscordEmoji UnicodeEmoji
=> this.UnicodeEmojiString != null ? DiscordEmoji.FromName(this.Discord, $":{this.UnicodeEmojiString}:", false) : null;
[JsonIgnore]
internal ulong GuildId = 0;
///
/// Gets the role flags.
///
[JsonProperty("flags", NullValueHandling = NullValueHandling.Ignore)]
public RoleFlags Flags { get; internal set; }
///
/// Gets a mention string for this role. If the role is mentionable, this string will mention all the users that belong to this role.
///
public string Mention
=> Formatter.Mention(this);
#region Methods
///
/// Modifies this role's position.
///
/// New position
/// Reason why we moved it
///
/// Thrown when the client does not have the permission.
/// Thrown when the role does not exist.
/// Thrown when an invalid parameter was provided.
/// Thrown when Discord is unable to process the request.
public Task ModifyPositionAsync(int position, string reason = null)
{
var roles = this.Discord.Guilds[this.GuildId].Roles.Values.OrderByDescending(xr => xr.Position)
.Select(x => new RestGuildRoleReorderPayload
{
RoleId = x.Id,
Position = x.Id == this.Id
? position
: x.Position <= position ? x.Position - 1 : x.Position
});
return this.Discord.ApiClient.ModifyGuildRolePositionAsync(this.GuildId, roles, reason);
}
///
/// Updates this role.
///
/// New role name.
/// New role permissions.
/// New role color.
/// New role hoist.
/// Whether this role is mentionable.
/// Audit log reason.
/// Thrown when the client does not have the permission.
/// Thrown when the role does not exist.
/// Thrown when an invalid parameter was provided.
/// Thrown when Discord is unable to process the request.
public Task ModifyAsync(string name = null, Permissions? permissions = null, DiscordColor? color = null, bool? hoist = null, bool? mentionable = null, string reason = null)
=> this.Discord.ApiClient.ModifyGuildRoleAsync(this.GuildId, this.Id, name, permissions, color?.Value, hoist, mentionable, null, null, reason);
///
/// Updates this role.
///
/// The action.
/// Thrown when the client does not have the permission.
/// Thrown when the role does not exist.
/// Thrown when an invalid parameter was provided.
/// Thrown when Discord is unable to process the request.
public Task ModifyAsync(Action action)
{
var mdl = new RoleEditModel();
action(mdl);
var canContinue = true;
- if (mdl.Icon.HasValue || mdl.UnicodeEmoji.HasValue)
+ if ((mdl.Icon.HasValue && mdl.Icon.Value != null) || (mdl.UnicodeEmoji.HasValue && mdl.UnicodeEmoji.Value != null))
canContinue = this.Discord.Guilds[this.GuildId].Features.CanSetRoleIcons;
- var iconb64 = ImageTool.Base64FromStream(mdl.Icon);
-
- var emoji = mdl.UnicodeEmoji
- .MapOrNull(e => e.Id == 0
- ? e.Name
- : throw new ArgumentException("Emoji must be unicode"));
+ var iconb64 = Optional.FromNullable(null);
+ if (mdl.Icon.HasValue && mdl.Icon.Value != null)
+ iconb64 = ImageTool.Base64FromStream(mdl.Icon);
+ else if (mdl.Icon.HasValue)
+ iconb64 = Optional.Some(null);
+
+ var emoji = Optional.FromNullable(null);
+
+ if (mdl.UnicodeEmoji.HasValue && mdl.UnicodeEmoji.Value != null)
+ emoji = mdl.UnicodeEmoji
+ .MapOrNull(e => e.Id == 0
+ ? e.Name
+ : throw new ArgumentException("Emoji must be unicode"));
+ else if (mdl.UnicodeEmoji.HasValue)
+ iconb64 = Optional.Some(null);
return canContinue ? this.Discord.ApiClient.ModifyGuildRoleAsync(this.GuildId, this.Id, mdl.Name, mdl.Permissions, mdl.Color?.Value, mdl.Hoist, mdl.Mentionable, iconb64, emoji, mdl.AuditLogReason) : throw new NotSupportedException($"Cannot modify role icon. Guild needs boost tier two.");
}
///
/// Deletes this role.
///
/// Reason as to why this role has been deleted.
///
/// Thrown when the client does not have the permission.
/// Thrown when the role does not exist.
/// Thrown when an invalid parameter was provided.
/// Thrown when Discord is unable to process the request.
public Task DeleteAsync(string reason = null)
=> this.Discord.ApiClient.DeleteRoleAsync(this.GuildId, this.Id, reason);
#endregion
///
/// Initializes a new instance of the class.
///
internal DiscordRole()
{ }
///
/// Checks whether this role has specific permissions.
///
/// Permissions to check for.
/// Whether the permissions are allowed or not.
public PermissionLevel CheckPermission(Permissions permission)
=> (this.Permissions & permission) != 0 ? PermissionLevel.Allowed : PermissionLevel.Unset;
///
/// Returns a string representation of this role.
///
/// String representation of this role.
public override string ToString()
=> $"Role {this.Id}; {this.Name}";
///
/// Checks whether this is equal to another object.
///
/// Object to compare to.
/// Whether the object is equal to this .
public override bool Equals(object obj)
=> this.Equals(obj as DiscordRole);
///
/// Checks whether this is equal to another .
///
/// to compare to.
/// Whether the is equal to this .
public bool Equals(DiscordRole e)
=> e switch
{
null => false,
_ => ReferenceEquals(this, e) || this.Id == e.Id
};
///
/// Gets the hash code for this .
///
/// The hash code for this .
public override int GetHashCode()
=> this.Id.GetHashCode();
///
/// Gets whether the two objects are equal.
///
/// First role to compare.
/// Second role to compare.
/// Whether the two roles are equal.
public static bool operator ==(DiscordRole e1, DiscordRole e2)
=> e1 is null == e2 is null
&& ((e1 is null && e2 is null) || e1.Id == e2.Id);
///
/// Gets whether the two objects are not equal.
///
/// First role to compare.
/// Second role to compare.
/// Whether the two roles are not equal.
public static bool operator !=(DiscordRole e1, DiscordRole e2)
=> !(e1 == e2);
}