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