Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 26 additions & 18 deletions app/http/endpoints/api/panel/panelcreate.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ import (
const freePanelLimit = 3

type panelBody struct {
ChannelId uint64 `json:"channel_id,string"`
MessageId uint64 `json:"message_id,string"`
ChannelId *uint64 `json:"channel_id,string"`
MessageId *uint64 `json:"message_id,string"`
Title string `json:"title"`
Content string `json:"content"`
Colour uint32 `json:"colour"`
Expand All @@ -52,9 +52,13 @@ type panelBody struct {
UseThreads bool `json:"use_threads"`
}

func (p *panelBody) IntoPanelMessageData(customId string, isPremium bool) panelMessageData {
return panelMessageData{
ChannelId: p.ChannelId,
func (p *panelBody) IntoPanelMessageData(customId string, isPremium bool) *panelMessageData {
if p.ChannelId == nil {
// This should never happen due to earlier validation
return nil
}
return &panelMessageData{
ChannelId: *p.ChannelId,
Title: p.Title,
Content: p.Content,
CustomId: customId,
Expand Down Expand Up @@ -87,7 +91,7 @@ func CreatePanel(c *gin.Context) {
return
}

data.MessageId = 0
data.MessageId = nil

// Check panel quota
premiumTier, err := rpc.PremiumClient.GetTierByGuildId(c, guildId, false, botContext.Token, botContext.RateLimiter)
Expand Down Expand Up @@ -168,20 +172,24 @@ func CreatePanel(c *gin.Context) {
}

messageData := data.IntoPanelMessageData(customId, premiumTier > premium.None)
msgId, err := messageData.send(botContext)
if err != nil {
var unwrapped request.RestError
if errors.As(err, &unwrapped) {
if unwrapped.StatusCode == http.StatusForbidden {
c.JSON(400, utils.ErrorStr("Bot does not have permission to send messages in channel %d", data.ChannelId))
var newMsgId *uint64
if messageData != nil {
msgId, err := messageData.send(botContext)
if err != nil {
var unwrapped request.RestError
if errors.As(err, &unwrapped) {
if unwrapped.StatusCode == http.StatusForbidden {
c.JSON(400, utils.ErrorStr("Bot does not have permission to send messages in channel %d", data.ChannelId))
} else {
c.JSON(400, utils.ErrorStr("Failed to send panel message to channel %d: %s", data.ChannelId, unwrapped.ApiError.Message))
}
} else {
c.JSON(400, utils.ErrorStr("Failed to send panel message to channel %d: %s", data.ChannelId, unwrapped.ApiError.Message))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewError(err, "Failed to send panel message to Discord"))
}
} else {
_ = c.AbortWithError(http.StatusInternalServerError, app.NewError(err, "Failed to send panel message to Discord"))
}

return
return
}
newMsgId = &msgId
}

var emojiId *uint64
Expand Down Expand Up @@ -214,7 +222,7 @@ func CreatePanel(c *gin.Context) {

// Store in DB
panel := database.Panel{
MessageId: msgId,
MessageId: newMsgId,
ChannelId: data.ChannelId,
GuildId: guildId,
Title: data.Title,
Expand Down
14 changes: 8 additions & 6 deletions app/http/endpoints/api/panel/paneldelete.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package api

import (
"fmt"
"errors"
"fmt"
"net/http"
"strconv"

Expand Down Expand Up @@ -70,11 +70,13 @@ func DeletePanel(c *gin.Context) {
}

// TODO: Set timeout on context
if err := rest.DeleteMessage(c, botContext.Token, botContext.RateLimiter, panel.ChannelId, panel.MessageId); err != nil {
var unwrapped request.RestError
if !errors.As(err, &unwrapped) || unwrapped.StatusCode != 404 {
_ = c.AbortWithError(http.StatusInternalServerError, app.NewError(err, "Failed to delete panel"))
return
if panel.ChannelId != nil && panel.MessageId != nil {
if err := rest.DeleteMessage(c, botContext.Token, botContext.RateLimiter, *panel.ChannelId, *panel.MessageId); err != nil {
var unwrapped request.RestError
if !errors.As(err, &unwrapped) || unwrapped.StatusCode != 404 {
_ = c.AbortWithError(http.StatusInternalServerError, app.NewError(err, "Failed to delete panel"))
return
}
}
}

Expand Down
10 changes: 7 additions & 3 deletions app/http/endpoints/api/panel/panelmessagedata.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ type panelMessageData struct {
IsPremium bool
}

func panelIntoMessageData(panel database.Panel, isPremium bool) panelMessageData {
func panelIntoMessageData(panel database.Panel, isPremium bool) *panelMessageData {
if panel.ChannelId == nil {
return nil
}

var emote *emoji.Emoji
if panel.EmojiName != nil { // No emoji = nil
if panel.EmojiId == nil { // Unicode emoji
Expand All @@ -42,8 +46,8 @@ func panelIntoMessageData(panel database.Panel, isPremium bool) panelMessageData
}
}

return panelMessageData{
ChannelId: panel.ChannelId,
return &panelMessageData{
ChannelId: *panel.ChannelId,
Title: panel.Title,
Content: panel.Content,
CustomId: panel.CustomId,
Expand Down
43 changes: 27 additions & 16 deletions app/http/endpoints/api/panel/panelresend.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package api

import (
"fmt"
"context"
"errors"
"fmt"
"strconv"

"github.com/TicketsBot-cloud/common/premium"
Expand Down Expand Up @@ -54,13 +54,20 @@ func ResendPanel(ctx *gin.Context) {
return
}

if panel.ChannelId == nil {
ctx.JSON(400, utils.ErrorStr("This panel has no selected channel."))
return
}

// delete old message
// TODO: Use proper context
if err := rest.DeleteMessage(context.Background(), botContext.Token, botContext.RateLimiter, panel.ChannelId, panel.GuildId); err != nil {
var unwrapped request.RestError
if errors.As(err, &unwrapped) && !unwrapped.IsClientError() {
ctx.JSON(500, utils.ErrorStr("Failed to send message. Please try again."))
return
if panel.MessageId != nil {
if err := rest.DeleteMessage(context.Background(), botContext.Token, botContext.RateLimiter, *panel.ChannelId, *panel.MessageId); err != nil {
var unwrapped request.RestError
if errors.As(err, &unwrapped) && !unwrapped.IsClientError() {
ctx.JSON(500, utils.ErrorStr("Failed to send message. Please try again."))
return
}
}
}

Expand All @@ -71,19 +78,23 @@ func ResendPanel(ctx *gin.Context) {
}

messageData := panelIntoMessageData(panel, premiumTier > premium.None)
msgId, err := messageData.send(botContext)
if err != nil {
var unwrapped request.RestError
if errors.As(err, &unwrapped) && unwrapped.StatusCode == 403 {
ctx.JSON(500, utils.ErrorStr("I do not have permission to send messages in the provided channel"))
} else {
ctx.JSON(500, utils.ErrorStr("Failed to send message. Please try again."))
}
var newMsgId *uint64
if messageData != nil {
msgId, err := messageData.send(botContext)
if err != nil {
var unwrapped request.RestError
if errors.As(err, &unwrapped) && unwrapped.StatusCode == 403 {
ctx.JSON(500, utils.ErrorStr("I do not have permission to send messages in the provided channel"))
} else {
ctx.JSON(500, utils.ErrorStr("Failed to send message. Please try again."))
}

return
return
}
newMsgId = &msgId
}

if err = dbclient.Client.Panel.UpdateMessageId(ctx, panel.PanelId, msgId); err != nil {
if err = dbclient.Client.Panel.UpdateMessageId(ctx, panel.PanelId, newMsgId); err != nil {
ctx.JSON(500, utils.ErrorStr("Failed to send message. Please try again."))
return
}
Expand Down
51 changes: 31 additions & 20 deletions app/http/endpoints/api/panel/panelupdate.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,31 +146,42 @@ func UpdatePanel(c *gin.Context) {
existing.ButtonLabel != data.ButtonLabel ||
existing.Disabled != data.Disabled

newMessageId := existing.MessageId
var newMessageId *uint64
if existing.ChannelId != nil && data.ChannelId != nil {
// old message exists and provided channel exists
newMessageId = existing.MessageId
}

if shouldUpdateMessage {
// delete old message, ignoring error
// TODO: Use proper context
_ = rest.DeleteMessage(c, botContext.Token, botContext.RateLimiter, existing.ChannelId, existing.MessageId)
if existing.ChannelId != nil && existing.MessageId != nil {
// delete old message, ignoring error
_ = rest.DeleteMessage(c, botContext.Token, botContext.RateLimiter, *existing.ChannelId, *existing.MessageId)
}

messageData := data.IntoPanelMessageData(existing.CustomId, premiumTier > premium.None)
newMessageId, err = messageData.send(botContext)
if err != nil {
var unwrapped request.RestError
if errors.As(err, &unwrapped) {
if unwrapped.StatusCode == 403 {
c.JSON(403, utils.ErrorStr("I do not have permission to send messages in the specified channel"))
return
} else if unwrapped.StatusCode == 404 {
// Swallow error
// TODO: Make channel_id column nullable, and set to null
} else {
_ = c.AbortWithError(http.StatusInternalServerError, app.NewError(err, "Failed to update panel"))
return
if data.ChannelId == nil {
messageData := data.IntoPanelMessageData(existing.CustomId, premiumTier > premium.None)
if messageData != nil {
messageId, err := messageData.send(botContext)
if err != nil {
var unwrapped request.RestError
if errors.As(err, &unwrapped) {
if unwrapped.StatusCode == 403 {
c.JSON(403, utils.ErrorStr("I do not have permission to send messages in the specified channel"))
return
} else if unwrapped.StatusCode == 404 {
// Swallow error
dbclient.Client.Panel.UpdateChannelId(c, existing.PanelId, nil)
} else {
_ = c.AbortWithError(http.StatusInternalServerError, app.NewError(err, "Failed to update panel"))
return
}
} else {
_ = c.AbortWithError(http.StatusInternalServerError, app.NewError(err, "Failed to update panel"))
return
}
}
} else {
_ = c.AbortWithError(http.StatusInternalServerError, app.NewError(err, "Failed to update panel"))
return
newMessageId = &messageId
}
}
}
Expand Down
5 changes: 4 additions & 1 deletion app/http/endpoints/api/panel/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,11 @@ func validateContent(ctx PanelValidationContext) validation.ValidationFunc {

func validateChannelId(ctx PanelValidationContext) validation.ValidationFunc {
return func() error {
if ctx.Data.ChannelId == nil {
return nil
}
for _, ch := range ctx.Channels {
if ch.Id == ctx.Data.ChannelId && (ch.Type == channel.ChannelTypeGuildText || ch.Type == channel.ChannelTypeGuildNews) {
if ch.Id == *ctx.Data.ChannelId && (ch.Type == channel.ChannelTypeGuildText || ch.Type == channel.ChannelTypeGuildNews) {
return nil
}
}
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/components/manage/PanelCreationForm.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,8 @@
label="Panel Channel"
allowAnnouncementChannel
col4
withNull
nullLabel={"None"}
{channels}
bind:value={data.channel_id}
/>
Expand Down
12 changes: 6 additions & 6 deletions frontend/src/views/panels/Panels.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -179,11 +179,11 @@
<tbody>
{#each panels as panel}
<tr>
<td
>#{channels.find(
(c) => c.id === panel.channel_id,
)?.name ?? "Unknown Channel"}</td
>
{#if panel.channel_id == null || panel.channel_id == "null"}
<td>None</td>
{:else}
<td>#{channels.find((c) => c.id === panel.channel_id)?.name ?? "Unknown Channel"}</td>
{/if}
<td>{panel.title}</td>
<td>
{#if panel.has_support_hours}
Expand All @@ -206,7 +206,7 @@
<td class="actions-cell">
<ActionDropdown bind:this={panel.dropdownRef}>
<button
disabled={panel.force_disabled}
disabled={panel.force_disabled || panel.channel_id == null || panel.channel_id == "null"}
on:click={() => {
resendPanel(panel.panel_id);
panel.dropdownRef?.close();
Expand Down