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