1 module dcord.types.channel;
2 
3 import std.stdio,
4        std.format,
5        std.variant,
6        std.algorithm,
7        core.vararg;
8 
9 import dcord.types,
10        dcord.client;
11 
12 alias ChannelMap = ModelMap!(Snowflake, Channel);
13 alias PermissionOverwriteMap = ModelMap!(Snowflake, PermissionOverwrite);
14 
15 /// Enumeration permission overwrites
16 enum PermissionOverwriteType {
17   ROLE = "role",
18   MEMBER = "member",
19 }
20 
21 /// Enumeration of channel types
22 enum ChannelType: ushort {
23   GUILD_TEXT = 0,
24   DM = 1,
25   GUILD_VOICE = 2,
26   GROUP_DM = 3,
27   GUILD_CATEGORY = 4,
28 }
29 
30 /// A class representing a permission overwrite
31 class PermissionOverwrite: IModel {
32   mixin Model;
33   Snowflake id;
34 
35   // Overwrite type
36   PermissionOverwriteType type;
37 
38   // Permissions
39   Permission allow;
40   Permission deny;
41 
42   // Parent channel
43   Channel channel;
44 }
45 
46 /// A channel object
47 class Channel: IModel, IPermissible {
48   mixin Model;
49   mixin Permissible;
50 
51   Snowflake id;
52   Snowflake guildID;
53   string name;
54   string topic;
55   Snowflake lastMessageID;
56   short position;
57   uint bitrate;
58   ChannelType type;
59   Snowflake parentID;
60 
61   @JSONListToMap("id")
62   UserMap recipients;
63 
64   // Overwrites
65   @JSONListToMap("id")
66   @JSONSource("permission_overwrites")
67   PermissionOverwriteMap overwrites;
68 
69   @property Guild guild() {
70     return this.client.state.guilds.get(this.guildID);
71   }
72 
73   override void initialize() {
74     this.overwrites = new PermissionOverwriteMap;
75   }
76 
77   override string toString() { // stfu
78     return format("<Channel %s (%s)>", this.name, this.id);
79   }
80 
81   Message sendMessage(inout(string) content, string nonce=null, bool tts=false) {
82     return this.client.api.channelsMessagesCreate(this.id, content, nonce, tts, null);
83   }
84 
85   Message sendMessagef(T...)(inout(string) content, T args) {
86     return this.client.api.channelsMessagesCreate(this.id, format(content, args), null, false, null);
87   }
88 
89   void createWebhook(string name, string avatar) {
90     return this.client.api.channelsCreateWebhook(this.id, name, avatar);
91   }
92 
93 
94   Message sendMessage(Sendable obj) {
95     return this.client.api.channelsMessagesCreate(
96       this.id,
97       obj.getContents(),
98       obj.getNonce(),
99       obj.getTTS(),
100       obj.getEmbed(),
101     );
102   }
103 
104   /// Whether this is a direct message
105   @property bool DM() {
106     return (
107       this.type == ChannelType.DM ||
108       this.type == ChannelType.GROUP_DM
109     );
110   }
111 
112   /// Whether this is a voice channel
113   @property bool voice() {
114     return (
115       this.type == ChannelType.GUILD_VOICE ||
116       this.type == ChannelType.GROUP_DM ||
117       this.type == ChannelType.DM
118     );
119   }
120 
121   /// Whether this is a text channel
122   @property bool text() {
123     return (
124       this.type == ChannelType.GUILD_TEXT ||
125       this.type == ChannelType.DM ||
126       this.type == ChannelType.GROUP_DM
127     );
128   }
129 
130   /// Whether this channel is a category
131   @property bool category() {
132     return this.type == ChannelType.GUILD_CATEGORY;
133   }
134 
135   /// Get all voice states for this channel
136   @property auto voiceStates() {
137     return this.guild.voiceStates.filter(c => c.channelID == this.id);
138   }
139 
140   /// Get permissions for a user in this channel
141   override Permission getPermissions(Snowflake user) {
142     GuildMember member = this.guild.getMember(user);
143     Permission perm = this.guild.getPermissions(user);
144 
145     // Apply any role overwrites
146     foreach (overwrite; this.overwrites.values) {
147       if(overwrite.type != PermissionOverwriteType.ROLE) continue;
148       if(!member.roles.canFind(overwrite.id)) continue;
149       perm ^= overwrite.deny;
150       perm |= overwrite.allow;
151     }
152 
153     // Finally grab a user overwrite
154     if (this.overwrites.has(member.id)) {
155       perm ^= this.overwrites.get(member.id).deny;
156       perm |= this.overwrites.get(member.id).allow;
157     }
158 
159     return perm;
160   }
161 
162 }