Documentation ¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
View Source
var BanCommand = &dgc.Command{ Name: "ban", Domain: "astral.moderation.ban", Aliases: []string{"ban"}, Category: "Moderation", Usage: "ban <user> [length] [reason]", Example: "ban @AmusedGrape 1d beans are good", Description: "Ban a user from the server.", Slash: true, SlashGuilds: []string{os.Getenv("DEV_GUILD")}, IntegrationID: "", Arguments: []*discordgo.ApplicationCommandOption{ { Name: "user", Description: "The user to ban.", Type: discordgo.ApplicationCommandOptionUser, Required: true, }, { Name: "reason", Description: "The reason for the ban.", Type: discordgo.ApplicationCommandOptionString, Required: false, }, { Name: "expiry", Description: "The amount of time the ban should last.", Type: discordgo.ApplicationCommandOptionString, Required: false, }, }, Handler: func(ctx *dgc.Ctx) { database := db.New() self := ctx.CustomObjects.MustGet("self").(types.Bot) if ctx.Arguments.Amount() < 2 { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, fmt.Errorf("Invalid arguments. Please provide a user and a reason."))) return } userId := ctx.Arguments.Get(0).AsUserMentionID() if userId == "" { userId = ctx.Arguments.Get(0).Raw() } victim, err := ctx.Session.GuildMember(ctx.Event.GuildID, userId) if err != nil { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, err)) return } timeout, err := utils.ParseDuration(ctx.Arguments.Get(1).Raw()) if err != nil { timeout = 0 } var remArgs []*dgc.Argument if timeout > 0 { remArgs = ctx.Arguments.GetAll()[2:] } else { timeout = 0 remArgs = ctx.Arguments.GetAll()[1:] } if len(remArgs) < 1 { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, fmt.Errorf("Invalid arguments. Please provide a reason."))) return } var strArgs []string for _, arg := range remArgs { strArgs = append(strArgs, arg.Raw()) } reason := strings.Join(strArgs, " ") if victim.User.ID == ctx.Event.Author.ID { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, fmt.Errorf("You cannot ban yourself."))) return } if victim.User.ID == ctx.Session.State.User.ID { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, fmt.Errorf("You cannot ban me."))) return } if victim.User.Bot { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, fmt.Errorf("You cannot ban bots."))) return } report, err := database.AddReport(types.Report{ Bot: *self.ID, Moderator: ctx.Message.Author.ID, User: victim.User.ID, Guild: ctx.Event.GuildID, Reason: reason, Action: "ban", Expiry: utils.NowAddPtr(timeout), Expires: timeout > 0, }) if err != nil { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, err)) return } expiresValue := "Never" if timeout > 0 { expiresValue = fmt.Sprintf("<t:%d>", report.Expiry.Unix()) } userChannel, err := ctx.Session.UserChannelCreate(victim.User.ID) if err != nil { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, err)) return } guild, err := ctx.Session.Guild(ctx.Message.GuildID) if err != nil { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, err)) return } _, err = ctx.Session.ChannelMessageSendEmbed(userChannel.ID, &discordgo.MessageEmbed{ Title: fmt.Sprintf(":hammer: Banned from %s", guild.Name), Color: 0xff0000, Fields: []*discordgo.MessageEmbedField{ { Name: "Reason", Value: reason, }, { Name: "Moderator", Value: fmt.Sprintf("%s#%s", ctx.Message.Author.Username, ctx.Message.Author.Discriminator), }, { Name: "Expires", Value: expiresValue, }, { Name: "Case ID", Value: fmt.Sprintf("`%s`", *report.ID), }, }, }) err = ctx.Session.GuildBanCreateWithReason(ctx.Event.GuildID, victim.User.ID, reason, 0) if err != nil { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, err)) return } var additionalFields []*discordgo.MessageEmbedField if err != nil { additionalFields = append(additionalFields, &discordgo.MessageEmbedField{ Name: "Error", Value: err.Error(), }) } ctx.ReplyEmbed(utils.GenerateEmbed(*ctx, discordgo.MessageEmbed{ Title: "The Ban Hammer has spoken! 🔨", Description: fmt.Sprintf("%s#%s has been banned.", victim.User.Username, victim.User.Discriminator), Color: 0x00ff00, Fields: append([]*discordgo.MessageEmbedField{ { Name: "Reason", Value: reason, }, { Name: "ID", Value: victim.User.ID, }, { Name: "Moderator", Value: fmt.Sprintf("%s#%s", ctx.Message.Author.Username, ctx.Message.Author.Discriminator), }, { Name: "Banned At", Value: fmt.Sprintf("<t:%d>", time.Now().Unix()), }, { Name: "Expires", Value: expiresValue, }, { Name: "Case ID", Value: fmt.Sprintf("`%s`", *report.ID), }, }, additionalFields...), })) }, }
View Source
var CaseCommand = &dgc.Command{ Name: "case", Domain: "astral.moderation.case", Aliases: []string{"case", "report"}, Usage: "case <case uuid>", Example: "case ff3f3f3f-3f3f-3f3f-3f3f-3f3f3f3f3f3f", Category: "Moderation", Description: "View a case.", Slash: true, SlashGuilds: []string{os.Getenv("DEV_GUILD")}, IntegrationID: "", Handler: func(ctx *dgc.Ctx) { database := db.New() if ctx.Arguments.Amount() < 1 { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, fmt.Errorf("Invalid arguments. Please provide a case uuid."))) return } caseId := ctx.Arguments.Get(0).Raw() c, err := database.GetReport(caseId) if err != nil { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, err)) return } embed := utils.GenerateEmbed(*ctx, discordgo.MessageEmbed{ Title: fmt.Sprintf("Case `%s`", *c.ID), Color: 0x00ff00, Fields: []*discordgo.MessageEmbedField{ { Name: "User", Value: fmt.Sprintf("<@%s>", c.User), Inline: true, }, { Name: "Moderator", Value: fmt.Sprintf("<@%s>", c.Moderator), Inline: true, }, { Name: "Action", Value: cases.Title(language.English, cases.Compact).String(c.Action), Inline: true, }, { Name: "Reason", Value: c.Reason, }, { Name: "Date", Value: fmt.Sprintf("<t:%d>", c.CreatedAt.Unix()), }, }, }) ctx.Session.ChannelMessageSendComplex(ctx.Event.ChannelID, &discordgo.MessageSend{ Embeds: []*discordgo.MessageEmbed{ embed, }, Components: []discordgo.MessageComponent{ discordgo.ActionsRow{ Components: []discordgo.MessageComponent{ discordgo.Button{ Label: "Delete", Style: discordgo.DangerButton, CustomID: fmt.Sprintf("delete_case_%s", *c.ID), Emoji: discordgo.ComponentEmoji{ Name: "🗑️", }, }, }, }, }, Reference: ctx.Event.Reference(), }) ctx.Session.AddHandlerOnce(func(s *discordgo.Session, i *discordgo.InteractionCreate) { if i.Type == discordgo.InteractionMessageComponent { if i.MessageComponentData().CustomID == fmt.Sprintf("delete_case_%s", *c.ID) { err := database.DeleteReport(*c.ID) if err != nil { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, err)) return } embed.Title = fmt.Sprintf("Case `%s` (deleted)", *c.ID) s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseUpdateMessage, Data: &discordgo.InteractionResponseData{ Embeds: []*discordgo.MessageEmbed{ embed, }, Components: []discordgo.MessageComponent{}, }, }) } } }) }, }
View Source
var HistoryCommand = &dgc.Command{ Name: "history", Domain: "astral.moderation.history", Aliases: []string{"history", "modlog", "cases"}, Category: "Moderation", Description: "Show the moderation history of a user, or the whole guild", Usage: "history [user]", Example: "history @AmusedGrape", Slash: true, SlashGuilds: []string{os.Getenv("DEV_GUILD")}, Handler: func(ctx *dgc.Ctx) { ctx.Session.MessageReactionAdd(ctx.Event.ChannelID, ctx.Event.Message.ID, "⌛") p := dgwidgets.NewPaginator(ctx.Session, ctx.Message.ChannelID) database := db.New() filter := types.ReportFilter{} if ctx.Arguments.Amount() > 0 { userId := ctx.Arguments.Get(0).AsUserMentionID() if userId == "" { userId = ctx.Arguments.Get(0).Raw() } filter.User = userId filter.Guild = ctx.Event.GuildID } reports, err := database.GetReportsFiltered(filter) if err != nil { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, err)) return } sort.Slice(reports, func(i, j int) bool { return reports[i].CreatedAt.After(*reports[j].CreatedAt) }) var embeds []*discordgo.MessageEmbed guild, err := ctx.Session.Guild(ctx.Event.GuildID) if err != nil { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, err)) return } for i := 0; i < len(reports); i += 5 { end := i + 5 if end > len(reports) { end = len(reports) } user, err := ctx.Session.User(reports[i].User) if err != nil { return } var fields []*discordgo.MessageEmbedField for _, report := range reports[i:end] { mod, err := ctx.Session.User(report.Moderator) if err != nil { return } val := fmt.Sprintf("Reason: %s\nCreated At: <t:%d>\nID: `%s`", report.Reason, report.CreatedAt.Unix(), *report.ID) if filter.User == "" { val = fmt.Sprintf("User: <@%s>\nReason: %s\nCreated At: <t:%d>\nID: `%s`", report.User, report.Reason, report.CreatedAt.Unix(), *report.ID) } fields = append(fields, &discordgo.MessageEmbedField{ Name: fmt.Sprintf("%s by %s#%s", cases.Title(language.English, cases.Compact).String(report.Action), mod.Username, mod.Discriminator), Value: val, Inline: false, }) } title := fmt.Sprintf("Moderation history for %s#%s", user.Username, user.Discriminator) if filter.User == "" { title = fmt.Sprintf("Moderation history for %s", guild.Name) } embeds = append(embeds, utils.GenerateEmbed(*ctx, discordgo.MessageEmbed{ Title: title, Color: 0x00ff00, Fields: fields, })) } p.Add(embeds...) p.SetPageFooters() p.ColourWhenDone = 0xffff p.Widget.Timeout = time.Minute * 2 ctx.Session.MessageReactionRemove(ctx.Event.ChannelID, ctx.Event.Message.ID, "⌛", ctx.Session.State.User.ID) err = p.Spawn() if err != nil { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, err)) return } }, }
View Source
var KickCommand = &dgc.Command{ Name: "kick", Domain: "astral.moderation.kick", Aliases: []string{"kick"}, Category: "Moderation", Usage: "kick <user> [length] [reason]", Example: "kick @AmusedGrape 1d beans are good", Description: "kick a user from the server.", Slash: true, SlashGuilds: []string{os.Getenv("DEV_GUILD")}, IntegrationID: "", Arguments: []*discordgo.ApplicationCommandOption{ { Name: "user", Description: "The user to kick.", Type: discordgo.ApplicationCommandOptionUser, Required: true, }, { Name: "reason", Description: "The reason for the kick.", Type: discordgo.ApplicationCommandOptionString, Required: false, }, }, Handler: func(ctx *dgc.Ctx) { database := db.New() self := ctx.CustomObjects.MustGet("self").(types.Bot) if ctx.Arguments.Amount() < 2 { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, fmt.Errorf("Invalid arguments. Please provide a user and a reason."))) return } userId := ctx.Arguments.Get(0).AsUserMentionID() if userId == "" { userId = ctx.Arguments.Get(0).Raw() } victim, err := ctx.Session.GuildMember(ctx.Event.GuildID, userId) if err != nil { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, err)) return } args := ctx.Arguments.GetAll()[1:] var argsStr []string for _, arg := range args { argsStr = append(argsStr, arg.Raw()) } reason := strings.Join(argsStr, " ") if victim.User.ID == ctx.Event.Author.ID { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, fmt.Errorf("You cannot kick yourself."))) return } if victim.User.ID == ctx.Session.State.User.ID { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, fmt.Errorf("You cannot kick me."))) return } if victim.User.Bot { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, fmt.Errorf("You cannot kick bots."))) return } report, err := database.AddReport(types.Report{ Bot: *self.ID, Moderator: ctx.Message.Author.ID, User: victim.User.ID, Guild: ctx.Event.GuildID, Reason: reason, Action: "kick", }) if err != nil { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, err)) return } userChannel, err := ctx.Session.UserChannelCreate(victim.User.ID) if err != nil { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, err)) return } guild, err := ctx.Session.Guild(ctx.Message.GuildID) if err != nil { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, err)) return } _, err = ctx.Session.ChannelMessageSendEmbed(userChannel.ID, &discordgo.MessageEmbed{ Title: fmt.Sprintf(":hammer: kickned from %s", guild.Name), Color: 0xff0000, Fields: []*discordgo.MessageEmbedField{ { Name: "Reason", Value: reason, }, { Name: "Moderator", Value: fmt.Sprintf("%s#%s", ctx.Message.Author.Username, ctx.Message.Author.Discriminator), }, { Name: "Case ID", Value: fmt.Sprintf("`%s`", *report.ID), }, }, }) err = ctx.Session.GuildMemberDeleteWithReason(ctx.Event.GuildID, victim.User.ID, reason) if err != nil { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, err)) return } var additionalFields []*discordgo.MessageEmbedField if err != nil { additionalFields = append(additionalFields, &discordgo.MessageEmbedField{ Name: "Error", Value: err.Error(), }) } ctx.ReplyEmbed(utils.GenerateEmbed(*ctx, discordgo.MessageEmbed{ Title: "The Boot has spoken! :boot:", Description: fmt.Sprintf("%s#%s has been kicked.", victim.User.Username, victim.User.Discriminator), Color: 0x00ff00, Fields: append([]*discordgo.MessageEmbedField{ { Name: "Reason", Value: reason, }, { Name: "ID", Value: victim.User.ID, }, { Name: "Moderator", Value: fmt.Sprintf("%s#%s", ctx.Message.Author.Username, ctx.Message.Author.Discriminator), }, { Name: "Kicked At", Value: fmt.Sprintf("<t:%d>", time.Now().Unix()), }, { Name: "Case ID", Value: fmt.Sprintf("`%s`", *report.ID), }, }, additionalFields...), })) }, }
View Source
var MuteCommand = &dgc.Command{ Name: "mute", Domain: "astral.moderation.mute", Aliases: []string{"mute"}, Category: "Moderation", Usage: "mute <user> [length] [reason]", Example: "mute @AmusedGrape 1d beans are good", Description: "Mute a user from the server.", Slash: true, SlashGuilds: []string{os.Getenv("DEV_GUILD")}, Handler: func(ctx *dgc.Ctx) { database := db.New() self := ctx.CustomObjects.MustGet("self").(types.Bot) if ctx.Arguments.Amount() < 2 { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, fmt.Errorf("Invalid arguments. Please provide a user and a reason."))) return } userId := ctx.Arguments.Get(0).AsUserMentionID() if userId == "" { userId = ctx.Arguments.Get(0).Raw() } victim, err := ctx.Session.GuildMember(ctx.Event.GuildID, userId) if err != nil { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, err)) return } timeout, err := utils.ParseDuration(ctx.Arguments.Get(1).Raw()) if err != nil { timeout = 0 } var remArgs []*dgc.Argument if timeout > 0 { remArgs = ctx.Arguments.GetAll()[2:] } else { timeout = 0 remArgs = ctx.Arguments.GetAll()[1:] } if len(remArgs) < 1 { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, fmt.Errorf("Invalid arguments. Please provide a reason."))) return } var strArgs []string for _, arg := range remArgs { strArgs = append(strArgs, arg.Raw()) } reason := strings.Join(strArgs, " ") if victim.User.ID == ctx.Event.Author.ID { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, fmt.Errorf("You cannot mute yourself."))) return } if victim.User.ID == ctx.Session.State.User.ID { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, fmt.Errorf("You cannot mute me."))) return } if victim.User.Bot { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, fmt.Errorf("You cannot mute bots."))) return } report, err := database.AddReport(types.Report{ Bot: *self.ID, Moderator: ctx.Message.Author.ID, User: victim.User.ID, Guild: ctx.Event.GuildID, Reason: reason, Action: "mute", Expiry: utils.NowAddPtr(timeout), Expires: timeout > 0, }) if err != nil { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, err)) return } expiresValue := "Never" if timeout > 0 { expiresValue = fmt.Sprintf("<t:%d>", report.Expiry.Unix()) } userChannel, err := ctx.Session.UserChannelCreate(victim.User.ID) if err != nil { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, err)) return } guild, err := ctx.Session.Guild(ctx.Message.GuildID) if err != nil { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, err)) return } _, err = ctx.Session.ChannelMessageSendEmbed(userChannel.ID, &discordgo.MessageEmbed{ Title: fmt.Sprintf("🤬 Muted from %s", guild.Name), Color: 0xff0000, Fields: []*discordgo.MessageEmbedField{ { Name: "Reason", Value: reason, }, { Name: "Moderator", Value: fmt.Sprintf("%s#%s", ctx.Message.Author.Username, ctx.Message.Author.Discriminator), }, { Name: "Expires", Value: expiresValue, }, { Name: "Case ID", Value: fmt.Sprintf("`%s`", *report.ID), }, }, }) if timeout.Seconds() > 0 && timeout.Hours() <= 672 { discordTimeout := utils.NowAddPtr(timeout) err = ctx.Session.GuildMemberTimeout(ctx.Event.GuildID, victim.User.ID, &discordTimeout) if err != nil { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, err)) return } } if timeout.Hours() > 672 || timeout.Seconds() == 0 { g, err := ctx.Session.State.Guild(ctx.Event.GuildID) if err != nil { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, err)) return } roles := g.Roles if err != nil { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, err)) return } var mutedRole *discordgo.Role for _, role := range roles { if strings.Contains(strings.ToLower(role.Name), "muted") { mutedRole = role break } } if mutedRole == nil { mutedRole, err = ctx.Session.GuildRoleCreate(ctx.Event.GuildID, &discordgo.RoleParams{ Name: "Muted", Color: utils.IntPointer(0), Permissions: utils.Int64Pointer(0), Mentionable: utils.BoolPointer(false), Hoist: utils.BoolPointer(false), }) if err != nil { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, err)) return } if err != nil { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, err)) return } categories, err := ctx.Session.GuildChannels(ctx.Event.GuildID) if err != nil { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, err)) return } for _, category := range categories { if category.Type == discordgo.ChannelTypeGuildCategory { err = ctx.Session.ChannelPermissionSet(category.ID, mutedRole.ID, discordgo.PermissionOverwriteTypeRole, 0, discordgo.PermissionSendMessages) if err != nil { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, err)) return } } } } err = ctx.Session.GuildMemberRoleAdd(ctx.Event.GuildID, victim.User.ID, mutedRole.ID) if err != nil { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, err)) return } } var additionalFields []*discordgo.MessageEmbedField if err != nil { additionalFields = append(additionalFields, &discordgo.MessageEmbedField{ Name: "Error", Value: err.Error(), }) } ctx.ReplyEmbed(utils.GenerateEmbed(*ctx, discordgo.MessageEmbed{ Title: "The Duct Tape has spoken! 🦆", Description: fmt.Sprintf("%s#%s has been muted.", victim.User.Username, victim.User.Discriminator), Color: 0x00ff00, Fields: append([]*discordgo.MessageEmbedField{ { Name: "Reason", Value: reason, }, { Name: "ID", Value: victim.User.ID, }, { Name: "Moderator", Value: fmt.Sprintf("%s#%s", ctx.Message.Author.Username, ctx.Message.Author.Discriminator), }, { Name: "Muted At", Value: fmt.Sprintf("<t:%d>", time.Now().Unix()), }, { Name: "Expires", Value: expiresValue, }, { Name: "Case ID", Value: fmt.Sprintf("`%s`", *report.ID), }, }, additionalFields...), })) }, }
View Source
var UnmuteCommand = &dgc.Command{ Name: "unmute", Domain: "astral.moderation.unmute", Aliases: []string{"unmute"}, Category: "Moderation", Usage: "unmute <user>", Example: "unmute @AmusedGrape", Description: "Unmute a user from the server.", Slash: true, SlashGuilds: []string{os.Getenv("DEV_GUILD")}, Handler: func(ctx *dgc.Ctx) { guild, err := ctx.Session.Guild(ctx.Event.GuildID) if err != nil { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, err)) return } // find the muted role var mutedRole *discordgo.Role for _, role := range guild.Roles { if strings.Contains(strings.ToLower(role.Name), "muted") { mutedRole = role break } } userId := ctx.Arguments.Get(0).AsUserMentionID() if userId == "" { userId = ctx.Arguments.Get(0).Raw() } victim, err := ctx.Session.GuildMember(ctx.Event.GuildID, userId) if err != nil { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, err)) return } var wasMuted bool for _, role := range victim.Roles { if role == mutedRole.ID { err := ctx.Session.GuildMemberRoleRemove(ctx.Event.GuildID, victim.User.ID, mutedRole.ID) if err != nil { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, err)) return } wasMuted = true } } if victim.CommunicationDisabledUntil != nil { err := ctx.Session.GuildMemberTimeout(ctx.Event.GuildID, victim.User.ID, nil) if err != nil { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, err)) return } wasMuted = true } if !wasMuted { ctx.ReplyEmbed(utils.ErrorEmbed(*ctx, fmt.Errorf("%s is not muted.", victim.User.Mention()))) return } ctx.ReplyEmbed(utils.GenerateEmbed(*ctx, discordgo.MessageEmbed{ Title: "Unmuted", Description: fmt.Sprintf("%s has been unmuted by %s", victim.User.Mention(), ctx.Event.Author.Mention()), Color: 0x00ff00, })) }, }
Functions ¶
This section is empty.
Types ¶
This section is empty.
Click to show internal directories.
Click to hide internal directories.