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 initialize() { 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 URL to the guild icon 158 string getIconURL(string fmt = "webp", size_t size = 1024) { 159 if (this.icon == "") { 160 return ""; 161 } 162 return format("https://cdn.discordapp.com/icons/%s/%s.%s?size=%s", this.id, this.icon, fmt, size); 163 } 164 165 /// Returns a GuildMember for a given user object 166 GuildMember getMember(User obj) { 167 return this.getMember(obj.id); 168 } 169 170 /// Returns a GuildMember for a given user/member id 171 GuildMember getMember(Snowflake id) { 172 return this.members.get(id); 173 } 174 175 /// Kick a given GuildMember 176 void kick(GuildMember member) { 177 this.kick(member.user); 178 } 179 180 /// Kick a given User 181 void kick(User user) { 182 this.client.api.guildsMembersKick(this.id, user.id); 183 } 184 185 /// Default role for this Guild 186 @property Role defaultRole() { 187 return this.roles.pick((r) { 188 return r.id == this.id; 189 }); 190 } 191 192 /// Default channel for this Guild 193 @property Channel defaultChannel() { 194 return this.channels.pick((c) { 195 return c.id == this.id; 196 }); 197 } 198 199 /// Request offline members for this guild 200 void requestOfflineMembers() { 201 this.client.gw.send(new RequestGuildMembers(this.id)); 202 } 203 204 override Permission getPermissions(Snowflake user) { 205 // If we're the owner, we have alllll the permissions 206 if (this.ownerID == user) { 207 return Permissions.ADMINISTRATOR; 208 } 209 210 // Otherwise grab the member object 211 GuildMember member = this.getMember(user); 212 Permission perm; 213 auto roles = member.roles.map!((rid) => this.roles.get(rid)); 214 215 // Iterate over roles and add permissions 216 foreach (role; roles) { 217 perm |= role.permissions; 218 } 219 220 return perm; 221 } 222 223 /// Set this servers name 224 void setName(string name) { 225 this.client.api.guildsModify(this.id, VibeJSON(["name" : VibeJSON(name)])); 226 } 227 228 /// Set this servers region 229 void setRegion(string region) { 230 this.client.api.guildsModify(this.id, VibeJSON(["region" : VibeJSON(region)])); 231 } 232 }