cmd.botGuild   F
last analyzed

Complexity

Conditions 38

Size

Total Lines 155
Code Lines 115

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 38
eloc 115
nop 1
dl 0
loc 155
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like cmd.botGuild often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
package cmd
2
3
import (
4
	"fmt"
5
	"github.com/bwmarrin/discordgo"
6
	"github.com/globalsign/mgo/bson"
7
	"strconv"
8
	"strings"
9
10
	"github.com/FlameInTheDark/dtbot/bot"
11
)
12
13
func showLogs(ctx *bot.Context, count int) {
14
	logs := ctx.DB.LogGet(count)
15
	var logString = []string{""}
16
	for _, log := range logs {
17
		logString = append(logString, fmt.Sprintf("[%v] %v: %v\n", log.Date, log.Module, log.Text))
18
	}
19
	ctx.ReplyEmbedPM("Logs", strings.Join(logString, ""))
20
}
21
22
// BotCommand special bot commands handler
23
func BotCommand(ctx bot.Context) {
24
	if ctx.IsServerAdmin() {
25
		if len(ctx.Args) == 0 {
26
			return
27
		}
28
		switch ctx.Args[0] {
29
		case "clear":
30
			ctx.MetricsCommand("bot", "clear")
31
			if len(ctx.Args) < 2 {
32
				ctx.BotMsg.Clear(&ctx, 0)
33
				return
34
			}
35
			from, err := strconv.Atoi(ctx.Args[1])
36
			if err != nil {
37
				return
38
			}
39
			ctx.BotMsg.Clear(&ctx, from)
40
		case "logs":
41
			ctx.MetricsCommand("bot", "logs")
42
			if ctx.IsAdmin() {
43
				if len(ctx.Args) < 2 {
44
					showLogs(&ctx, 10)
45
				} else {
46
					count, err := strconv.Atoi(ctx.Args[1])
47
					if err != nil {
48
						fmt.Println(err)
49
						return
50
					}
51
					showLogs(&ctx, count)
52
				}
53
			}
54
		case "conflist":
55
			ctx.MetricsCommand("bot", "conflist")
56
			ctx.ReplyEmbed("Config", ctx.Loc("conf_list"))
57
		case "setconf":
58
			botSetConf(&ctx)
59
		case "stations":
60
			botStations(&ctx)
61
		case "guild":
62
			botGuild(&ctx)
63
		case "stats":
64
			ctx.MetricsCommand("bot", "stats")
65
			if !ctx.IsAdmin() {
66
				return
67
			}
68
			var users int
69
			for _, g := range ctx.Discord.State.Guilds {
70
				users += len(g.Members)
71
			}
72
			ctx.ReplyEmbed("Stats", fmt.Sprintf(ctx.Loc("stats_command"), len(ctx.Discord.State.Guilds), users))
0 ignored issues
show
introduced by
can't check non-constant format in call to Sprintf
Loading history...
73
		case "blacklist":
74
			botBlacklist(&ctx)
75
		}
76
	} else {
77
		ctx.ReplyEmbed("Bot", ctx.Loc("admin_require"))
78
	}
79
}
80
81
func guildsListID(guilds []*discordgo.Guild, current, pages int) string {
82
	var list string
83
	for _, g := range guilds {
84
		var gName string
85
		if len(g.Name) > 20 {
86
			gName = fmt.Sprintf("%v...", g.Name[:20])
87
		} else {
88
			gName = g.Name
89
		}
90
		list += fmt.Sprintf("[%v] - %v\n", g.ID, gName)
91
	}
92
	list += fmt.Sprintf("Page: %v | %v", current, pages)
93
	return list
94
}
95
96
func guildsListName(guilds []*discordgo.Guild, current, pages int) string {
97
	var list string
98
	for i, g := range guilds {
99
		var gName string
100
		if len(g.Name) > 20 {
101
			gName = fmt.Sprintf("%v...", g.Name[:20])
102
		} else {
103
			gName = g.Name
104
		}
105
		list += fmt.Sprintf("[%v] - %v | U: %v\n", i, gName, len(g.Members))
106
	}
107
	list += fmt.Sprintf("Page: %v | %v", current, pages)
108
	return list
109
}
110
111
func botSetConf(ctx *bot.Context) {
112
	ctx.MetricsCommand("bot", "setconf")
113
	if len(ctx.Args) > 2 {
114
		target := strings.Split(ctx.Args[1], ".")
115
		switch target[0] {
116
		case "general":
117
			switch target[1] {
118
			case "language":
119
				ctx.Guilds.Guilds[ctx.Guild.ID].Language = ctx.Args[2]
120
				_ = ctx.DB.Guilds().Update(bson.M{"id": ctx.Guild.ID}, bson.M{"$set": bson.M{"language": ctx.Args[2]}})
121
				ctx.ReplyEmbedPM("Config", fmt.Sprintf("Language set to: %v", ctx.Args[2]))
122
			case "timezone":
123
				tz, err := strconv.Atoi(ctx.Args[1])
124
				if err != nil {
125
					ctx.ReplyEmbedPM("Settings", "Not a number")
126
				}
127
				ctx.Guilds.Guilds[ctx.Guild.ID].Timezone = tz
128
				_ = ctx.DB.Guilds().Update(bson.M{"id": ctx.Guild.ID}, bson.M{"$set": bson.M{"timezone": tz}})
129
				ctx.ReplyEmbedPM("Config", fmt.Sprintf("Timezone set to: %v", ctx.Args[2]))
130
			case "nick":
131
				_ = ctx.Discord.GuildMemberNickname(ctx.Guild.ID, "@me", ctx.Args[2])
132
				ctx.ReplyEmbedPM("Config", fmt.Sprintf("Nickname changed to %v", ctx.Args[2]))
133
			}
134
		case "weather":
135
			switch target[1] {
136
			case "city":
137
				ctx.Guilds.Guilds[ctx.Guild.ID].WeatherCity = ctx.Args[2]
138
				_ = ctx.DB.Guilds().Update(bson.M{"id": ctx.Guild.ID}, bson.M{"$set": bson.M{"weathercity": ctx.Args[2]}})
139
				ctx.ReplyEmbedPM("Config", fmt.Sprintf("Weather city set to: %v", ctx.Args[2]))
140
			}
141
		case "news":
142
			switch target[1] {
143
			case "country":
144
				ctx.Guilds.Guilds[ctx.Guild.ID].NewsCounty = ctx.Args[2]
145
				_ = ctx.DB.Guilds().Update(bson.M{"id": ctx.Guild.ID}, bson.M{"$set": bson.M{"newscounty": ctx.Args[2]}})
146
				ctx.ReplyEmbedPM("Config", fmt.Sprintf("News country set to: %v", ctx.Args[2]))
147
			}
148
		case "embed":
149
			switch target[1] {
150
			case "color":
151
				var color int64
152
				var err error
153
				if strings.HasPrefix(ctx.Args[2], "#") {
154
					color, err = strconv.ParseInt(ctx.Args[2][1:], 16, 32)
155
					if err != nil {
156
						ctx.Log("Config", ctx.Guild.ID, fmt.Sprintf("error setting parameter %v to value %v: %v", ctx.Args[1], target[2], err.Error()))
157
						return
158
					}
159
				} else {
160
					color, err = strconv.ParseInt(ctx.Args[2], 16, 32)
161
					if err != nil {
162
						ctx.Log("Config", ctx.Guild.ID, fmt.Sprintf("error setting parameter %v to value %v: %v", ctx.Args[1], ctx.Args[2], err.Error()))
163
						return
164
					}
165
				}
166
				ctx.Guilds.Guilds[ctx.Guild.ID].EmbedColor = int(color)
167
				_ = ctx.DB.Guilds().Update(bson.M{"id": ctx.Guild.ID}, bson.M{"$set": bson.M{"embedcolor": int(color)}})
168
				ctx.ReplyEmbedPM("Config", fmt.Sprintf("Embed color set to: %v", ctx.Args[2]))
169
			}
170
		}
171
	}
172
}
173
174
func botGuild(ctx *bot.Context) {
175
	ctx.MetricsCommand("bot", "guild")
176
	if len(ctx.Args) < 2 && !ctx.IsAdmin() {
177
		return
178
	}
179
	switch ctx.Arg(1) {
180
	case "leave":
181
		if len(ctx.Args) < 3 {
182
			return
183
		}
184
		err := ctx.Discord.GuildLeave(ctx.Args[2])
185
		if err != nil {
186
			ctx.Log("Guild", ctx.Guild.ID, fmt.Sprintf("error leaving from guild [%v]: %v", ctx.Args[2], err.Error()))
187
			ctx.ReplyEmbedPM("Guild", fmt.Sprintf("Error leaving from guild [%v]: %v", ctx.Args[2], err.Error()))
188
			return
189
		}
190
		ctx.ReplyEmbedPM("Guild", fmt.Sprintf("Leave from guild: %v", ctx.Args[2]))
191
	case "info":
192
		var guild *discordgo.Guild
193
		var err error
194
195
		if len(ctx.Args) < 3 {
196
			guild = ctx.Guild
197
		} else {
198
			guild, err = ctx.Discord.Guild(ctx.Args[2])
199
			if err != nil {
200
				ctx.ReplyEmbed(ctx.Loc("guild_info"), ctx.Loc("guild_not_found"))
201
				return
202
			}
203
		}
204
205
		var (
206
			usersOnline   int
207
			usersOffline  int
208
			usersIdle     int
209
			usersDND      int
210
			usersBot      int
211
			channelsVoice int
212
			channelsText  int
213
			guildEmojis   int
214
			guildRoles    string
215
			guildUsers    int
216
			guildOwner    string
217
		)
218
219
		for _, m := range guild.Members {
220
			if m.User.ID == guild.OwnerID {
221
				guildOwner = m.User.Username + "#" + m.User.Discriminator
222
			}
223
		}
224
225
		for _, p := range guild.Presences {
226
			switch p.Status {
227
			case discordgo.StatusOnline:
228
				usersOnline++
229
			case discordgo.StatusIdle:
230
				usersIdle++
231
			case discordgo.StatusDoNotDisturb:
232
				usersDND++
233
			}
234
		}
235
		guildUsers = len(guild.Members)
236
		usersOffline = guild.MemberCount - (usersOnline + usersIdle + usersDND)
237
238
		for _, m := range guild.Members {
239
			if m.User.Bot {
240
				usersBot++
241
			}
242
		}
243
244
		for _, c := range guild.Channels {
245
			switch c.Type {
246
			case discordgo.ChannelTypeGuildText:
247
				channelsText++
248
			case discordgo.ChannelTypeGuildVoice:
249
				channelsVoice++
250
			}
251
		}
252
253
		for _, _ = range guild.Emojis {
0 ignored issues
show
introduced by
should omit values from range; this loop is equivalent to for range ...
Loading history...
254
			guildEmojis++
255
		}
256
257
		for _, r := range guild.Roles {
258
			if r.Name == "@everyone" {
259
				continue
260
			}
261
			if len(guildRoles+r.Name) < 100 {
262
				guildRoles += r.Name + "\n"
263
			}
264
		}
265
266
		emb := bot.NewEmbed(ctx.Loc("guild_info"))
267
		emb.Color(ctx.GetGuild().EmbedColor)
268
		emb.Field(ctx.Loc("guild_name"), guild.Name, true)
269
		emb.Field(ctx.Loc("guild_emoji"), fmt.Sprintf(ctx.Loc("guild_emoji_count"), guildEmojis), true)
0 ignored issues
show
introduced by
can't check non-constant format in call to Sprintf
Loading history...
270
		emb.Field(ctx.Loc("guild_channels"), fmt.Sprintf(ctx.Loc("guild_channels_format"), channelsText, channelsVoice), true)
0 ignored issues
show
introduced by
can't check non-constant format in call to Sprintf
Loading history...
271
		emb.Field(ctx.Loc("guild_id"), guild.ID, true)
272
		emb.Field(ctx.Loc("guild_users"), fmt.Sprintf(ctx.Loc("guild_users_format"), guildUsers, usersOnline, usersOffline, usersIdle, usersDND, usersBot), true)
0 ignored issues
show
introduced by
can't check non-constant format in call to Sprintf
Loading history...
273
		emb.Field(ctx.Loc("guild_roles"), guildRoles, true)
274
		emb.Field(ctx.Loc("guild_owner"), fmt.Sprintf(ctx.Loc("guild_owner_format"), guildOwner, guild.OwnerID), true)
0 ignored issues
show
introduced by
can't check non-constant format in call to Sprintf
Loading history...
275
		emb.Send(ctx)
276
	case "list":
277
		var selected string
278
		var paged = false
279
		if len(ctx.Args) > 2 && ctx.Args[2] == "id" {
280
			if len(ctx.Args) > 3 {
281
				selected = ctx.Args[3]
282
				paged = true
283
			} else {
284
				selected = "1"
285
			}
286
		} else {
287
			if len(ctx.Args) > 2 {
288
				selected = ctx.Args[2]
289
				paged = true
290
			} else {
291
				selected = "1"
292
			}
293
		}
294
		// calculates count of pages
295
		guilds := ctx.Discord.State.Guilds
296
		pages := 1 + int(len(guilds)/20)
297
		// paginate
298
		var indexTo = 20
299
		if paged {
300
			page, err := strconv.Atoi(selected)
301
			if err == nil {
302
				indexTo = page * 20
303
				indexFrom := indexTo - 20
304
305
				if indexFrom < 0 {
306
					indexFrom = 0
307
				}
308
				if indexTo > len(guilds) {
309
					indexTo = len(guilds) - 1
310
				}
311
				if len(ctx.Args) > 2 && ctx.Args[2] == "id" {
312
					ctx.ReplyEmbed("Guilds", guildsListID(guilds[indexFrom:indexTo], page, pages)+fmt.Sprintf("\nFrom: %v\nTo: %v", indexFrom, indexTo))
313
				} else {
314
					ctx.ReplyEmbed("Guilds", guildsListName(guilds[indexFrom:indexTo], page, pages)+fmt.Sprintf("\nFrom: %v\nTo: %v", indexFrom, indexTo))
315
				}
316
317
			} else {
318
				ctx.ReplyEmbed("Guilds", fmt.Sprintf("Selected: %v\nError: %v", selected, err.Error()))
319
			}
320
321
		} else {
322
			if indexTo > len(guilds) {
323
				indexTo = len(guilds) - 1
324
			}
325
			if len(ctx.Args) > 2 && ctx.Args[2] == "id" {
326
				ctx.ReplyEmbed("Guilds", guildsListID(guilds[:indexTo], 1, 1)+fmt.Sprintf("\nTo: %v", indexTo))
327
			} else {
328
				ctx.ReplyEmbed("Guilds", guildsListName(guilds[:indexTo], 1, 1)+fmt.Sprintf("\nTo: %v", indexTo))
329
			}
330
		}
331
	}
332
}
333
334
func botStations(ctx *bot.Context) {
335
	ctx.MetricsCommand("bot", "stations")
336
	if !ctx.IsAdmin() {
337
		return
338
	}
339
	switch ctx.Args[1] {
340
	case "add":
341
		if len(ctx.Args) > 5 {
342
			name := strings.Join(ctx.Args[5:], " ")
343
			err := ctx.DB.AddRadioStation(name, ctx.Args[3], ctx.Args[4], ctx.Args[2])
344
			if err != nil {
345
				ctx.ReplyEmbed("Stations", "Adding error")
346
			}
347
			ctx.ReplyEmbed("Stations", ctx.Loc("stations_added"))
348
		} else {
349
			ctx.ReplyEmbed("Stations", "Arguments missed")
350
		}
351
	case "remove":
352
		if len(ctx.Args) > 2 {
353
			err := ctx.DB.RemoveRadioStation(ctx.Args[2])
354
			if err != nil {
355
				ctx.ReplyEmbed("Stations", ctx.Loc("stations_removed"))
356
			}
357
		} else {
358
			ctx.ReplyEmbed("Stations", "Arguments missed")
359
		}
360
	}
361
}
362
363
func botBlacklist(ctx *bot.Context) {
364
	if len(ctx.Args) > 2 {
365
		switch ctx.Args[1] {
366
		case "addguild":
367
			ctx.BlacklistAddGuild(ctx.Args[2])
368
			ctx.ReplyEmbed("Bot", fmt.Sprintf(ctx.Loc("blacklist_guild_add"), ctx.Args[2]))
0 ignored issues
show
introduced by
can't check non-constant format in call to Sprintf
Loading history...
369
		case "adduser":
370
			ctx.BlacklistAddUser(ctx.Args[2])
371
			ctx.ReplyEmbed("Bot", fmt.Sprintf(ctx.Loc("blacklist_user_add"), ctx.Args[2]))
0 ignored issues
show
introduced by
can't check non-constant format in call to Sprintf
Loading history...
372
		case "removeuser":
373
			ctx.BlacklistRemoveUser(ctx.Args[2])
374
			ctx.ReplyEmbed("Bot", fmt.Sprintf(ctx.Loc("blacklist_user_remove"), ctx.Args[2]))
0 ignored issues
show
introduced by
can't check non-constant format in call to Sprintf
Loading history...
375
		case "removeguild":
376
			ctx.BlacklistRemoveGuild(ctx.Args[2])
377
			ctx.ReplyEmbed("Bot", fmt.Sprintf(ctx.Loc("blacklist_guild_remove"), ctx.Args[2]))
0 ignored issues
show
introduced by
can't check non-constant format in call to Sprintf
Loading history...
378
		}
379
	}
380
381
}
382