using Discord.Audio; using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using EmbedModel = Discord.API.GuildEmbed; using Model = Discord.API.Guild; namespace Discord.Rest { [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class RestGuild : RestEntity, IGuild, IUpdateable { private ImmutableDictionary _roles; private ImmutableArray _emotes; private ImmutableArray _features; public string Name { get; private set; } public int AFKTimeout { get; private set; } public bool IsEmbeddable { get; private set; } public VerificationLevel VerificationLevel { get; private set; } public MfaLevel MfaLevel { get; private set; } public DefaultMessageNotifications DefaultMessageNotifications { get; private set; } public ulong? AFKChannelId { get; private set; } public ulong? EmbedChannelId { get; private set; } public ulong? SystemChannelId { get; private set; } public ulong OwnerId { get; private set; } public string VoiceRegionId { get; private set; } public string IconId { get; private set; } public string SplashId { get; private set; } internal bool Available { get; private set; } public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id); [Obsolete("DefaultChannelId is deprecated, use GetDefaultChannelAsync")] public ulong DefaultChannelId => Id; public string IconUrl => CDN.GetGuildIconUrl(Id, IconId); public string SplashUrl => CDN.GetGuildSplashUrl(Id, SplashId); public RestRole EveryoneRole => GetRole(Id); public IReadOnlyCollection Roles => _roles.ToReadOnlyCollection(); public IReadOnlyCollection Emotes => _emotes; public IReadOnlyCollection Features => _features; internal RestGuild(BaseDiscordClient client, ulong id) : base(client, id) { } internal static RestGuild Create(BaseDiscordClient discord, Model model) { var entity = new RestGuild(discord, model.Id); entity.Update(model); return entity; } internal void Update(Model model) { AFKChannelId = model.AFKChannelId; EmbedChannelId = model.EmbedChannelId; SystemChannelId = model.SystemChannelId; AFKTimeout = model.AFKTimeout; IsEmbeddable = model.EmbedEnabled; IconId = model.Icon; Name = model.Name; OwnerId = model.OwnerId; VoiceRegionId = model.Region; SplashId = model.Splash; VerificationLevel = model.VerificationLevel; MfaLevel = model.MfaLevel; DefaultMessageNotifications = model.DefaultMessageNotifications; if (model.Emojis != null) { var emotes = ImmutableArray.CreateBuilder(model.Emojis.Length); for (int i = 0; i < model.Emojis.Length; i++) emotes.Add(model.Emojis[i].ToEntity()); _emotes = emotes.ToImmutableArray(); } else _emotes = ImmutableArray.Create(); if (model.Features != null) _features = model.Features.ToImmutableArray(); else _features = ImmutableArray.Create(); var roles = ImmutableDictionary.CreateBuilder(); if (model.Roles != null) { for (int i = 0; i < model.Roles.Length; i++) roles[model.Roles[i].Id] = RestRole.Create(Discord, this, model.Roles[i]); } _roles = roles.ToImmutable(); Available = true; } internal void Update(EmbedModel model) { EmbedChannelId = model.ChannelId; IsEmbeddable = model.Enabled; } //General public async Task UpdateAsync(RequestOptions options = null) => Update(await Discord.ApiClient.GetGuildAsync(Id, options).ConfigureAwait(false)); public Task DeleteAsync(RequestOptions options = null) => GuildHelper.DeleteAsync(this, Discord, options); public async Task ModifyAsync(Action func, RequestOptions options = null) { var model = await GuildHelper.ModifyAsync(this, Discord, func, options).ConfigureAwait(false); Update(model); } public async Task ModifyEmbedAsync(Action func, RequestOptions options = null) { var model = await GuildHelper.ModifyEmbedAsync(this, Discord, func, options).ConfigureAwait(false); Update(model); } public async Task ReorderChannelsAsync(IEnumerable args, RequestOptions options = null) { var arr = args.ToArray(); await GuildHelper.ReorderChannelsAsync(this, Discord, arr, options); } public async Task ReorderRolesAsync(IEnumerable args, RequestOptions options = null) { var models = await GuildHelper.ReorderRolesAsync(this, Discord, args, options).ConfigureAwait(false); foreach (var model in models) { var role = GetRole(model.Id); if (role != null) role.Update(model); } } public Task LeaveAsync(RequestOptions options = null) => GuildHelper.LeaveAsync(this, Discord, options); //Bans public Task> GetBansAsync(RequestOptions options = null) => GuildHelper.GetBansAsync(this, Discord, options); public Task GetBanAsync(IUser user, RequestOptions options = null) => GuildHelper.GetBanAsync(this, Discord, user.Id, options); public Task GetBanAsync(ulong userId, RequestOptions options = null) => GuildHelper.GetBanAsync(this, Discord, userId, options); public Task AddBanAsync(IUser user, int pruneDays = 0, string reason = null, RequestOptions options = null) => GuildHelper.AddBanAsync(this, Discord, user.Id, pruneDays, reason, options); public Task AddBanAsync(ulong userId, int pruneDays = 0, string reason = null, RequestOptions options = null) => GuildHelper.AddBanAsync(this, Discord, userId, pruneDays, reason, options); public Task RemoveBanAsync(IUser user, RequestOptions options = null) => GuildHelper.RemoveBanAsync(this, Discord, user.Id, options); public Task RemoveBanAsync(ulong userId, RequestOptions options = null) => GuildHelper.RemoveBanAsync(this, Discord, userId, options); //Channels public Task> GetChannelsAsync(RequestOptions options = null) => GuildHelper.GetChannelsAsync(this, Discord, options); public Task GetChannelAsync(ulong id, RequestOptions options = null) => GuildHelper.GetChannelAsync(this, Discord, id, options); public async Task GetTextChannelAsync(ulong id, RequestOptions options = null) { var channel = await GuildHelper.GetChannelAsync(this, Discord, id, options).ConfigureAwait(false); return channel as RestTextChannel; } public async Task> GetTextChannelsAsync(RequestOptions options = null) { var channels = await GuildHelper.GetChannelsAsync(this, Discord, options).ConfigureAwait(false); return channels.Select(x => x as RestTextChannel).Where(x => x != null).ToImmutableArray(); } public async Task GetVoiceChannelAsync(ulong id, RequestOptions options = null) { var channel = await GuildHelper.GetChannelAsync(this, Discord, id, options).ConfigureAwait(false); return channel as RestVoiceChannel; } public async Task> GetVoiceChannelsAsync(RequestOptions options = null) { var channels = await GuildHelper.GetChannelsAsync(this, Discord, options).ConfigureAwait(false); return channels.Select(x => x as RestVoiceChannel).Where(x => x != null).ToImmutableArray(); } public async Task> GetCategoryChannelsAsync(RequestOptions options = null) { var channels = await GuildHelper.GetChannelsAsync(this, Discord, options).ConfigureAwait(false); return channels.Select(x => x as RestCategoryChannel).Where(x => x != null).ToImmutableArray(); } public async Task GetAFKChannelAsync(RequestOptions options = null) { var afkId = AFKChannelId; if (afkId.HasValue) { var channel = await GuildHelper.GetChannelAsync(this, Discord, afkId.Value, options).ConfigureAwait(false); return channel as RestVoiceChannel; } return null; } public async Task GetDefaultChannelAsync(RequestOptions options = null) { var channels = await GetTextChannelsAsync(options).ConfigureAwait(false); var user = await GetCurrentUserAsync(options).ConfigureAwait(false); return channels .Where(c => user.GetPermissions(c).ViewChannel) .OrderBy(c => c.Position) .FirstOrDefault(); } public async Task GetEmbedChannelAsync(RequestOptions options = null) { var embedId = EmbedChannelId; if (embedId.HasValue) return await GuildHelper.GetChannelAsync(this, Discord, embedId.Value, options).ConfigureAwait(false); return null; } public async Task GetSystemChannelAsync(RequestOptions options = null) { var systemId = SystemChannelId; if (systemId.HasValue) { var channel = await GuildHelper.GetChannelAsync(this, Discord, systemId.Value, options).ConfigureAwait(false); return channel as RestTextChannel; } return null; } public Task CreateTextChannelAsync(string name, RequestOptions options = null, Action func = null) => GuildHelper.CreateTextChannelAsync(this, Discord, name, options, func); public Task CreateVoiceChannelAsync(string name, RequestOptions options = null, Action func = null) => GuildHelper.CreateVoiceChannelAsync(this, Discord, name, options, func); public Task CreateCategoryChannelAsync(string name, RequestOptions options = null) => GuildHelper.CreateCategoryChannelAsync(this, Discord, name, options); //Integrations public Task> GetIntegrationsAsync(RequestOptions options = null) => GuildHelper.GetIntegrationsAsync(this, Discord, options); public Task CreateIntegrationAsync(ulong id, string type, RequestOptions options = null) => GuildHelper.CreateIntegrationAsync(this, Discord, id, type, options); //Invites public Task> GetInvitesAsync(RequestOptions options = null) => GuildHelper.GetInvitesAsync(this, Discord, options); //Roles public RestRole GetRole(ulong id) { if (_roles.TryGetValue(id, out RestRole value)) return value; return null; } public async Task CreateRoleAsync(string name, GuildPermissions? permissions = default(GuildPermissions?), Color? color = default(Color?), bool isHoisted = false, RequestOptions options = null) { var role = await GuildHelper.CreateRoleAsync(this, Discord, name, permissions, color, isHoisted, options).ConfigureAwait(false); _roles = _roles.Add(role.Id, role); return role; } //Users public IAsyncEnumerable> GetUsersAsync(RequestOptions options = null) => GuildHelper.GetUsersAsync(this, Discord, null, null, options); public Task GetUserAsync(ulong id, RequestOptions options = null) => GuildHelper.GetUserAsync(this, Discord, id, options); public Task GetCurrentUserAsync(RequestOptions options = null) => GuildHelper.GetUserAsync(this, Discord, Discord.CurrentUser.Id, options); public Task GetOwnerAsync(RequestOptions options = null) => GuildHelper.GetUserAsync(this, Discord, OwnerId, options); public Task PruneUsersAsync(int days = 30, bool simulate = false, RequestOptions options = null) => GuildHelper.PruneUsersAsync(this, Discord, days, simulate, options); //Audit logs public IAsyncEnumerable> GetAuditLogsAsync(int limit, RequestOptions options = null) => GuildHelper.GetAuditLogsAsync(this, Discord, null, limit, options); //Webhooks public Task GetWebhookAsync(ulong id, RequestOptions options = null) => GuildHelper.GetWebhookAsync(this, Discord, id, options); public Task> GetWebhooksAsync(RequestOptions options = null) => GuildHelper.GetWebhooksAsync(this, Discord, options); public override string ToString() => Name; private string DebuggerDisplay => $"{Name} ({Id})"; //Emotes public Task GetEmoteAsync(ulong id, RequestOptions options = null) => GuildHelper.GetEmoteAsync(this, Discord, id, options); public Task CreateEmoteAsync(string name, Image image, Optional> roles = default(Optional>), RequestOptions options = null) => GuildHelper.CreateEmoteAsync(this, Discord, name, image, roles, options); public Task ModifyEmoteAsync(GuildEmote emote, Action func, RequestOptions options = null) => GuildHelper.ModifyEmoteAsync(this, Discord, emote.Id, func, options); public Task DeleteEmoteAsync(GuildEmote emote, RequestOptions options = null) => GuildHelper.DeleteEmoteAsync(this, Discord, emote.Id, options); //IGuild bool IGuild.Available => Available; IAudioClient IGuild.AudioClient => null; IRole IGuild.EveryoneRole => EveryoneRole; IReadOnlyCollection IGuild.Roles => Roles; async Task> IGuild.GetBansAsync(RequestOptions options) => await GetBansAsync(options).ConfigureAwait(false); /// async Task IGuild.GetBanAsync(IUser user, RequestOptions options) => await GetBanAsync(user, options).ConfigureAwait(false); /// async Task IGuild.GetBanAsync(ulong userId, RequestOptions options) => await GetBanAsync(userId, options).ConfigureAwait(false); async Task> IGuild.GetChannelsAsync(CacheMode mode, RequestOptions options) { if (mode == CacheMode.AllowDownload) return await GetChannelsAsync(options).ConfigureAwait(false); else return ImmutableArray.Create(); } async Task IGuild.GetChannelAsync(ulong id, CacheMode mode, RequestOptions options) { if (mode == CacheMode.AllowDownload) return await GetChannelAsync(id, options).ConfigureAwait(false); else return null; } async Task> IGuild.GetTextChannelsAsync(CacheMode mode, RequestOptions options) { if (mode == CacheMode.AllowDownload) return await GetTextChannelsAsync(options).ConfigureAwait(false); else return ImmutableArray.Create(); } async Task IGuild.GetTextChannelAsync(ulong id, CacheMode mode, RequestOptions options) { if (mode == CacheMode.AllowDownload) return await GetTextChannelAsync(id, options).ConfigureAwait(false); else return null; } async Task> IGuild.GetVoiceChannelsAsync(CacheMode mode, RequestOptions options) { if (mode == CacheMode.AllowDownload) return await GetVoiceChannelsAsync(options).ConfigureAwait(false); else return ImmutableArray.Create(); } async Task> IGuild.GetCategoriesAsync(CacheMode mode, RequestOptions options) { if (mode == CacheMode.AllowDownload) return await GetCategoryChannelsAsync(options).ConfigureAwait(false); else return null; } async Task IGuild.GetVoiceChannelAsync(ulong id, CacheMode mode, RequestOptions options) { if (mode == CacheMode.AllowDownload) return await GetVoiceChannelAsync(id, options).ConfigureAwait(false); else return null; } async Task IGuild.GetAFKChannelAsync(CacheMode mode, RequestOptions options) { if (mode == CacheMode.AllowDownload) return await GetAFKChannelAsync(options).ConfigureAwait(false); else return null; } async Task IGuild.GetDefaultChannelAsync(CacheMode mode, RequestOptions options) { if (mode == CacheMode.AllowDownload) return await GetDefaultChannelAsync(options).ConfigureAwait(false); else return null; } async Task IGuild.GetEmbedChannelAsync(CacheMode mode, RequestOptions options) { if (mode == CacheMode.AllowDownload) return await GetEmbedChannelAsync(options).ConfigureAwait(false); else return null; } async Task IGuild.GetSystemChannelAsync(CacheMode mode, RequestOptions options) { if (mode == CacheMode.AllowDownload) return await GetSystemChannelAsync(options).ConfigureAwait(false); else return null; } async Task IGuild.CreateTextChannelAsync(string name, RequestOptions options, Action func) => await CreateTextChannelAsync(name, options, func).ConfigureAwait(false); async Task IGuild.CreateVoiceChannelAsync(string name, RequestOptions options, Action func) => await CreateVoiceChannelAsync(name, options, func).ConfigureAwait(false); async Task IGuild.CreateCategoryAsync(string name, RequestOptions options) => await CreateCategoryChannelAsync(name, options).ConfigureAwait(false); async Task> IGuild.GetIntegrationsAsync(RequestOptions options) => await GetIntegrationsAsync(options).ConfigureAwait(false); async Task IGuild.CreateIntegrationAsync(ulong id, string type, RequestOptions options) => await CreateIntegrationAsync(id, type, options).ConfigureAwait(false); async Task> IGuild.GetInvitesAsync(RequestOptions options) => await GetInvitesAsync(options).ConfigureAwait(false); IRole IGuild.GetRole(ulong id) => GetRole(id); async Task IGuild.CreateRoleAsync(string name, GuildPermissions? permissions, Color? color, bool isHoisted, RequestOptions options) => await CreateRoleAsync(name, permissions, color, isHoisted, options).ConfigureAwait(false); async Task IGuild.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) { if (mode == CacheMode.AllowDownload) return await GetUserAsync(id, options).ConfigureAwait(false); else return null; } async Task IGuild.GetCurrentUserAsync(CacheMode mode, RequestOptions options) { if (mode == CacheMode.AllowDownload) return await GetCurrentUserAsync(options).ConfigureAwait(false); else return null; } async Task IGuild.GetOwnerAsync(CacheMode mode, RequestOptions options) { if (mode == CacheMode.AllowDownload) return await GetOwnerAsync(options).ConfigureAwait(false); else return null; } async Task> IGuild.GetUsersAsync(CacheMode mode, RequestOptions options) { if (mode == CacheMode.AllowDownload) return (await GetUsersAsync(options).FlattenAsync().ConfigureAwait(false)).ToImmutableArray(); else return ImmutableArray.Create(); } Task IGuild.DownloadUsersAsync() { throw new NotSupportedException(); } async Task> IGuild.GetAuditLogAsync(int limit, CacheMode cacheMode, RequestOptions options) { if (cacheMode == CacheMode.AllowDownload) return (await GetAuditLogsAsync(limit, options).FlattenAsync().ConfigureAwait(false)).ToImmutableArray(); else return ImmutableArray.Create(); } async Task IGuild.GetWebhookAsync(ulong id, RequestOptions options) => await GetWebhookAsync(id, options); async Task> IGuild.GetWebhooksAsync(RequestOptions options) => await GetWebhooksAsync(options); } }