1 module dcord.types.guild;
2
3 import std.stdio,
4 std.algorithm,
5 std.array,
6 std.conv;
7
8 import dcord.types,
9 dcord.client,
10 dcord.gateway;
11
12 alias GuildMap = ModelMap!(Snowflake, Guild);
13 alias RoleMap = ModelMap!(Snowflake, Role);
14 alias GuildMemberMap = ModelMap!(Snowflake, GuildMember);
15 alias EmojiMap = ModelMap!(Snowflake, Emoji);
16
17 /// Enumeration representing the verification level of the guild
18 enum VerificationLevel: ushort {
19 NONE = 0,
20 LOW = 1,
21 MEDIUM = 2,
22 HIGH = 3,
23 EXTREME = 4,
24 }
25
26 /// A class representing roles
27 class Role: IModel {
28 mixin Model;
29
30 Snowflake id;
31 Snowflake guildID;
32
33 string name;
34 bool hoist;
35 bool managed;
36 uint color;
37 Permission permissions;
38 short position;
39 bool mentionable;
40
41 @property Guild guild() {
42 return this.client.state.guilds.get(this.guildID);
43 }
44 }
45
46 class Emoji: IModel {
47 mixin Model;
48
49 Snowflake id;
50 Snowflake guildID;
51 string name;
52 bool requireColons;
53 bool managed;
54
55 Snowflake[] roles;
56
57 @property Guild guild() {
58 return this.client.state.guilds.get(this.guildID);
59 }
60
61 bool matches(string usage) {
62 if (this.name == ":" ~ usage ~ ":") {
63 return true;
64 } else if (this.requireColons) {
65 return false;
66 } else {
67 return this.name == usage;
68 }
69 }
70 }
71
72 class GuildMember : IModel {
73 mixin Model;
74
75 User user;
76 Snowflake guildID;
77 string nick;
78 string joinedAt;
79 bool mute;
80 bool deaf;
81
82 Snowflake[] roles;
83
84 @property Snowflake id() {
85 return this.user.id;
86 }
87
88 @property Guild guild() {
89 return this.client.state.guilds.get(this.guildID);
90 }
91
92 override string toString() {
93 return format("<GuildMember %s#%s (%s / %s)>",
94 this.user.username,
95 this.user.discriminator,
96 this.id,
97 this.guild.id);
98 }
99
100 bool hasRole(Role role) {
101 return this.hasRole(role.id);
102 }
103
104 bool hasRole(Snowflake id) {
105 return this.roles.canFind(id);
106 }
107 }
108
109 class Guild : IModel, IPermissible {
110 mixin Model;
111 mixin Permissible;
112
113 Snowflake id;
114 Snowflake ownerID;
115 Snowflake afkChannelID;
116 Snowflake embedChannelID;
117 string name;
118 string icon;
119 string splash;
120 string region;
121 uint afkTimeout;
122 bool embedEnabled;
123 ushort verificationLevel;
124 ushort mfaLevel;
125 string[] features;
126
127 bool unavailable;
128
129 @JSONListToMap("id")
130 GuildMemberMap members;
131
132 @JSONListToMap("sessionID")
133 VoiceStateMap voiceStates;
134
135 @JSONListToMap("id")
136 ChannelMap channels;
137
138 @JSONListToMap("id")
139 RoleMap roles;
140
141 @JSONListToMap("id")
142 EmojiMap emojis;
143
144 override void initialize() {
145 // It's possible these are not created
146 if (!this.members) return;
147
148 this.members.each((m) { m.guildID = this.id; });
149 this.voiceStates.each((vc) { vc.guildID = this.id; });
150 this.channels.each((c) { c.guildID = this.id; });
151 this.roles.each((r) { r.guildID = this.id; });
152 this.emojis.each((e) { e.guildID = this.id; });
153 }
154
155 override string toString() {
156 return format("<Guild %s (%s)>", this.name, this.id);
157 }
158
159 /// Returns a URL to the guild icon
160 string getIconURL(string fmt = "webp", size_t size = 1024) {
161 if (this.icon == "") {
162 return "";
163 }
164 return format("https://cdn.discordapp.com/icons/%s/%s.%s?size=%s", this.id, this.icon, fmt, size);
165 }
166
167 /// Returns a GuildMember for a given user object
168 GuildMember getMember(User obj) {
169 return this.getMember(obj.id);
170 }
171
172 /// Returns a GuildMember for a given user/member id
173 GuildMember getMember(Snowflake id) {
174 return this.members.get(id);
175 }
176
177 /// Kick a given GuildMember
178 void kick(GuildMember member) {
179 this.kick(member.user);
180 }
181
182 /// Kick a given User
183 void kick(User user) {
184 this.client.api.guildsMembersKick(this.id, user.id);
185 }
186
187 /// Ban a given GuildMember
188 void ban(GuildMember member) {
189 this.ban(member.user);
190 }
191
192 /// Ban a given User
193 void ban(User user) {
194 this.client.api.guildMembersBan(this.id, user.id);
195 }
196
197 /// Unban a given GuildMember
198 void removeBan(GuildMember member) {
199 this.removeBan(member.user);
200 }
201
202 /// Unban a given User
203 void removeBan(User user) {
204 this.client.api.guildMembersRemoveBan(this.id, user.id);
205 }
206
207 /// Default role for this Guild
208 @property Role defaultRole() {
209 return this.roles.pick((r) {
210 return r.id == this.id;
211 });
212 }
213
214 /// Default channel for this Guild
215 @property Channel defaultChannel() {
216 return this.channels.pick((c) {
217 return c.id == this.id;
218 });
219 }
220
221 /// Request offline members for this guild
222 void requestOfflineMembers() {
223 this.client.gw.send(new RequestGuildMembers(this.id));
224 }
225
226 override Permission getPermissions(Snowflake user) {
227 // If we're the owner, we have alllll the permissions
228 if (this.ownerID == user) {
229 return Permissions.ADMINISTRATOR;
230 }
231
232 // Otherwise grab the member object
233 GuildMember member = this.getMember(user);
234 Permission perm;
235 auto roles = member.roles.map!((rid) => this.roles.get(rid));
236
237 // Iterate over roles and add permissions
238 foreach (role; roles) {
239 perm |= role.permissions;
240 }
241
242 return perm;
243 }
244
245 /// Set this servers name
246 void setName(string name) {
247 this.client.api.guildsModify(this.id, VibeJSON(["name" : VibeJSON(name)]));
248 }
249
250 /// Set this servers region
251 void setRegion(string region) {
252 this.client.api.guildsModify(this.id, VibeJSON(["region" : VibeJSON(region)]));
253 }
254 }