2024-07-20 23:37:50 +01:00

277 lines
7.1 KiB
Go

package api
import (
"context"
"errors"
"fmt"
"github.com/TicketsBot/GoPanel/botcontext"
dbclient "github.com/TicketsBot/GoPanel/database"
"github.com/TicketsBot/GoPanel/utils"
"github.com/TicketsBot/database"
"github.com/gin-gonic/gin"
"github.com/rxdn/gdl/rest"
"github.com/rxdn/gdl/rest/request"
"strconv"
)
func RemoveMember(ctx *gin.Context) {
guildId, selfId := ctx.Keys["guildid"].(uint64), ctx.Keys["userid"].(uint64)
snowflake, err := strconv.ParseUint(ctx.Param("snowflake"), 10, 64)
if err != nil {
ctx.JSON(400, utils.ErrorJson(err))
return
}
// get entity type
typeParsed, err := strconv.Atoi(ctx.Query("type"))
if err != nil {
ctx.JSON(400, utils.ErrorJson(err))
return
}
entityType, ok := entityTypes[typeParsed]
if !ok {
ctx.JSON(400, utils.ErrorStr("Invalid entity type"))
return
}
teamId := ctx.Param("teamid")
if teamId == "default" {
removeDefaultMember(ctx, guildId, selfId, snowflake, entityType)
} else {
parsed, err := strconv.Atoi(teamId)
if err != nil {
ctx.JSON(400, utils.ErrorStr("Invalid team ID"))
return
}
removeTeamMember(ctx, parsed, guildId, snowflake, entityType)
}
}
func removeDefaultMember(ctx *gin.Context, guildId, selfId, snowflake uint64, entityType entityType) {
// permission check
var isAdmin bool
var err error
switch entityType {
case entityTypeUser:
isAdmin, err = dbclient.Client.Permissions.IsAdmin(ctx, guildId, snowflake)
case entityTypeRole:
isAdmin, err = dbclient.Client.RolePermissions.IsAdmin(ctx, snowflake)
}
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
// only guild owner can remove admins
if isAdmin {
botCtx, err := botcontext.ContextForGuild(guildId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
// TODO: Use proper context
guild, err := botCtx.GetGuild(context.Background(), guildId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
if guild.OwnerId != selfId {
ctx.JSON(403, utils.ErrorStr("Only the server owner can remove admins"))
return
}
}
switch entityType {
case entityTypeUser:
err = dbclient.Client.Permissions.RemoveSupport(ctx, guildId, snowflake)
case entityTypeRole:
err = dbclient.Client.RolePermissions.RemoveSupport(ctx, guildId, snowflake)
}
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
// Remove on-call role
metadata, err := dbclient.Client.GuildMetadata.Get(ctx, guildId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
if metadata.OnCallRole != nil {
botContext, err := botcontext.ContextForGuild(guildId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
if entityType == entityTypeUser {
// If the member is not in the guild we do not have to worry
// TODO: Use proper context
member, err := botContext.GetGuildMember(context.Background(), guildId, snowflake)
if err == nil {
if member.HasRole(*metadata.OnCallRole) {
// Attempt to remove role but ignore failure
// TODO: Use proper context
_ = botContext.RemoveGuildMemberRole(context.Background(), guildId, snowflake, *metadata.OnCallRole)
}
} else {
if err, ok := err.(request.RestError); !ok || err.StatusCode != 404 {
ctx.JSON(500, utils.ErrorJson(err))
return
}
}
} else if entityType == entityTypeRole {
// Recreate role
if err := dbclient.Client.GuildMetadata.SetOnCallRole(ctx, guildId, nil); err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
// TODO: Use proper context
if err := botContext.DeleteGuildRole(context.Background(), guildId, *metadata.OnCallRole); err != nil && !isUnknownRoleError(err) {
ctx.JSON(500, utils.ErrorJson(err))
return
}
if _, err := createOnCallRole(botContext, guildId, nil); err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
} else {
ctx.JSON(500, utils.ErrorStr("Infallible"))
return
}
}
ctx.JSON(200, utils.SuccessResponse)
}
func removeTeamMember(ctx *gin.Context, teamId int, guildId, snowflake uint64, entityType entityType) {
team, exists, err := dbclient.Client.SupportTeam.GetById(ctx, guildId, teamId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
if !exists {
ctx.JSON(404, utils.ErrorStr("Support team with provided ID not found"))
return
}
// Remove from DB
switch entityType {
case entityTypeUser:
err = dbclient.Client.SupportTeamMembers.Delete(ctx, teamId, snowflake)
case entityTypeRole:
err = dbclient.Client.SupportTeamRoles.Delete(ctx, teamId, snowflake)
}
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
// Remove on-call role
if team.OnCallRole != nil {
botContext, err := botcontext.ContextForGuild(guildId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
if entityType == entityTypeUser {
// If the member is not in the guild we do not have to worry
// TODO: Use proper context
member, err := botContext.GetGuildMember(context.Background(), guildId, snowflake)
if err == nil {
if member.HasRole(*team.OnCallRole) {
// Attempt to remove role but ignore failure
// TODO: Use proper context
_ = botContext.RemoveGuildMemberRole(context.Background(), guildId, snowflake, *team.OnCallRole)
}
} else {
var err request.RestError
if !errors.As(err, &err) || err.StatusCode != 404 {
ctx.JSON(500, utils.ErrorJson(err))
return
}
}
// TODO: Use proper context
_ = botContext.RemoveGuildMemberRole(context.Background(), guildId, snowflake, *team.OnCallRole)
} else if entityType == entityTypeRole {
// Recreate role
if err := dbclient.Client.SupportTeam.SetOnCallRole(ctx, teamId, nil); err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
// TODO: Use proper context
if err := botContext.DeleteGuildRole(context.Background(), guildId, *team.OnCallRole); err != nil && !isUnknownRoleError(err) {
ctx.JSON(500, utils.ErrorJson(err))
return
}
if _, err := createOnCallRole(botContext, guildId, &team); err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
} else {
ctx.JSON(500, utils.ErrorStr("Infallible"))
}
}
ctx.JSON(200, utils.SuccessResponse)
}
func createOnCallRole(botContext *botcontext.BotContext, guildId uint64, team *database.SupportTeam) (uint64, error) {
var roleName string
if team == nil {
roleName = "On Call" // TODO: Translate
} else {
roleName = utils.StringMax(fmt.Sprintf("On Call - %s", team.Name), 100)
}
data := rest.GuildRoleData{
Name: roleName,
Hoist: utils.Ptr(false),
Mentionable: utils.Ptr(false),
}
// TODO: Use proper context
role, err := botContext.CreateGuildRole(context.Background(), guildId, data)
if err != nil {
return 0, err
}
if team == nil {
if err := dbclient.Client.GuildMetadata.SetOnCallRole(context.Background(), guildId, &role.Id); err != nil {
return 0, err
}
} else {
if err := dbclient.Client.SupportTeam.SetOnCallRole(context.Background(), team.Id, &role.Id); err != nil {
return 0, err
}
}
return role.Id, nil
}
func isUnknownRoleError(err error) bool {
var restErr request.RestError
if errors.As(err, &restErr) && restErr.ApiError.Message == "Unknown Role" {
return true
}
return false
}