From 5e2b3ad4fc77cb6c9d45fd6d7f5e4a24d58bd47c Mon Sep 17 00:00:00 2001 From: rxdn <29165304+rxdn@users.noreply.github.com> Date: Sun, 10 Sep 2023 17:49:04 +0100 Subject: [PATCH] Better error handling --- app/http/endpoints/api/ticket/closeticket.go | 4 +- app/http/endpoints/api/ticket/getticket.go | 18 ++++----- app/http/endpoints/api/transcripts/get.go | 2 +- app/http/endpoints/api/transcripts/render.go | 2 +- internal/api/error.go | 40 ++++++++++++++++++++ utils/permissionutils.go | 36 +++++++++--------- 6 files changed, 72 insertions(+), 30 deletions(-) create mode 100644 internal/api/error.go diff --git a/app/http/endpoints/api/ticket/closeticket.go b/app/http/endpoints/api/ticket/closeticket.go index efca641..ba6ca13 100644 --- a/app/http/endpoints/api/ticket/closeticket.go +++ b/app/http/endpoints/api/ticket/closeticket.go @@ -54,9 +54,9 @@ func CloseTicket(ctx *gin.Context) { return } - hasPermission, err := utils.HasPermissionToViewTicket(guildId, userId, ticket) + hasPermission, requestErr := utils.HasPermissionToViewTicket(guildId, userId, ticket) if err != nil { - ctx.JSON(500, utils.ErrorJson(err)) + ctx.JSON(requestErr.StatusCode, utils.ErrorJson(requestErr)) return } diff --git a/app/http/endpoints/api/ticket/getticket.go b/app/http/endpoints/api/ticket/getticket.go index 3172ca6..7c6764f 100644 --- a/app/http/endpoints/api/ticket/getticket.go +++ b/app/http/endpoints/api/ticket/getticket.go @@ -23,7 +23,7 @@ func GetTicket(ctx *gin.Context) { if err != nil { ctx.AbortWithStatusJSON(500, gin.H{ "success": false, - "error": err.Error(), + "error": err.Error(), }) return } @@ -50,7 +50,7 @@ func GetTicket(ctx *gin.Context) { if ticket.GuildId != guildId { ctx.AbortWithStatusJSON(403, gin.H{ "success": false, - "error": "Guild ID doesn't match", + "error": "Guild ID doesn't match", }) return } @@ -58,14 +58,14 @@ func GetTicket(ctx *gin.Context) { if !ticket.Open { ctx.AbortWithStatusJSON(404, gin.H{ "success": false, - "error": "Ticket does not exist", + "error": "Ticket does not exist", }) return } - hasPermission, err := utils.HasPermissionToViewTicket(guildId, userId, ticket) + hasPermission, requestErr := utils.HasPermissionToViewTicket(guildId, userId, ticket) if err != nil { - ctx.JSON(500, utils.ErrorJson(err)) + ctx.JSON(requestErr.StatusCode, utils.ErrorJson(requestErr)) return } @@ -98,15 +98,15 @@ func GetTicket(ctx *gin.Context) { } messagesFormatted = append(messagesFormatted, map[string]interface{}{ - "author": message.Author, - "content": content, + "author": message.Author, + "content": content, }) } } ctx.JSON(200, gin.H{ - "success": true, - "ticket": ticket, + "success": true, + "ticket": ticket, "messages": messagesFormatted, }) } diff --git a/app/http/endpoints/api/transcripts/get.go b/app/http/endpoints/api/transcripts/get.go index 792341a..5369fd2 100644 --- a/app/http/endpoints/api/transcripts/get.go +++ b/app/http/endpoints/api/transcripts/get.go @@ -41,7 +41,7 @@ func GetTranscriptHandler(ctx *gin.Context) { if ticket.UserId != userId { hasPermission, err := utils.HasPermissionToViewTicket(guildId, userId, ticket) if err != nil { - ctx.JSON(500, utils.ErrorJson(err)) + ctx.JSON(err.StatusCode, utils.ErrorJson(err)) return } diff --git a/app/http/endpoints/api/transcripts/render.go b/app/http/endpoints/api/transcripts/render.go index 4e5661f..d6b6a03 100644 --- a/app/http/endpoints/api/transcripts/render.go +++ b/app/http/endpoints/api/transcripts/render.go @@ -42,7 +42,7 @@ func GetTranscriptRenderHandler(ctx *gin.Context) { if ticket.UserId != userId { hasPermission, err := utils.HasPermissionToViewTicket(guildId, userId, ticket) if err != nil { - ctx.JSON(500, utils.ErrorJson(err)) + ctx.JSON(err.StatusCode, utils.ErrorJson(err)) return } diff --git a/internal/api/error.go b/internal/api/error.go new file mode 100644 index 0000000..7ab9efe --- /dev/null +++ b/internal/api/error.go @@ -0,0 +1,40 @@ +package api + +import "net/http" + +type RequestError struct { + Err error + UserMessage *string + StatusCode int +} + +func NewError(statusCode int, err error) *RequestError { + return &RequestError{ + Err: err, + StatusCode: statusCode, + } +} + +func NewInternalServerError(err error, message string) *RequestError { + return NewErrorWithMessage(http.StatusInternalServerError, err, message) +} + +func NewDatabaseError(err error) *RequestError { + return NewInternalServerError(err, "Error interacting with database: please contact support") +} + +func NewErrorWithMessage(statusCode int, err error, message string) *RequestError { + return &RequestError{ + Err: err, + UserMessage: &message, + StatusCode: statusCode, + } +} + +func (r *RequestError) Error() string { + if r.UserMessage != nil { + return *r.UserMessage + } else { + return r.Err.Error() + } +} diff --git a/utils/permissionutils.go b/utils/permissionutils.go index bbb73cb..cde81b4 100644 --- a/utils/permissionutils.go +++ b/utils/permissionutils.go @@ -3,9 +3,11 @@ package utils import ( "github.com/TicketsBot/GoPanel/botcontext" dbclient "github.com/TicketsBot/GoPanel/database" + "github.com/TicketsBot/GoPanel/internal/api" "github.com/TicketsBot/common/permission" "github.com/TicketsBot/database" "github.com/rxdn/gdl/objects/member" + "net/http" ) func GetPermissionLevel(guildId, userId uint64) (permission.PermissionLevel, error) { @@ -47,7 +49,7 @@ func GetPermissionLevel(guildId, userId uint64) (permission.PermissionLevel, err } // TODO: Use this on the ticket list -func HasPermissionToViewTicket(guildId, userId uint64, ticket database.Ticket) (bool, error) { +func HasPermissionToViewTicket(guildId, userId uint64, ticket database.Ticket) (bool, *api.RequestError) { // If user opened the ticket, they will always have permission if ticket.UserId == userId && ticket.GuildId == guildId { return true, nil @@ -56,7 +58,7 @@ func HasPermissionToViewTicket(guildId, userId uint64, ticket database.Ticket) ( // Admin override botContext, err := botcontext.ContextForGuild(guildId) if err != nil { - return false, err + return false, api.NewInternalServerError(err, "Error retrieving guild context") } if botContext.IsBotAdmin(userId) { @@ -66,14 +68,14 @@ func HasPermissionToViewTicket(guildId, userId uint64, ticket database.Ticket) ( // Check staff override staffOverride, err := dbclient.Client.StaffOverride.HasActiveOverride(guildId) if err != nil { - return false, err + return false, api.NewDatabaseError(err) } // If staff override enabled and the user is bot staff, grant admin permissions if staffOverride { isBotStaff, err := dbclient.Client.BotStaff.IsStaff(userId) if err != nil { - return false, err + return false, api.NewDatabaseError(err) } if isBotStaff { @@ -84,7 +86,7 @@ func HasPermissionToViewTicket(guildId, userId uint64, ticket database.Ticket) ( // Check if server owner guild, err := botContext.GetGuild(guildId) if err != nil { - return false, err + return false, api.NewInternalServerError(err, "Error retrieving guild object") } if guild.OwnerId == userId { @@ -93,13 +95,13 @@ func HasPermissionToViewTicket(guildId, userId uint64, ticket database.Ticket) ( member, err := botContext.GetGuildMember(guildId, userId) if err != nil { - return false, err + return false, api.NewErrorWithMessage(http.StatusForbidden, err, "User not in server: are you logged into the correct account?") } // Admins should have access to all tickets isAdmin, err := dbclient.Client.Permissions.IsAdmin(guildId, userId) if err != nil { - return false, err + return false, api.NewDatabaseError(err) } if isAdmin { @@ -109,7 +111,7 @@ func HasPermissionToViewTicket(guildId, userId uint64, ticket database.Ticket) ( // TODO: Check in db adminRoles, err := dbclient.Client.RolePermissions.GetAdminRoles(guildId) if err != nil { - return false, err + return false, api.NewDatabaseError(err) } for _, roleId := range adminRoles { @@ -120,7 +122,7 @@ func HasPermissionToViewTicket(guildId, userId uint64, ticket database.Ticket) ( // If ticket is not from a panel, we can use default team perms if ticket.PanelId == nil { - canView, err := isOnDefaultTeam(guildId, userId, botContext, member) + canView, err := isOnDefaultTeam(guildId, member) if err != nil { return false, err } @@ -129,11 +131,11 @@ func HasPermissionToViewTicket(guildId, userId uint64, ticket database.Ticket) ( } else { panel, err := dbclient.Client.Panel.GetById(*ticket.PanelId) if err != nil { - return false, err + return false, api.NewDatabaseError(err) } if panel.WithDefaultTeam { - canView, err := isOnDefaultTeam(guildId, userId, botContext, member) + canView, err := isOnDefaultTeam(guildId, member) if err != nil { return false, err } @@ -146,7 +148,7 @@ func HasPermissionToViewTicket(guildId, userId uint64, ticket database.Ticket) ( // If panel does not use the default team, or the user is not assigned to it, check support teams supportTeams, err := dbclient.Client.PanelTeams.GetTeams(*ticket.PanelId) if err != nil { - return false, err + return false, api.NewDatabaseError(err) } if len(supportTeams) > 0 { @@ -158,7 +160,7 @@ func HasPermissionToViewTicket(guildId, userId uint64, ticket database.Ticket) ( // Check if user is added to support team directly isSupport, err := dbclient.Client.SupportTeamMembers.IsSupportSubset(guildId, userId, supportTeamIds) if err != nil { - return false, err + return false, api.NewDatabaseError(err) } if isSupport { @@ -168,7 +170,7 @@ func HasPermissionToViewTicket(guildId, userId uint64, ticket database.Ticket) ( // Check if user is added to support team via a role isSupport, err = dbclient.Client.SupportTeamRoles.IsSupportAnySubset(guildId, member.Roles, supportTeamIds) if err != nil { - return false, err + return false, api.NewDatabaseError(err) } if isSupport { @@ -180,7 +182,7 @@ func HasPermissionToViewTicket(guildId, userId uint64, ticket database.Ticket) ( } } -func isOnDefaultTeam(guildId, userId uint64, ctx botcontext.BotContext, member member.Member) (bool, error) { +func isOnDefaultTeam(guildId uint64, member member.Member) (bool, *api.RequestError) { // Admin perms are already checked straight away, so we don't need to check for them here // Check user perms for support if isSupport, err := dbclient.Client.Permissions.IsSupport(guildId, member.User.Id); err == nil { @@ -188,13 +190,13 @@ func isOnDefaultTeam(guildId, userId uint64, ctx botcontext.BotContext, member m return true, nil } } else { - return false, err + return false, api.NewDatabaseError(err) } // Check DB for support roles supportRoles, err := dbclient.Client.RolePermissions.GetSupportRoles(guildId) if err != nil { - return false, err + return false, api.NewDatabaseError(err) } for _, supportRoleId := range supportRoles {