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