diff --git a/internal/database/migrations/000004_add_sar_role_type.down.sql b/internal/database/migrations/000004_add_sar_role_type.down.sql new file mode 100644 index 0000000..9fe1be3 --- /dev/null +++ b/internal/database/migrations/000004_add_sar_role_type.down.sql @@ -0,0 +1,14 @@ +BEGIN; + CREATE TYPE role_type_new AS ENUM ( + 'normal', + 'moderator', + 'admin', + 'patreon', + ); + UPDATE roles SET role_type = 'normal' WHERE role_type = 'sar'; + ALTER TABLE roles + ALTER COLUMN roles TYPE role_type_new; + USING (roles::text::role_type_new) + DROP TYPE role_type; + ALTER TYPE role_type_new RENAME TO role_type; +COMMIT; diff --git a/internal/database/migrations/000004_add_sar_role_type.up.sql b/internal/database/migrations/000004_add_sar_role_type.up.sql new file mode 100644 index 0000000..0b9c326 --- /dev/null +++ b/internal/database/migrations/000004_add_sar_role_type.up.sql @@ -0,0 +1 @@ +ALTER TYPE role_type ADD VALUE 'sar'; diff --git a/internal/exts/guild/roles.go b/internal/exts/guild/roles.go index 7a90f0a..1598a84 100644 --- a/internal/exts/guild/roles.go +++ b/internal/exts/guild/roles.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + "github.com/bwmarrin/discordgo" "github.com/dustinpianalto/disgoman" "github.com/dustinpianalto/geeksbot" "github.com/dustinpianalto/geeksbot/internal/discord_utils" @@ -169,3 +170,215 @@ func removeModRoleCommandFunc(ctx disgoman.Context, args []string) { _, _ = ctx.Send("Please include at least one role to remove from the moderator or admin lists.") } } + +var MakeRoleSelfAssignableCommand = &disgoman.Command{ + Name: "make-role-self-assignable", + Aliases: []string{"makesar", "addsar"}, + Description: "Makes the passed in role self assignable by anyone", + OwnerOnly: false, + Hidden: false, + RequiredPermissions: disgoman.PermissionManageServer, + Invoke: makeRoleSelfAssignableCommandFunc, +} + +func makeRoleSelfAssignableCommandFunc(ctx disgoman.Context, args []string) { + added := make(map[string]bool) + guild, err := services.GuildService.GetOrCreateGuild(ctx.Guild.ID) + if err != nil { + discord_utils.SendErrorMessage(ctx, "Something went wrong getting the guild", err) + return + } + + roles := append(args, ctx.Message.MentionRoles...) + if len(roles) > 0 { + for _, id := range roles { + if strings.HasPrefix(id, "<@&") && strings.HasSuffix(id, ">") { + continue + } + if _, ok := added[id]; ok { + continue + } + + var role *discordgo.Role + var err error + if role, err = ctx.Session.State.Role(ctx.Guild.ID, id); err != nil { + discord_utils.SendErrorMessage(ctx, fmt.Sprintf("%s does not reference a valid role for this guild", id), err) + return + } + + _, err = services.GuildService.CreateOrUpdateRole(geeksbot.Role{ + ID: role.ID, + RoleType: "sar", + Guild: guild, + }) + if err != nil { + discord_utils.SendErrorMessage(ctx, fmt.Sprintf("There was a problem updating <@&%s>", role.ID), err) + return + } + _, _ = ctx.Send(fmt.Sprintf("%s is now self assignable", role.Name)) + + } + } else { + _, _ = ctx.Send("Please include at least one role to make self assignable") + } + +} + +var RemoveSelfAssignableCommand = &disgoman.Command{ + Name: "remove-self-assignable-role", + Aliases: []string{"removesar"}, + Description: "Makes a role that was previously self assignable not so", + OwnerOnly: false, + Hidden: false, + RequiredPermissions: disgoman.PermissionManageServer, + Invoke: removeSelfAssignableRoleCommandFunc, +} + +func removeSelfAssignableRoleCommandFunc(ctx disgoman.Context, args []string) { + removed := make(map[string]bool) + guild, err := services.GuildService.GetOrCreateGuild(ctx.Guild.ID) + if err != nil { + discord_utils.SendErrorMessage(ctx, "Something went wrong getting the guild", err) + return + } + + roles := append(args, ctx.Message.MentionRoles...) + if len(roles) > 0 { + for _, id := range roles { + if strings.HasPrefix(id, "<@&") && strings.HasSuffix(id, ">") { + continue + } + if _, ok := removed[id]; ok { + continue + } + + var err error + var role *discordgo.Role + if role, err = ctx.Session.State.Role(ctx.Guild.ID, id); err != nil { + discord_utils.SendErrorMessage(ctx, fmt.Sprintf("%s does not reference a valid role for this guild", id), err) + return + } + _, err = services.GuildService.CreateOrUpdateRole(geeksbot.Role{ + ID: role.ID, + RoleType: "normal", + Guild: guild, + }) + if err != nil { + discord_utils.SendErrorMessage(ctx, fmt.Sprintf("There was a problem updating <@&%s>", role.ID), err) + return + } + _, _ = ctx.Send(fmt.Sprintf("%s's self assignability has been removed.", role.Name)) + } + } else { + _, _ = ctx.Send("Please include at least one role to make self assignable") + } + +} + +var SelfAssignRoleCommand = &disgoman.Command{ + Name: "giverole", + Aliases: []string{"iwant", "givetome"}, + Description: "Assigns a person the passed in role if it is self assignable", + OwnerOnly: false, + Hidden: false, + RequiredPermissions: 0, + Invoke: selfAssignRoleCommandFunc, +} + +func selfAssignRoleCommandFunc(ctx disgoman.Context, args []string) { + added := make(map[string]bool) + roles := append(args, ctx.Message.MentionRoles...) + if len(roles) > 0 { + for _, id := range roles { + if strings.HasPrefix(id, "<@&") && strings.HasSuffix(id, ">") { + continue + } + if _, ok := added[id]; ok { + continue + } + var role *discordgo.Role + var err error + if role, err = ctx.Session.State.Role(ctx.Guild.ID, id); err != nil { + discord_utils.SendErrorMessage(ctx, fmt.Sprintf("%s does not reference a valid role for this guild", id), err) + return + } + if memberHasRole(ctx.Member, role.ID) { + _, _ = ctx.Send(fmt.Sprintf("You already have the %s role silly...", role.Name)) + return + } + r, err := services.GuildService.Role(role.ID) + if err != nil || r.RoleType != "sar" { + discord_utils.SendErrorMessage(ctx, fmt.Sprintf("You aren't allowed to assign yourself the %s role", role.Name), err) + return + } + err = ctx.Session.GuildMemberRoleAdd(ctx.Guild.ID, ctx.User.ID, role.ID) + if err != nil { + discord_utils.SendErrorMessage(ctx, "There was a problem adding that role to you.", err) + return + } + _, _ = ctx.Send(fmt.Sprintf("Congratulations! The %s role has been added to your... Ummm... Thing.", role.Name)) + } + } else { + _, _ = ctx.Send("Please include at least one role to make self assignable") + } + +} + +var UnAssignRoleCommand = &disgoman.Command{ + Name: "removerole", + Aliases: []string{"idon'twant"}, + Description: "Removes a role from a person if the role is self assignable", + OwnerOnly: false, + Hidden: false, + RequiredPermissions: 0, + Invoke: unAssignRoleCommandFunc, +} + +func unAssignRoleCommandFunc(ctx disgoman.Context, args []string) { + removed := make(map[string]bool) + roles := append(args, ctx.Message.MentionRoles...) + if len(roles) > 0 { + for _, id := range roles { + if strings.HasPrefix(id, "<@&") && strings.HasSuffix(id, ">") { + continue + } + if _, ok := removed[id]; ok { + continue + } + + var role *discordgo.Role + var err error + if role, err = ctx.Session.State.Role(ctx.Guild.ID, id); err != nil { + discord_utils.SendErrorMessage(ctx, fmt.Sprintf("%s does not reference a valid role for this guild", id), err) + return + } + if !memberHasRole(ctx.Member, role.ID) { + _, _ = ctx.Send(fmt.Sprintf("I can't remove the %s role from you because you don't have it...", role.Name)) + return + } + r, err := services.GuildService.Role(role.ID) + if err != nil || r.RoleType != "sar" { + discord_utils.SendErrorMessage(ctx, fmt.Sprintf("You aren't allowed to assign yourself the %s role", role.Name), err) + return + } + err = ctx.Session.GuildMemberRoleRemove(ctx.Guild.ID, ctx.User.ID, role.ID) + if err != nil { + discord_utils.SendErrorMessage(ctx, "There was a problem removing that role from your account", err) + return + } + _, _ = ctx.Send(fmt.Sprintf("Sad to see you go... but the %s role has been removed.", role.Name)) + } + } else { + _, _ = ctx.Send("Please include at least one role to make self assignable") + } + +} + +func memberHasRole(m *discordgo.Member, id string) bool { + for _, r := range m.Roles { + if r == id { + return true + } + } + return false +}