Custom embeds
This commit is contained in:
parent
0b743b52d2
commit
9818bad95e
@ -2,6 +2,7 @@ package api
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/TicketsBot/GoPanel/botcontext"
|
||||
dbclient "github.com/TicketsBot/GoPanel/database"
|
||||
"github.com/TicketsBot/GoPanel/rpc"
|
||||
@ -12,6 +13,7 @@ import (
|
||||
"github.com/TicketsBot/common/premium"
|
||||
"github.com/TicketsBot/database"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/rxdn/gdl/objects/channel"
|
||||
"github.com/rxdn/gdl/objects/guild/emoji"
|
||||
"github.com/rxdn/gdl/objects/interaction/component"
|
||||
@ -33,7 +35,7 @@ type panelBody struct {
|
||||
Colour uint32 `json:"colour"`
|
||||
CategoryId uint64 `json:"category_id,string"`
|
||||
Emoji types.Emoji `json:"emote"`
|
||||
WelcomeMessage *string `json:"welcome_message"`
|
||||
WelcomeMessage *types.CustomEmbed `json:"welcome_message" validate:"omitempty,dive"`
|
||||
Mentions []string `json:"mentions"`
|
||||
WithDefaultTeam bool `json:"default_team"`
|
||||
Teams []int `json:"teams"`
|
||||
@ -66,10 +68,7 @@ func CreatePanel(ctx *gin.Context) {
|
||||
|
||||
botContext, err := botcontext.ContextForGuild(guildId)
|
||||
if err != nil {
|
||||
ctx.AbortWithStatusJSON(500, gin.H{
|
||||
"success": false,
|
||||
"error": err.Error(),
|
||||
})
|
||||
ctx.JSON(500, utils.ErrorJson(err))
|
||||
return
|
||||
}
|
||||
|
||||
@ -137,26 +136,41 @@ func CreatePanel(ctx *gin.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
// Store welcome message embed first
|
||||
var welcomeMessageEmbed *int
|
||||
if data.WelcomeMessage != nil {
|
||||
embed, fields := data.WelcomeMessage.IntoDatabaseStruct()
|
||||
embed.GuildId = guildId
|
||||
|
||||
id, err := dbclient.Client.Embeds.CreateWithFields(embed, fields)
|
||||
if err != nil {
|
||||
ctx.JSON(500, utils.ErrorJson(err))
|
||||
return
|
||||
}
|
||||
|
||||
welcomeMessageEmbed = &id
|
||||
}
|
||||
|
||||
// Store in DB
|
||||
panel := database.Panel{
|
||||
MessageId: msgId,
|
||||
ChannelId: data.ChannelId,
|
||||
GuildId: guildId,
|
||||
Title: data.Title,
|
||||
Content: data.Content,
|
||||
Colour: int32(data.Colour),
|
||||
TargetCategory: data.CategoryId,
|
||||
EmojiId: emojiId,
|
||||
EmojiName: emojiName,
|
||||
WelcomeMessage: data.WelcomeMessage,
|
||||
WithDefaultTeam: data.WithDefaultTeam,
|
||||
CustomId: customId,
|
||||
ImageUrl: data.ImageUrl,
|
||||
ThumbnailUrl: data.ThumbnailUrl,
|
||||
ButtonStyle: int(data.ButtonStyle),
|
||||
ButtonLabel: data.ButtonLabel,
|
||||
FormId: data.FormId,
|
||||
NamingScheme: data.NamingScheme,
|
||||
MessageId: msgId,
|
||||
ChannelId: data.ChannelId,
|
||||
GuildId: guildId,
|
||||
Title: data.Title,
|
||||
Content: data.Content,
|
||||
Colour: int32(data.Colour),
|
||||
TargetCategory: data.CategoryId,
|
||||
EmojiId: emojiId,
|
||||
EmojiName: emojiName,
|
||||
WelcomeMessageEmbed: welcomeMessageEmbed,
|
||||
WithDefaultTeam: data.WithDefaultTeam,
|
||||
CustomId: customId,
|
||||
ImageUrl: data.ImageUrl,
|
||||
ThumbnailUrl: data.ThumbnailUrl,
|
||||
ButtonStyle: int(data.ButtonStyle),
|
||||
ButtonLabel: data.ButtonLabel,
|
||||
FormId: data.FormId,
|
||||
NamingScheme: data.NamingScheme,
|
||||
}
|
||||
|
||||
panelId, err := dbclient.Client.Panel.Create(panel)
|
||||
@ -214,8 +228,27 @@ func CreatePanel(ctx *gin.Context) {
|
||||
}
|
||||
|
||||
var urlRegex = regexp.MustCompile(`^https?://([-a-zA-Z0-9@:%._+~#=]{1,256})\.[a-zA-Z0-9()]{1,63}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)$`)
|
||||
var validate = validator.New()
|
||||
|
||||
func (p *panelBody) doValidations(ctx *gin.Context, guildId uint64) bool {
|
||||
err := validate.Struct(p)
|
||||
if err != nil {
|
||||
validationErrors, ok := err.(validator.ValidationErrors)
|
||||
if !ok {
|
||||
ctx.JSON(500, utils.ErrorStr("An error occurred while validating the panel"))
|
||||
return false
|
||||
}
|
||||
|
||||
formatted := "Your input contained the following errors:"
|
||||
for _, validationError := range validationErrors {
|
||||
formatted += fmt.Sprintf("\n%s", validationError.Error())
|
||||
}
|
||||
|
||||
formatted = strings.TrimSuffix(formatted, "\n")
|
||||
ctx.JSON(400, utils.ErrorStr(formatted))
|
||||
return false
|
||||
}
|
||||
|
||||
botContext, err := botcontext.ContextForGuild(guildId)
|
||||
if err != nil {
|
||||
return false // TODO: Log error
|
||||
@ -254,14 +287,6 @@ func (p *panelBody) doValidations(ctx *gin.Context, guildId uint64) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
if !p.verifyWelcomeMessage() {
|
||||
ctx.JSON(400, gin.H{
|
||||
"success": false,
|
||||
"error": "Welcome message must be blank or between 1 - 4096 characters",
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
if !p.verifyImageUrl() || !p.verifyThumbnailUrl() {
|
||||
ctx.JSON(400, gin.H{
|
||||
"success": false,
|
||||
@ -405,10 +430,6 @@ func (p *panelBody) verifyEmoji(ctx botcontext.BotContext, guildId uint64) bool
|
||||
}
|
||||
}
|
||||
|
||||
func (p *panelBody) verifyWelcomeMessage() bool {
|
||||
return p.WelcomeMessage == nil || (len(*p.WelcomeMessage) > 0 && len(*p.WelcomeMessage) <= 4096)
|
||||
}
|
||||
|
||||
func (p *panelBody) verifyImageUrl() bool {
|
||||
if p.ImageUrl != nil && len(*p.ImageUrl) == 0 {
|
||||
p.ImageUrl = nil
|
||||
|
@ -45,6 +45,14 @@ func DeletePanel(ctx *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// Delete welcome message embed
|
||||
if panel.WelcomeMessageEmbed != nil {
|
||||
if err := database.Client.Embeds.Delete(*panel.WelcomeMessageEmbed); err != nil {
|
||||
ctx.JSON(500, utils.ErrorJson(err))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err := database.Client.Panel.Delete(panelId); err != nil {
|
||||
ctx.JSON(500, utils.ErrorJson(err))
|
||||
return
|
||||
|
@ -14,21 +14,25 @@ import (
|
||||
func ListPanels(ctx *gin.Context) {
|
||||
type panelResponse struct {
|
||||
database.Panel
|
||||
UseCustomEmoji bool `json:"use_custom_emoji"`
|
||||
Emoji types.Emoji `json:"emote"`
|
||||
Mentions []string `json:"mentions"`
|
||||
Teams []int `json:"teams"`
|
||||
UseServerDefaultNamingScheme bool `json:"use_server_default_naming_scheme"`
|
||||
WelcomeMessage *types.CustomEmbed `json:"welcome_message"`
|
||||
UseCustomEmoji bool `json:"use_custom_emoji"`
|
||||
Emoji types.Emoji `json:"emote"`
|
||||
Mentions []string `json:"mentions"`
|
||||
Teams []int `json:"teams"`
|
||||
UseServerDefaultNamingScheme bool `json:"use_server_default_naming_scheme"`
|
||||
}
|
||||
|
||||
guildId := ctx.Keys["guildid"].(uint64)
|
||||
|
||||
panels, err := dbclient.Client.Panel.GetByGuild(guildId)
|
||||
panels, err := dbclient.Client.Panel.GetByGuildWithWelcomeMessage(guildId)
|
||||
if err != nil {
|
||||
ctx.AbortWithStatusJSON(500, gin.H{
|
||||
"success": false,
|
||||
"error": err.Error(),
|
||||
})
|
||||
ctx.JSON(500, utils.ErrorJson(err))
|
||||
return
|
||||
}
|
||||
|
||||
allFields, err := dbclient.Client.EmbedFields.GetAllFieldsForPanels(guildId)
|
||||
if err != nil {
|
||||
ctx.JSON(500, utils.ErrorJson(err))
|
||||
return
|
||||
}
|
||||
|
||||
@ -75,8 +79,15 @@ func ListPanels(ctx *gin.Context) {
|
||||
teamIds = make([]int, 0)
|
||||
}
|
||||
|
||||
var welcomeMessage *types.CustomEmbed
|
||||
if p.WelcomeMessage != nil {
|
||||
fields := allFields[p.WelcomeMessage.Id]
|
||||
welcomeMessage = types.NewCustomEmbed(p.WelcomeMessage, fields)
|
||||
}
|
||||
|
||||
wrapped[i] = panelResponse{
|
||||
Panel: p,
|
||||
Panel: p.Panel,
|
||||
WelcomeMessage: welcomeMessage,
|
||||
UseCustomEmoji: p.EmojiId != nil,
|
||||
Emoji: types.NewEmoji(p.EmojiName, p.EmojiId),
|
||||
Mentions: mentions,
|
||||
|
@ -2,6 +2,7 @@ package api
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/TicketsBot/GoPanel/botcontext"
|
||||
dbclient "github.com/TicketsBot/GoPanel/database"
|
||||
"github.com/TicketsBot/GoPanel/rpc"
|
||||
@ -105,31 +106,67 @@ func UpdatePanel(ctx *gin.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
// Update welcome message
|
||||
var welcomeMessageEmbed *int
|
||||
if data.WelcomeMessage == nil {
|
||||
if existing.WelcomeMessageEmbed != nil { // If welcome message wasn't null, but now is, delete the embed
|
||||
if err := dbclient.Client.Embeds.Delete(*existing.WelcomeMessageEmbed); err != nil {
|
||||
ctx.JSON(500, utils.ErrorJson(err))
|
||||
return
|
||||
}
|
||||
} // else, welcomeMessageEmbed will be nil
|
||||
} else {
|
||||
// TODO: Upsert? Don't think we can, as no unique key in the table, panel_id is in panels table
|
||||
if existing.WelcomeMessageEmbed == nil { // Create
|
||||
embed, fields := data.WelcomeMessage.IntoDatabaseStruct()
|
||||
embed.GuildId = guildId
|
||||
|
||||
id, err := dbclient.Client.Embeds.CreateWithFields(embed, fields)
|
||||
if err != nil {
|
||||
ctx.JSON(500, utils.ErrorJson(err))
|
||||
return
|
||||
}
|
||||
|
||||
welcomeMessageEmbed = &id
|
||||
} else { // Update
|
||||
welcomeMessageEmbed = existing.WelcomeMessageEmbed
|
||||
|
||||
embed, fields := data.WelcomeMessage.IntoDatabaseStruct()
|
||||
embed.Id = *existing.WelcomeMessageEmbed
|
||||
embed.GuildId = guildId
|
||||
|
||||
if err := dbclient.Client.Embeds.UpdateWithFields(embed, fields); err != nil {
|
||||
ctx.JSON(500, utils.ErrorJson(err))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Store in DB
|
||||
panel := database.Panel{
|
||||
PanelId: panelId,
|
||||
MessageId: newMessageId,
|
||||
ChannelId: data.ChannelId,
|
||||
GuildId: guildId,
|
||||
Title: data.Title,
|
||||
Content: data.Content,
|
||||
Colour: int32(data.Colour),
|
||||
TargetCategory: data.CategoryId,
|
||||
EmojiName: emojiName,
|
||||
EmojiId: emojiId,
|
||||
WelcomeMessage: data.WelcomeMessage,
|
||||
WithDefaultTeam: data.WithDefaultTeam,
|
||||
CustomId: existing.CustomId,
|
||||
ImageUrl: data.ImageUrl,
|
||||
ThumbnailUrl: data.ThumbnailUrl,
|
||||
ButtonStyle: int(data.ButtonStyle),
|
||||
ButtonLabel: data.ButtonLabel,
|
||||
FormId: data.FormId,
|
||||
NamingScheme: data.NamingScheme,
|
||||
PanelId: panelId,
|
||||
MessageId: newMessageId,
|
||||
ChannelId: data.ChannelId,
|
||||
GuildId: guildId,
|
||||
Title: data.Title,
|
||||
Content: data.Content,
|
||||
Colour: int32(data.Colour),
|
||||
TargetCategory: data.CategoryId,
|
||||
EmojiName: emojiName,
|
||||
EmojiId: emojiId,
|
||||
WelcomeMessageEmbed: welcomeMessageEmbed,
|
||||
WithDefaultTeam: data.WithDefaultTeam,
|
||||
CustomId: existing.CustomId,
|
||||
ImageUrl: data.ImageUrl,
|
||||
ThumbnailUrl: data.ThumbnailUrl,
|
||||
ButtonStyle: int(data.ButtonStyle),
|
||||
ButtonLabel: data.ButtonLabel,
|
||||
FormId: data.FormId,
|
||||
NamingScheme: data.NamingScheme,
|
||||
}
|
||||
|
||||
if err = dbclient.Client.Panel.Update(panel); err != nil {
|
||||
ctx.AbortWithStatusJSON(500, utils.ErrorJson(err))
|
||||
ctx.JSON(500, utils.ErrorJson(err))
|
||||
return
|
||||
}
|
||||
|
||||
@ -149,7 +186,7 @@ func UpdatePanel(ctx *gin.Context) {
|
||||
} else {
|
||||
roleId, err := strconv.ParseUint(mention, 10, 64)
|
||||
if err != nil {
|
||||
ctx.AbortWithStatusJSON(500, utils.ErrorJson(err))
|
||||
ctx.JSON(500, utils.ErrorJson(err))
|
||||
return
|
||||
}
|
||||
|
||||
@ -159,6 +196,7 @@ func UpdatePanel(ctx *gin.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println(panel.PanelId)
|
||||
if err := dbclient.Client.PanelUserMention.Set(panel.PanelId, shouldMentionUser); err != nil {
|
||||
ctx.AbortWithStatusJSON(500, utils.ErrorJson(err))
|
||||
return
|
||||
|
@ -12,5 +12,6 @@
|
||||
font-size: 14px;
|
||||
padding: 0 4px;
|
||||
margin-left: 4px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
</style>
|
80
frontend/src/components/Collapsible.svelte
Normal file
80
frontend/src/components/Collapsible.svelte
Normal file
@ -0,0 +1,80 @@
|
||||
<div style="margin-bottom: 8px">
|
||||
<div style="cursor: pointer;" class="inline" on:click={toggle}>
|
||||
{#if expanded}
|
||||
<i class="{retractIcon}"></i>
|
||||
{:else}
|
||||
<i class="{expandIcon}"></i>
|
||||
{/if}
|
||||
|
||||
<slot name="header"></slot>
|
||||
|
||||
<hr/>
|
||||
</div>
|
||||
|
||||
<div bind:this={content} class="content">
|
||||
<slot name="content"></slot>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
import {onMount} from "svelte";
|
||||
|
||||
export let retractIcon = "fas fa-minus";
|
||||
export let expandIcon = "fas fa-plus";
|
||||
|
||||
let expanded = false;
|
||||
let showOverflow = true;
|
||||
|
||||
let content;
|
||||
|
||||
export function toggle() {
|
||||
if (expanded) {
|
||||
content.style.maxHeight = 0;
|
||||
} else {
|
||||
updateSize();
|
||||
}
|
||||
|
||||
expanded = !expanded;
|
||||
}
|
||||
|
||||
export function updateSize() {
|
||||
content.style.maxHeight = `${content.scrollHeight}px`;
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
const fn = (e) => {
|
||||
if (expanded) {
|
||||
updateSize();
|
||||
}
|
||||
}
|
||||
|
||||
content.addEventListener('DOMNodeInserted', fn);
|
||||
content.addEventListener('DOMNodeRemoved', fn);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.content {
|
||||
display: flex;
|
||||
transition: max-height .3s ease-in-out, margin-top .3s ease-in-out, margin-bottom .3s ease-in-out;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
max-height: 0;
|
||||
}
|
||||
|
||||
.inline {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
hr {
|
||||
border-top: 1px solid #777;
|
||||
border-bottom: 0;
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
208
frontend/src/components/EmbedBuilder.svelte
Normal file
208
frontend/src/components/EmbedBuilder.svelte
Normal file
@ -0,0 +1,208 @@
|
||||
<div class="modal" transition:fade>
|
||||
<div class="modal-wrapper">
|
||||
<Card footer="{true}" footerRight="{true}" fill="{false}">
|
||||
<span slot="title">Embed Builder</span>
|
||||
|
||||
<div slot="body" class="body-wrapper">
|
||||
<form class="form-wrapper" on:submit|preventDefault>
|
||||
<div class="row">
|
||||
<Colour col3 label="Embed Colour" bind:value={data.colour}/>
|
||||
<Input col3 label="Title" placeholder="Embed Title" bind:value={data.title}/>
|
||||
<Input col3 label="Title URL (Optional)" placeholder="https://example.com" bind:value={data.url}/>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<Textarea col1 label="Description" placeholder="Large text area, up to 4096 characters"
|
||||
bind:value={data.description}/>
|
||||
</div>
|
||||
|
||||
<Collapsible>
|
||||
<span slot="header">Author</span>
|
||||
|
||||
<div slot="content" class="row">
|
||||
<Input col3 label="Author Name" placeholder="Author Name" bind:value={data.author.name}/>
|
||||
<Input col3 label="Author Icon URL (Optional)" placeholder="https://example.com/image.png"
|
||||
tooltipText="Small icon displayed in the top left" bind:value={data.author.icon_url}/>
|
||||
<Input col3 label="Author URL (Optional)" placeholder="https://example.com"
|
||||
tooltipText="Hyperlink on the author's name" bind:value={data.author.url}/>
|
||||
</div>
|
||||
</Collapsible>
|
||||
|
||||
<Collapsible>
|
||||
<span slot="header">Images</span>
|
||||
<div slot="content" class="row">
|
||||
<Input col2 label="Large Image URL" placeholder="https://example.com/image.png"
|
||||
bind:value={data.image_url}/>
|
||||
<Input col2 label="Small Image URL" placeholder="https://example.com/image.png"
|
||||
bind:value={data.thumbnail_url}/>
|
||||
</div>
|
||||
</Collapsible>
|
||||
|
||||
<Collapsible>
|
||||
<span slot="header">Footer</span>
|
||||
<div slot="content" class="row">
|
||||
<Input col3 label="Footer Text" placeholder="Footer Text" badge="Premium" bind:value={data.footer.text}/>
|
||||
<Input col3 label="Footer Icon URL (Optional)" badge="Premium" placeholder="https://example.com/image.png"
|
||||
bind:value={data.footer.icon_url}/>
|
||||
<DateTimePicker col3 label="Footer Timestamp (Optional)" bind:value={data.timestamp}/>
|
||||
</div>
|
||||
</Collapsible>
|
||||
|
||||
<Collapsible>
|
||||
<span slot="header">Fields</span>
|
||||
<div slot="content" class="col-1">
|
||||
{#each data.fields as field, i}
|
||||
<div class="row" style="justify-content: flex-start; gap: 10px">
|
||||
<Input col2 label="Field Name" placeholder="Field Name" bind:value={field.name}/>
|
||||
<Checkbox label="Inline" bind:value={field.inline}/>
|
||||
|
||||
<div style="margin-top: 18px; display: flex; align-self: center">
|
||||
<Button danger icon="fas fa-trash-can" on:click={() => deleteField(i)}>Delete</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<Textarea col1 label="Field Value" placeholder="Large text area, up to 1024 characters"
|
||||
bind:value={field.value}/>
|
||||
</div>
|
||||
{/each}
|
||||
<Button type="button" icon="fas fa-plus" fullWidth on:click={addField}>Add Field</Button>
|
||||
</div>
|
||||
</Collapsible>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div slot="footer">
|
||||
<Button danger={true} on:click={dispatchClose}>Cancel</Button>
|
||||
<div style="margin-left: 12px">
|
||||
<Button icon="fas fa-paper-plane" on:click={dispatchConfirm}>Submit</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-backdrop" transition:fade>
|
||||
</div>
|
||||
|
||||
<svelte:window on:keydown={handleKeydown}/>
|
||||
|
||||
<script>
|
||||
import {createEventDispatcher} from 'svelte';
|
||||
import {fade} from 'svelte/transition'
|
||||
import Card from "./Card.svelte";
|
||||
import Button from "./Button.svelte";
|
||||
import Input from "./form/Input.svelte";
|
||||
import Colour from "./form/Colour.svelte";
|
||||
import Textarea from "./form/Textarea.svelte";
|
||||
import DateTimePicker from "./form/DateTimePicker.svelte";
|
||||
import Collapsible from "./Collapsible.svelte";
|
||||
import Checkbox from "./form/Checkbox.svelte";
|
||||
|
||||
export let guildId;
|
||||
|
||||
export let data;
|
||||
|
||||
if (data === undefined || data === null) {
|
||||
if (!data) {
|
||||
data = {};
|
||||
}
|
||||
|
||||
data.fields = [];
|
||||
data.colour = '#2ECC71';
|
||||
data.author = {};
|
||||
data.footer = {};
|
||||
}
|
||||
|
||||
function addField() {
|
||||
data.fields.push({name: '', value: '', inline: false});
|
||||
data = data;
|
||||
}
|
||||
|
||||
function deleteField(i) {
|
||||
data.fields.splice(i, 1);
|
||||
data = data;
|
||||
}
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
function dispatchClose() {
|
||||
dispatch('close', {});
|
||||
}
|
||||
|
||||
// Dispatch with data
|
||||
function dispatchConfirm() {
|
||||
// Map blank strings to null
|
||||
const mapper = (obj) => {
|
||||
Object.keys(obj).forEach(key => {
|
||||
if (typeof obj[key] === 'string' && obj[key] === '') {
|
||||
obj[key] = null;
|
||||
} else if (typeof obj[key] === 'object') {
|
||||
mapper(obj[key]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
mapper(data);
|
||||
|
||||
dispatch('confirm', data);
|
||||
}
|
||||
|
||||
function handleKeydown(e) {
|
||||
if (e.key === "Escape") {
|
||||
dispatchClose();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.modal {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 999;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.modal-wrapper {
|
||||
display: flex;
|
||||
width: 60%;
|
||||
margin: 10% auto auto auto;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1280px) {
|
||||
.modal-wrapper {
|
||||
width: 96%;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-backdrop {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 500;
|
||||
background-color: #000;
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
.form-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
42
frontend/src/components/form/DateTimePicker.svelte
Normal file
42
frontend/src/components/form/DateTimePicker.svelte
Normal file
@ -0,0 +1,42 @@
|
||||
<div class:col-1={col1} class:col-2={col2} class:col-3={col3} class:col-4={col4}>
|
||||
{#if label !== undefined}
|
||||
<div class="label-wrapper">
|
||||
<label for="picker" class="form-label">
|
||||
{label}
|
||||
</label>
|
||||
</div>
|
||||
{/if}
|
||||
<input type="datetime-local" id="picker" class="form-input" disabled="{disabled}"
|
||||
bind:this={picker} on:input on:change bind:value={value} on:click={() => picker.showPicker()}>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let picker;
|
||||
|
||||
export let value;
|
||||
export let label;
|
||||
export let placeholder;
|
||||
export let disabled = false;
|
||||
|
||||
export let col1 = false;
|
||||
export let col2 = false;
|
||||
export let col3 = false;
|
||||
export let col4 = false;
|
||||
</script>
|
||||
|
||||
<style>
|
||||
input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.label-wrapper {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.tooltip-icon {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
@ -1,22 +1,23 @@
|
||||
<div class:col-1={col1} class:col-2={col2} class:col-3={col3} class:col-4={col4}>
|
||||
{#if label !== undefined}
|
||||
<div class="label-wrapper">
|
||||
<label for="input" class="form-label">
|
||||
{label}
|
||||
</label>
|
||||
{#if tooltipText !== undefined}
|
||||
<div style="margin-bottom: 5px">
|
||||
<Tooltip tip={tooltipText} top color="#121212">
|
||||
{#if tooltipLink !== undefined}
|
||||
<a href={tooltipLink} target="_blank">
|
||||
<i class="fas fa-circle-info form-label tooltip-icon"></i>
|
||||
</a>
|
||||
{:else}
|
||||
<i class="fas fa-circle-info form-label tooltip-icon"></i>
|
||||
{/if}
|
||||
</Tooltip>
|
||||
</div>
|
||||
{/if}
|
||||
<label for="input" class="form-label">{label}</label>
|
||||
{#if badge !== undefined}
|
||||
<Badge>{badge}</Badge>
|
||||
{/if}
|
||||
{#if tooltipText !== undefined}
|
||||
<div style="margin-bottom: 5px">
|
||||
<Tooltip tip={tooltipText} top color="#121212">
|
||||
{#if tooltipLink !== undefined}
|
||||
<a href={tooltipLink} target="_blank">
|
||||
<i class="fas fa-circle-info form-label tooltip-icon"></i>
|
||||
</a>
|
||||
{:else}
|
||||
<i class="fas fa-circle-info form-label tooltip-icon"></i>
|
||||
{/if}
|
||||
</Tooltip>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
<input id="input" class="form-input" placeholder="{placeholder}" disabled="{disabled}" on:input on:change
|
||||
@ -25,10 +26,12 @@
|
||||
|
||||
<script>
|
||||
import Tooltip from 'svelte-tooltip';
|
||||
import Badge from "../Badge.svelte";
|
||||
|
||||
export let value;
|
||||
export let label;
|
||||
export let placeholder;
|
||||
export let badge;
|
||||
export let disabled = false;
|
||||
|
||||
export let tooltipText = undefined;
|
||||
|
@ -69,6 +69,7 @@
|
||||
.modal-wrapper {
|
||||
display: flex;
|
||||
width: 75%;
|
||||
margin: 10% auto auto auto;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1280px) {
|
||||
|
@ -1,3 +1,9 @@
|
||||
{#if welcomeMessageBuilder}
|
||||
<EmbedBuilder data={data.welcome_message}
|
||||
on:close={closeWelcomeMessageBuilder}
|
||||
on:confirm={handleWelcomeMessageUpdate}/>
|
||||
{/if}
|
||||
|
||||
<form class="settings-form" on:submit|preventDefault>
|
||||
<div class="row">
|
||||
<div class="col-1-3">
|
||||
@ -68,9 +74,35 @@
|
||||
class:advanced-settings-hide={!advancedSettings} class:show-overflow={overflowShow}>
|
||||
<div class="inner" class:inner-show={advancedSettings} class:absolute={advancedSettings && !overflowShow} >
|
||||
<div class="row">
|
||||
<Textarea col1=true bind:value={data.welcome_message} label="Welcome Message"
|
||||
placeholder="If blank, your server's default welcome message will be used"
|
||||
on:input={handleWelcomeMessageUpdate}/>
|
||||
<div class="col-2">
|
||||
<label class="form-label">Welcome Message</label>
|
||||
<div class="row" style="justify-content: flex-start; gap: 10px">
|
||||
<Button icon="fas fa-brush" on:click={openWelcomeMessageBuilder}>Open Editor</Button>
|
||||
<Button icon="fas fa-trash-can" danger
|
||||
on:click={() => data.welcome_message = null}>Clear</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-2">
|
||||
<label for="naming-scheme-wrapper" class="form-label">Naming Scheme</label>
|
||||
<div class="row" id="naming-scheme-wrapper">
|
||||
<div>
|
||||
<label class="form-label">Use Server Default</label>
|
||||
<Toggle hideLabel
|
||||
toggledColor="#66bb6a"
|
||||
untoggledColor="#ccc"
|
||||
bind:toggled={data.use_server_default_naming_scheme} />
|
||||
</div>
|
||||
<div class="col-fill">
|
||||
{#if !data.use_server_default_naming_scheme}
|
||||
<Input label="Naming Scheme"
|
||||
bind:value={data.naming_scheme}
|
||||
placeholder="ticket-%id%"
|
||||
tooltipText="Click here for the full placeholder list"
|
||||
tooltipLink="https://docs.ticketsbot.net" />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-2">
|
||||
@ -104,29 +136,6 @@
|
||||
<Input col2={true} label="Large Image URL" bind:value={data.image_url} placeholder="https://example.com/image.png" />
|
||||
<Input col2={true} label="Small Image URL" bind:value={data.thumbnail_url} placeholder="https://example.com/image.png" />
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-2">
|
||||
<label for="naming-scheme-wrapper" class="form-label">Naming Scheme</label>
|
||||
<div class="row" id="naming-scheme-wrapper">
|
||||
<div>
|
||||
<label class="form-label">Use Server Default</label>
|
||||
<Toggle hideLabel
|
||||
toggledColor="#66bb6a"
|
||||
untoggledColor="#ccc"
|
||||
bind:toggled={data.use_server_default_naming_scheme} />
|
||||
</div>
|
||||
<div class="col-fill">
|
||||
{#if !data.use_server_default_naming_scheme}
|
||||
<Input label="Naming Scheme"
|
||||
bind:value={data.naming_scheme}
|
||||
placeholder="ticket-%id%"
|
||||
tooltipText="Click here for the full placeholder list"
|
||||
tooltipLink="https://docs.ticketsbot.net" />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@ -137,6 +146,7 @@
|
||||
import Colour from "../form/Colour.svelte";
|
||||
import Button from "../Button.svelte";
|
||||
import ChannelDropdown from "../ChannelDropdown.svelte";
|
||||
import EmbedBuilder from "../EmbedBuilder.svelte";
|
||||
|
||||
import {createEventDispatcher, onMount} from 'svelte';
|
||||
import {colourToInt, intToColour} from "../../js/util";
|
||||
@ -145,9 +155,7 @@
|
||||
import EmojiItem from "../EmojiItem.svelte";
|
||||
import Select from 'svelte-select';
|
||||
import Dropdown from "../form/Dropdown.svelte";
|
||||
import Checkbox from "../form/Checkbox.svelte";
|
||||
import Toggle from "svelte-toggle";
|
||||
import Slider from "../form/Slider.svelte";
|
||||
|
||||
export let guildId;
|
||||
export let seedDefault = true;
|
||||
@ -173,6 +181,17 @@
|
||||
let selectedTeams = seedDefault ? [{id: 'default', name: 'Default'}] : [];
|
||||
let selectedMentions = [];
|
||||
|
||||
let welcomeMessageBuilder = false;
|
||||
|
||||
function openWelcomeMessageBuilder() {
|
||||
welcomeMessageBuilder = true;
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
}
|
||||
|
||||
function closeWelcomeMessageBuilder() {
|
||||
welcomeMessageBuilder = false;
|
||||
}
|
||||
|
||||
// Replace spaces with dashes in naming scheme as the user types
|
||||
$: if (data.naming_scheme !== undefined && data.naming_scheme !== null && data.naming_scheme.includes(' ')) {
|
||||
data.naming_scheme = data.naming_scheme.replaceAll(' ', '-');
|
||||
@ -222,10 +241,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
function handleWelcomeMessageUpdate() {
|
||||
if (data.welcome_message === "") {
|
||||
data.welcome_message = null;
|
||||
}
|
||||
function handleWelcomeMessageUpdate(e) {
|
||||
data.welcome_message = e.detail;
|
||||
closeWelcomeMessageBuilder();
|
||||
}
|
||||
|
||||
function handleEmojiTypeChange(e) {
|
||||
|
@ -74,6 +74,7 @@
|
||||
.modal-wrapper {
|
||||
display: flex;
|
||||
width: 75%;
|
||||
margin: 10% auto auto auto;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1280px) {
|
||||
|
14
go.mod
14
go.mod
@ -6,14 +6,15 @@ require (
|
||||
github.com/BurntSushi/toml v0.3.1
|
||||
github.com/TicketsBot/archiverclient v0.0.0-20220326163414-558fd52746dc
|
||||
github.com/TicketsBot/common v0.0.0-20220615205931-a6a31e73b52a
|
||||
github.com/TicketsBot/database v0.0.0-20220623211222-6d64f44d5cfb
|
||||
github.com/TicketsBot/database v0.0.0-20220627203133-dd19fe34f094
|
||||
github.com/TicketsBot/logarchiver v0.0.0-20220326162808-cdf0310f5e1c
|
||||
github.com/TicketsBot/worker v0.0.0-20220621165800-203b0004b733
|
||||
github.com/TicketsBot/worker v0.0.0-20220627203254-f37bdb40b39a
|
||||
github.com/apex/log v1.1.2
|
||||
github.com/getsentry/sentry-go v0.13.0
|
||||
github.com/gin-contrib/static v0.0.0-20191128031702-f81c604d8ac2
|
||||
github.com/gin-gonic/contrib v0.0.0-20191209060500-d6e26eeaa607
|
||||
github.com/gin-gonic/gin v1.7.7
|
||||
github.com/go-playground/validator/v10 v10.11.0
|
||||
github.com/go-redis/redis v6.15.9+incompatible
|
||||
github.com/go-redis/redis/v8 v8.11.3
|
||||
github.com/go-redis/redis_rate/v9 v9.1.1
|
||||
@ -39,9 +40,8 @@ require (
|
||||
github.com/getsentry/raven-go v0.2.0 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-errors/errors v1.1.0 // indirect
|
||||
github.com/go-playground/locales v0.13.0 // indirect
|
||||
github.com/go-playground/universal-translator v0.17.0 // indirect
|
||||
github.com/go-playground/validator/v10 v10.6.1 // indirect
|
||||
github.com/go-playground/locales v0.14.0 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.0 // indirect
|
||||
github.com/gofrs/uuid v3.3.0+incompatible // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/gomodule/redigo v2.0.0+incompatible // indirect
|
||||
@ -60,7 +60,7 @@ require (
|
||||
github.com/juju/ratelimit v1.0.1 // indirect
|
||||
github.com/klauspost/compress v1.10.10 // indirect
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
|
||||
github.com/leodido/go-urn v1.2.0 // indirect
|
||||
github.com/leodido/go-urn v1.2.1 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
||||
@ -71,7 +71,7 @@ require (
|
||||
github.com/tatsuworks/czlib v0.0.0-20190916144400-8a51758ea0d9 // indirect
|
||||
github.com/ugorji/go/codec v1.2.6 // indirect
|
||||
go.uber.org/atomic v1.6.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect
|
||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac // indirect
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
|
49
go.sum
49
go.sum
@ -5,18 +5,15 @@ github.com/TicketsBot/archiverclient v0.0.0-20220326163414-558fd52746dc h1:n15W8
|
||||
github.com/TicketsBot/archiverclient v0.0.0-20220326163414-558fd52746dc/go.mod h1:2KcfHS0JnSsgcxZBs3NyWMXNQzEo67mBSGOyzHPWOCc=
|
||||
github.com/TicketsBot/common v0.0.0-20220615205931-a6a31e73b52a h1:SwA18cDURmnXSrKBdetNVanSsyJBMtyosDzvgYMpKP4=
|
||||
github.com/TicketsBot/common v0.0.0-20220615205931-a6a31e73b52a/go.mod h1:ZAoYcDD7SQLTsZT7dbo/X0J256+pogVRAReunCGng+U=
|
||||
github.com/TicketsBot/database v0.0.0-20220623160906-a56dc9dfda90 h1:K0t6IaZdeZzEr2BaYj/NBuWIm/hA31jkqFh2c3nyDrw=
|
||||
github.com/TicketsBot/database v0.0.0-20220623160906-a56dc9dfda90/go.mod h1:F57cywrZsnper1cy56Bx0c/HEsxQBLHz3Pl98WXblWw=
|
||||
github.com/TicketsBot/database v0.0.0-20220623203124-d335941a5a86 h1:oCynNT5m2nP5y+rf52/tGGhRGI85C3YSaoI4Ox3RuLs=
|
||||
github.com/TicketsBot/database v0.0.0-20220623203124-d335941a5a86/go.mod h1:F57cywrZsnper1cy56Bx0c/HEsxQBLHz3Pl98WXblWw=
|
||||
github.com/TicketsBot/database v0.0.0-20220623211222-6d64f44d5cfb h1:nLL2HT+RZVnGIi474Al+xdLiBH9Wsr287m7tBAePJQY=
|
||||
github.com/TicketsBot/database v0.0.0-20220623211222-6d64f44d5cfb/go.mod h1:F57cywrZsnper1cy56Bx0c/HEsxQBLHz3Pl98WXblWw=
|
||||
github.com/TicketsBot/database v0.0.0-20220627203133-dd19fe34f094 h1:a272Wj4At5XjIjLoRAdn4PwfZ288+A4QzwTvFAR6fho=
|
||||
github.com/TicketsBot/database v0.0.0-20220627203133-dd19fe34f094/go.mod h1:F57cywrZsnper1cy56Bx0c/HEsxQBLHz3Pl98WXblWw=
|
||||
github.com/TicketsBot/logarchiver v0.0.0-20220326162808-cdf0310f5e1c h1:OqGjFH6mbE6gd+NqI2ARJdtH3UUvhiAkD0r0fhGJK2s=
|
||||
github.com/TicketsBot/logarchiver v0.0.0-20220326162808-cdf0310f5e1c/go.mod h1:jgi2OXQKsd5nUnTIRkwvPmeuD/i7OhN68LKMssuQY1c=
|
||||
github.com/TicketsBot/ttlcache v1.6.1-0.20200405150101-acc18e37b261 h1:NHD5GB6cjlkpZFjC76Yli2S63/J2nhr8MuE6KlYJpQM=
|
||||
github.com/TicketsBot/ttlcache v1.6.1-0.20200405150101-acc18e37b261/go.mod h1:2zPxDAN2TAPpxUPjxszjs3QFKreKrQh5al/R3cMXmYk=
|
||||
github.com/TicketsBot/worker v0.0.0-20220621165800-203b0004b733 h1:G4iUjk4lgGRvbRCSJshpwuQetl+z3v7PmHzIW+HII9k=
|
||||
github.com/TicketsBot/worker v0.0.0-20220621165800-203b0004b733/go.mod h1:fhEqdxVhgXds/xB3ql05XSDqPLF4XWjkfyHr+JQFe0g=
|
||||
github.com/TicketsBot/worker v0.0.0-20220627203254-f37bdb40b39a h1:cx2YtngcJ7KpOBm/QotWKHb2XZbvUDJwD9azBl31e/k=
|
||||
github.com/TicketsBot/worker v0.0.0-20220627203254-f37bdb40b39a/go.mod h1:R70+F86Z+UlretKMxOX1jRqCwvVlvuem9UAyAL4EiG8=
|
||||
github.com/apex/log v1.1.2 h1:bnDuVoi+o98wOdVqfEzNDlY0tcmBia7r4YkjS9EqGYk=
|
||||
github.com/apex/log v1.1.2/go.mod h1:SyfRweFO+TlkIJ3DVizTSeI1xk7jOIIqOnUPZQTTsww=
|
||||
github.com/apex/logs v0.0.3/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo=
|
||||
@ -37,6 +34,7 @@ github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMe
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@ -68,14 +66,16 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V
|
||||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
|
||||
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
|
||||
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
|
||||
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
|
||||
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
|
||||
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
|
||||
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
||||
github.com/go-playground/validator/v10 v10.6.1 h1:W6TRDXt4WcWp4c4nf/G+6BkGdhiIo0k417gfr+V6u4I=
|
||||
github.com/go-playground/validator/v10 v10.6.1/go.mod h1:xm76BBt941f7yWdGnI2DVPFFg1UK3YY04qifoXU3lOk=
|
||||
github.com/go-playground/validator/v10 v10.11.0 h1:0W+xRM511GY47Yy3bZUbJVitCNg2BOGlCyvTqsp/xIw=
|
||||
github.com/go-playground/validator/v10 v10.11.0/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
|
||||
github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
|
||||
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||
github.com/go-redis/redis/v8 v8.3.4/go.mod h1:jszGxBCez8QA1HWSmQxJO9Y82kNibbUmeYhKWrBejTU=
|
||||
@ -200,13 +200,18 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
|
||||
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
|
||||
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
@ -234,7 +239,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
@ -252,6 +256,7 @@ github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+t
|
||||
github.com/pasztorpisti/qs v0.0.0-20171216220353-8d6c33ee906c h1:Gcce/r5tSQeprxswXXOwQ/RBU1bjQWVd9dB7QKoPXBE=
|
||||
github.com/pasztorpisti/qs v0.0.0-20171216220353-8d6c33ee906c/go.mod h1:1iCZ0433JJMecYqCa+TdWA9Pax8MGl4ByuNDZ7eSnQY=
|
||||
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
@ -261,6 +266,9 @@ github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
|
||||
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
|
||||
@ -289,6 +297,7 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/tatsuworks/czlib v0.0.0-20190916144400-8a51758ea0d9 h1:i2aD44Moa5N5pt/WNwHLvIklzPymtr8vkkBlVdNElUE=
|
||||
github.com/tatsuworks/czlib v0.0.0-20190916144400-8a51758ea0d9/go.mod h1:6HrfShlf4bKeQEFdWn4JP/yet/mHW2RhxOQf0e3HWA0=
|
||||
github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0=
|
||||
@ -324,8 +333,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M=
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
@ -340,7 +349,8 @@ golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwY
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20211008194852-3b03d305991f h1:1scJEYZBaF48BaG6tYbtxmLcXqwYGSfGcMoStTqkkIw=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
|
||||
@ -368,6 +378,7 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac h1:oN6lz7iLW/YC7un8pq+9bOLyXrprv2+DKfkJY+2LJJw=
|
||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
@ -411,7 +422,8 @@ gopkg.in/alexcesaro/statsd.v2 v2.0.0 h1:FXkZSCZIH17vLCO5sO2UucTHsH9pc+17F6pl3JVC
|
||||
gopkg.in/alexcesaro/statsd.v2 v2.0.0/go.mod h1:i0ubccKGzBVNBpdGV5MocxyA/XlLUJzA7SLonnE4drU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||
@ -428,6 +440,7 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
nhooyr.io/websocket v1.8.4 h1:P43INlkmY2eCxLvHeiMFK/ROUiOm0NdzRGGDtURbe58=
|
||||
nhooyr.io/websocket v1.8.4/go.mod h1:LiqdCg1Cu7TPWxEvPjPa0TGYxCsy4pHNTN9gGluwBpQ=
|
||||
|
38
utils/types/colour.go
Normal file
38
utils/types/colour.go
Normal file
@ -0,0 +1,38 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Colour uint32
|
||||
|
||||
func (c Colour) Uint32() uint32 {
|
||||
return uint32(c)
|
||||
}
|
||||
|
||||
func (c Colour) MarshalJSON() ([]byte, error) {
|
||||
return []byte(fmt.Sprintf(`"#%06x"`, c)), nil
|
||||
}
|
||||
|
||||
func (c *Colour) UnmarshalJSON(b []byte) error {
|
||||
if len(b) < 2 {
|
||||
return fmt.Errorf("invalid colour")
|
||||
}
|
||||
|
||||
s := string(b)[1 : len(b)-1] // Trim quotes
|
||||
s = strings.TrimPrefix(s, `#`) // Trim # if present
|
||||
|
||||
tmp, err := strconv.ParseUint(s, 16, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if tmp > 0xFFFFFF {
|
||||
return fmt.Errorf("colour value %v is out of range", tmp)
|
||||
}
|
||||
|
||||
*c = Colour(tmp)
|
||||
return nil
|
||||
}
|
141
utils/types/customembed.go
Normal file
141
utils/types/customembed.go
Normal file
@ -0,0 +1,141 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/utils"
|
||||
"github.com/TicketsBot/database"
|
||||
"github.com/rxdn/gdl/objects/channel/embed"
|
||||
)
|
||||
|
||||
type CustomEmbed struct {
|
||||
Title *string `json:"title" validate:"omitempty,min=1,max=255"`
|
||||
Description *string `json:"description" validate:"omitempty,min=1,max=4096"`
|
||||
Url *string `json:"url" validate:"omitempty,url"`
|
||||
Colour Colour `json:"colour" validate:"required,gte=0,lte=16777215"`
|
||||
Author Author `json:"author" validate:"dive"`
|
||||
ImageUrl *string `json:"image_url" validate:"omitempty,url"`
|
||||
ThumbnailUrl *string `json:"thumbnail_url" validate:"omitempty,url"`
|
||||
Footer Footer `json:"footer" validate:"dive"`
|
||||
Timestamp *DateTimeLocal `json:"timestamp" validate:"omitempty"`
|
||||
Fields []Field `json:"fields" validate:"dive,max=25"`
|
||||
}
|
||||
|
||||
type Author struct {
|
||||
Name *string `json:"name" validate:"omitempty,min=1,max=255"`
|
||||
IconUrl *string `json:"icon_url" validate:"omitempty,url"`
|
||||
Url *string `json:"url" validate:"omitempty,url"`
|
||||
}
|
||||
|
||||
type Footer struct {
|
||||
Text *string `json:"text" validate:"omitempty,min=1,max=2048"`
|
||||
IconUrl *string `json:"icon_url" validate:"omitempty,url"`
|
||||
}
|
||||
|
||||
type Field struct {
|
||||
Name string `json:"name" validate:"min=1,max=255"`
|
||||
Value string `json:"value" validate:"min=1,max=1024"`
|
||||
Inline bool `json:"inline"`
|
||||
}
|
||||
|
||||
func NewCustomEmbed(c *database.CustomEmbed, fields []database.EmbedField) *CustomEmbed {
|
||||
wrappedFields := make([]Field, len(fields))
|
||||
for i, field := range fields {
|
||||
wrappedFields[i] = Field{
|
||||
Name: field.Name,
|
||||
Value: field.Value,
|
||||
Inline: field.Inline,
|
||||
}
|
||||
}
|
||||
|
||||
return &CustomEmbed{
|
||||
Title: c.Title,
|
||||
Description: c.Description,
|
||||
Url: c.Url,
|
||||
Colour: Colour(c.Colour),
|
||||
Author: Author{
|
||||
Name: c.AuthorName,
|
||||
IconUrl: c.AuthorIconUrl,
|
||||
Url: c.AuthorUrl,
|
||||
},
|
||||
ImageUrl: c.ImageUrl,
|
||||
ThumbnailUrl: c.ThumbnailUrl,
|
||||
Footer: Footer{
|
||||
Text: c.FooterText,
|
||||
IconUrl: c.FooterIconUrl,
|
||||
},
|
||||
Timestamp: NewDateTimeLocalFromPtr(c.Timestamp),
|
||||
Fields: wrappedFields,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *CustomEmbed) IntoDatabaseStruct() (*database.CustomEmbed, []database.EmbedField) {
|
||||
fields := make([]database.EmbedField, len(c.Fields))
|
||||
for i, field := range c.Fields {
|
||||
fields[i] = database.EmbedField{
|
||||
Name: field.Name,
|
||||
Value: field.Value,
|
||||
Inline: field.Inline,
|
||||
}
|
||||
}
|
||||
|
||||
return &database.CustomEmbed{
|
||||
Title: c.Title,
|
||||
Description: c.Description,
|
||||
Url: c.Url,
|
||||
Colour: uint32(c.Colour),
|
||||
AuthorName: c.Author.Name,
|
||||
AuthorIconUrl: c.Author.IconUrl,
|
||||
AuthorUrl: c.Author.Url,
|
||||
ImageUrl: c.ImageUrl,
|
||||
ThumbnailUrl: c.ThumbnailUrl,
|
||||
FooterText: c.Footer.Text,
|
||||
FooterIconUrl: c.Footer.IconUrl,
|
||||
Timestamp: TimeOrNil(c.Timestamp),
|
||||
}, fields
|
||||
}
|
||||
|
||||
func (c *CustomEmbed) IntoDiscordEmbed() *embed.Embed {
|
||||
e := &embed.Embed{
|
||||
Title: utils.ValueOrZero(c.Title),
|
||||
Description: utils.ValueOrZero(c.Description),
|
||||
Url: utils.ValueOrZero(c.Url),
|
||||
Timestamp: TimeOrNil(c.Timestamp),
|
||||
Color: int(c.Colour),
|
||||
}
|
||||
|
||||
if c.Footer.Text != nil {
|
||||
e.Footer = &embed.EmbedFooter{
|
||||
Text: *c.Footer.Text,
|
||||
IconUrl: utils.ValueOrZero(c.Footer.IconUrl),
|
||||
}
|
||||
}
|
||||
|
||||
if c.ImageUrl != nil {
|
||||
e.SetImage(*c.ImageUrl)
|
||||
}
|
||||
|
||||
if c.ThumbnailUrl != nil {
|
||||
e.SetThumbnail(*c.ThumbnailUrl)
|
||||
}
|
||||
|
||||
if c.Author.Name != nil {
|
||||
e.Author = &embed.EmbedAuthor{
|
||||
Name: *c.Author.Name,
|
||||
IconUrl: utils.ValueOrZero(c.Author.IconUrl),
|
||||
Url: utils.ValueOrZero(c.Author.Url),
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.Fields) > 0 {
|
||||
e.Fields = make([]*embed.EmbedField, len(c.Fields))
|
||||
|
||||
for i, field := range c.Fields {
|
||||
e.Fields[i] = &embed.EmbedField{
|
||||
Name: field.Name,
|
||||
Value: field.Value,
|
||||
Inline: field.Inline,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return e
|
||||
}
|
49
utils/types/datetimelocal.go
Normal file
49
utils/types/datetimelocal.go
Normal file
@ -0,0 +1,49 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/TicketsBot/GoPanel/utils"
|
||||
"time"
|
||||
)
|
||||
|
||||
type DateTimeLocal time.Time
|
||||
|
||||
var format = "2006-01-02T15:04"
|
||||
|
||||
func NewDateTimeLocalFromPtr(t *time.Time) *DateTimeLocal {
|
||||
if t == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return utils.Ptr(DateTimeLocal(*t))
|
||||
}
|
||||
|
||||
func TimeOrNil(d *DateTimeLocal) *time.Time {
|
||||
if d == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return utils.Ptr(d.Time())
|
||||
}
|
||||
|
||||
func (d DateTimeLocal) Time() time.Time {
|
||||
return time.Time(d)
|
||||
}
|
||||
|
||||
func (d DateTimeLocal) MarshalJSON() ([]byte, error) {
|
||||
return []byte(fmt.Sprintf(`"%s"`, time.Time(d).Format(format))), nil
|
||||
}
|
||||
|
||||
func (d *DateTimeLocal) UnmarshalJSON(b []byte) error {
|
||||
if len(b) < 2 || b[0] != '"' || b[len(b)-1] != '"' {
|
||||
return fmt.Errorf("invalid DateTimeLocal")
|
||||
}
|
||||
|
||||
tmp, err := time.Parse(format, string(b[1:len(b)-1]))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*d = DateTimeLocal(tmp)
|
||||
return nil
|
||||
}
|
@ -3,3 +3,11 @@ package utils
|
||||
func Ptr[T any](v T) *T {
|
||||
return &v
|
||||
}
|
||||
|
||||
func ValueOrZero[T any](v *T) T {
|
||||
if v == nil {
|
||||
return *new(T)
|
||||
} else {
|
||||
return *v
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user