update panels
This commit is contained in:
parent
ca7eee6daa
commit
66d54b4e03
@ -228,11 +228,11 @@ func (p *panel) verifyContent() bool {
|
||||
return len(p.Content) > 0 && len(p.Content) < 1025
|
||||
}
|
||||
|
||||
func (p *panel) getEmoji() (string, bool) {
|
||||
func (p *panel) getEmoji() (emoji string, ok bool) {
|
||||
p.Emote = strings.Replace(p.Emote, ":", "", -1)
|
||||
|
||||
emoji := utils.GetEmojiByName(p.Emote)
|
||||
return emoji, emoji != ""
|
||||
emoji, ok = utils.GetEmoji(p.Emote)
|
||||
return
|
||||
}
|
||||
|
||||
func (p *panel) verifyChannel(channels []channel.Channel) bool {
|
||||
|
206
app/http/endpoints/api/panelupdate.go
Normal file
206
app/http/endpoints/api/panelupdate.go
Normal file
@ -0,0 +1,206 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/botcontext"
|
||||
dbclient "github.com/TicketsBot/GoPanel/database"
|
||||
"github.com/TicketsBot/GoPanel/rpc"
|
||||
"github.com/TicketsBot/common/premium"
|
||||
"github.com/TicketsBot/database"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/rxdn/gdl/rest"
|
||||
"github.com/rxdn/gdl/rest/request"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func UpdatePanel(ctx *gin.Context) {
|
||||
guildId := ctx.Keys["guildid"].(uint64)
|
||||
|
||||
botContext, err := botcontext.ContextForGuild(guildId)
|
||||
if err != nil {
|
||||
ctx.AbortWithStatusJSON(500, gin.H{
|
||||
"success": false,
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
var data panel
|
||||
|
||||
if err := ctx.BindJSON(&data); err != nil {
|
||||
ctx.AbortWithStatusJSON(400, gin.H{
|
||||
"success": false,
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
messageId, err := strconv.ParseUint(ctx.Param("message"), 10, 64)
|
||||
if err != nil {
|
||||
ctx.AbortWithStatusJSON(400, gin.H{
|
||||
"success": false,
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
data.MessageId = messageId
|
||||
|
||||
// get existing
|
||||
existing, err := dbclient.Client.Panel.Get(data.MessageId)
|
||||
if err != nil {
|
||||
ctx.AbortWithStatusJSON(500, gin.H{
|
||||
"success": false,
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// check guild ID matches
|
||||
if existing.GuildId != guildId {
|
||||
ctx.AbortWithStatusJSON(400, gin.H{
|
||||
"success": false,
|
||||
"error": "Guild ID does not match",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if !data.doValidations(ctx, guildId) {
|
||||
return
|
||||
}
|
||||
|
||||
// check if we need to update the message
|
||||
shouldUpdateMessage := uint32(existing.Colour) != data.Colour ||
|
||||
existing.ChannelId != data.ChannelId ||
|
||||
existing.Content != data.Content ||
|
||||
existing.Title != data.Title ||
|
||||
existing.ReactionEmote != data.Emote
|
||||
|
||||
emoji, _ := data.getEmoji() // already validated
|
||||
newMessageId := messageId
|
||||
|
||||
if shouldUpdateMessage {
|
||||
// delete old message
|
||||
if err := rest.DeleteMessage(botContext.Token, botContext.RateLimiter, existing.ChannelId, existing.MessageId); err != nil {
|
||||
ctx.AbortWithStatusJSON(500, gin.H{
|
||||
"success": false,
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
premiumTier := rpc.PremiumClient.GetTierByGuildId(guildId, true, botContext.Token, botContext.RateLimiter)
|
||||
newMessageId, err = data.sendEmbed(&botContext, premiumTier > premium.None)
|
||||
if err != nil {
|
||||
if err == request.ErrForbidden {
|
||||
ctx.AbortWithStatusJSON(500, gin.H{
|
||||
"success": false,
|
||||
"error": "I do not have permission to send messages in the specified channel",
|
||||
})
|
||||
} else {
|
||||
// TODO: Most appropriate error?
|
||||
ctx.AbortWithStatusJSON(500, gin.H{
|
||||
"success": false,
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Add reaction
|
||||
if err = rest.CreateReaction(botContext.Token, botContext.RateLimiter, data.ChannelId, newMessageId, emoji); err != nil {
|
||||
if err == request.ErrForbidden {
|
||||
ctx.AbortWithStatusJSON(500, gin.H{
|
||||
"success": false,
|
||||
"error": "I do not have permission to add reactions in the specified channel",
|
||||
})
|
||||
} else {
|
||||
// TODO: Most appropriate error?
|
||||
ctx.AbortWithStatusJSON(500, gin.H{
|
||||
"success": false,
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Store in DB
|
||||
panel := database.Panel{
|
||||
MessageId: newMessageId,
|
||||
ChannelId: data.ChannelId,
|
||||
GuildId: guildId,
|
||||
Title: data.Title,
|
||||
Content: data.Content,
|
||||
Colour: int32(data.Colour),
|
||||
TargetCategory: data.CategoryId,
|
||||
ReactionEmote: emoji,
|
||||
WelcomeMessage: data.WelcomeMessage,
|
||||
}
|
||||
|
||||
if err = dbclient.Client.Panel.Update(messageId, panel); err != nil {
|
||||
ctx.AbortWithStatusJSON(500, gin.H{
|
||||
"success": false,
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// insert role mention data
|
||||
// delete old data
|
||||
if err = dbclient.Client.PanelRoleMentions.DeleteAll(newMessageId); err != nil {
|
||||
ctx.AbortWithStatusJSON(500, gin.H{
|
||||
"success": false,
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: Reduce to 1 query
|
||||
if err = dbclient.Client.PanelUserMention.Set(newMessageId, false); err != nil {
|
||||
ctx.AbortWithStatusJSON(500, gin.H{
|
||||
"success": false,
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// string is role ID or "user" to mention the ticket opener
|
||||
for _, mention := range data.Mentions {
|
||||
if mention == "user" {
|
||||
if err = dbclient.Client.PanelUserMention.Set(newMessageId, true); err != nil {
|
||||
ctx.AbortWithStatusJSON(500, gin.H{
|
||||
"success": false,
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
} else {
|
||||
roleId, err := strconv.ParseUint(mention, 10, 64)
|
||||
if err != nil {
|
||||
ctx.AbortWithStatusJSON(500, gin.H{
|
||||
"success": false,
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// should we check the role is a valid role in the guild?
|
||||
// not too much of an issue if it isnt
|
||||
|
||||
if err = dbclient.Client.PanelRoleMentions.Add(newMessageId, roleId); err != nil {
|
||||
ctx.AbortWithStatusJSON(500, gin.H{
|
||||
"success": false,
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx.JSON(200, gin.H{
|
||||
"success": true,
|
||||
"message_id": strconv.FormatUint(newMessageId, 10),
|
||||
})
|
||||
}
|
@ -89,6 +89,7 @@ func StartServer() {
|
||||
|
||||
guildAuthApi.GET("/panels", api.ListPanels)
|
||||
guildAuthApi.PUT("/panels", api.CreatePanel)
|
||||
guildAuthApi.PUT("/panels/:message", api.UpdatePanel)
|
||||
guildAuthApi.DELETE("/panels/:message", api.DeletePanel)
|
||||
|
||||
guildAuthApi.GET("/logs/", api.GetLogs)
|
||||
@ -142,36 +143,43 @@ func createRenderer() multitemplate.Renderer {
|
||||
r = addManageTemplate(r, "blacklist")
|
||||
r = addManageTemplate(r, "logs")
|
||||
r = addManageTemplate(r, "modmaillogs")
|
||||
r = addManageTemplate(r, "settings")
|
||||
r = addManageTemplate(r, "settings", "./public/templates/includes/substitutionmodal.tmpl")
|
||||
r = addManageTemplate(r, "ticketlist")
|
||||
r = addManageTemplate(r, "ticketview")
|
||||
r = addManageTemplate(r, "panels")
|
||||
r = addManageTemplate(r, "panels", "./public/templates/includes/substitutionmodal.tmpl", "./public/templates/includes/paneleditmodal.tmpl")
|
||||
r = addManageTemplate(r, "tags")
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func addMainTemplate(renderer multitemplate.Renderer, name string) multitemplate.Renderer {
|
||||
renderer.AddFromFiles(fmt.Sprintf("main/%s", name),
|
||||
func addMainTemplate(renderer multitemplate.Renderer, name string, extra ...string) multitemplate.Renderer {
|
||||
files := []string{
|
||||
"./public/templates/layouts/main.tmpl",
|
||||
"./public/templates/includes/head.tmpl",
|
||||
"./public/templates/includes/sidebar.tmpl",
|
||||
"./public/templates/includes/loadingscreen.tmpl",
|
||||
fmt.Sprintf("./public/templates/views/%s.tmpl", name),
|
||||
)
|
||||
}
|
||||
|
||||
files = append(files, extra...)
|
||||
|
||||
renderer.AddFromFiles(fmt.Sprintf("main/%s", name), files...)
|
||||
return renderer
|
||||
}
|
||||
|
||||
func addManageTemplate(renderer multitemplate.Renderer, name string) multitemplate.Renderer {
|
||||
renderer.AddFromFiles(fmt.Sprintf("manage/%s", name),
|
||||
func addManageTemplate(renderer multitemplate.Renderer, name string, extra ...string) multitemplate.Renderer {
|
||||
files := []string{
|
||||
"./public/templates/layouts/manage.tmpl",
|
||||
"./public/templates/includes/head.tmpl",
|
||||
"./public/templates/includes/sidebar.tmpl",
|
||||
"./public/templates/includes/navbar.tmpl",
|
||||
"./public/templates/includes/substitutionmodal.tmpl",
|
||||
"./public/templates/includes/loadingscreen.tmpl",
|
||||
fmt.Sprintf("./public/templates/views/%s.tmpl", name),
|
||||
)
|
||||
}
|
||||
|
||||
files = append(files, extra...)
|
||||
|
||||
renderer.AddFromFiles(fmt.Sprintf("manage/%s", name), files...)
|
||||
return renderer
|
||||
}
|
||||
|
||||
|
2
go.mod
2
go.mod
@ -6,7 +6,7 @@ require (
|
||||
github.com/BurntSushi/toml v0.3.1
|
||||
github.com/TicketsBot/archiverclient v0.0.0-20200425115930-0ca198cc8306
|
||||
github.com/TicketsBot/common v0.0.0-20200529141045-7426ad13f1a4
|
||||
github.com/TicketsBot/database v0.0.0-20200619194554-a6db672a94cf
|
||||
github.com/TicketsBot/database v0.0.0-20200620140717-f747a0bb4238
|
||||
github.com/apex/log v1.1.2
|
||||
github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff // indirect
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
|
@ -195,3 +195,7 @@ html > ::-webkit-scrollbar {
|
||||
.bootstrap-select .bs-ok-default:after {
|
||||
color: #2ECC71 !important;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
z-index: 1000 !important;
|
||||
}
|
23
public/static/js/modalbackdrop.js
Normal file
23
public/static/js/modalbackdrop.js
Normal file
@ -0,0 +1,23 @@
|
||||
function clear(...elements) {
|
||||
for (const elementId of elements) {
|
||||
document.getElementById(elementId).value = '';
|
||||
}
|
||||
}
|
||||
|
||||
function hideBackdrop() {
|
||||
for (const backdrop of document.getElementsByClassName('modal-backdrop fade show')) {
|
||||
backdrop.remove();
|
||||
}
|
||||
}
|
||||
|
||||
function registerHideListener(elementId) {
|
||||
$(`#${elementId}`).on('hidden.bs.modal', hideBackdrop);
|
||||
}
|
||||
|
||||
function showBackdrop() {
|
||||
hideBackdrop();
|
||||
|
||||
const backdrop = document.createElement('div');
|
||||
backdrop.classList.add('modal-backdrop', 'fade', 'show');
|
||||
document.getElementsByClassName('main-panel')[0].appendChild(backdrop);
|
||||
}
|
222
public/templates/includes/paneleditmodal.tmpl
Normal file
222
public/templates/includes/paneleditmodal.tmpl
Normal file
@ -0,0 +1,222 @@
|
||||
{{define "paneleditmodal"}}
|
||||
<div class="modal fade" id="editmodal" tabindex="-1" role="dialog" aria-labelledby="editmodal" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title"><b>Edit Panel</b></h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-4 pr-1">
|
||||
<div class="form-group">
|
||||
<label class="black">Panel Title</label>
|
||||
<input type="text" class="form-control" placeholder="Open a ticket!" id="edit-title">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-8 pr-1">
|
||||
<div class="form-group">
|
||||
<label class="black">Panel Content</label>
|
||||
<textarea type="text" class="form-control"
|
||||
placeholder="By reacting to this ticket, a ticket will be opened for you."
|
||||
id="edit-content"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-2 pr-1">
|
||||
<label class="black">Panel Colour</label>
|
||||
<div class="input-group mb-3">
|
||||
<input type="color" class="form-control input-fill" id="edit-colour">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-3 pr-1">
|
||||
<label class="black">Panel Channel</label>
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<div class="input-group-text">#</div>
|
||||
</div>
|
||||
<select class="form-control" id="edit-channel-container">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4 pr-1">
|
||||
<label class="black">Ticket Channel Category</label>
|
||||
<div class="input-group mb-3">
|
||||
<select class="form-control" id="edit-category-container">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 pr-1">
|
||||
<div class="form-group">
|
||||
<label class="black">Reaction Emote</label>
|
||||
<input type="text" class="form-control" placeholder="envelope_with_arrow" id="edit-reaction">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4 pr-1 offset-md-4">
|
||||
<div class="text-center">
|
||||
<button class="btn btn-primary btn-fill" type="button" data-toggle="collapse" data-target="#edit-advanced" aria-expanded="false" aria-controls="edit-advanced">
|
||||
Expand advanced settings
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="collapse" id="edit-advanced" style="width: 100%">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12 pr-1">
|
||||
<div class="form-group">
|
||||
<label class="black">Welcome Message</label>
|
||||
<textarea type="text" class="form-control" placeholder="If not provided, your server's default welcome message will be used" id="edit-welcome-message"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12 pr-1">
|
||||
<div class="form-group">
|
||||
<label class="black">Mention On Open</label>
|
||||
<select class="selectpicker form-control" id="edit-mentions" multiple data-live-search="true" data-dropup-auto="false" data-size="5" data-display="static">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input type="hidden" id="edit-message-id">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-primary btn-fill" onclick="updatePanel()">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function resetEditModal() {
|
||||
clear('edit-title', 'edit-content', 'edit-message-id', 'edit-reaction', 'edit-welcome-message');
|
||||
$('#edit-mentions').selectpicker('deselectAll');
|
||||
}
|
||||
|
||||
registerHideListener('editmodal');
|
||||
$('#editmodal').on('hidden.bs.modal', resetEditModal);
|
||||
|
||||
async function openEditModal(messageId) {
|
||||
resetEditModal();
|
||||
|
||||
const res = await axios.get('/api/{{.guildId}}/panels');
|
||||
if (res.status !== 200) {
|
||||
showToast("Error", res.data);
|
||||
return;
|
||||
}
|
||||
|
||||
const panel = res.data.find(panel => panel.message_id === messageId);
|
||||
if (panel === undefined) {
|
||||
showToast('Error', 'Panel not found');
|
||||
return;
|
||||
}
|
||||
|
||||
await fillEditData(panel);
|
||||
|
||||
$('#editmodal').modal('show');
|
||||
showBackdrop();
|
||||
}
|
||||
|
||||
async function fillEditData(panel) {
|
||||
document.getElementById('edit-message-id').value = panel.message_id;
|
||||
document.getElementById('edit-title').value = panel.title;
|
||||
document.getElementById('edit-content').value = panel.content;
|
||||
document.getElementById('edit-colour').value = `#${panel.colour.toString(16)}`;
|
||||
document.getElementById('edit-reaction').value = panel.emote;
|
||||
|
||||
if (panel.welcome_message !== null) {
|
||||
document.getElementById('edit-welcome-message').value = panel.welcome_message;
|
||||
}
|
||||
|
||||
const channels = await getChannels();
|
||||
await fillChannels('edit-channel-container', channels);
|
||||
await fillCategories('edit-category-container', channels);
|
||||
await fillMentions('edit-mentions');
|
||||
|
||||
setActiveChannel(panel);
|
||||
setActiveCategory(panel);
|
||||
setActiveMentions(panel);
|
||||
}
|
||||
|
||||
function setActiveChannel(panel) {
|
||||
const select = document.getElementById('edit-channel-container');
|
||||
for (let i = 0; i < select.children.length; i++) {
|
||||
const child = select.children[i];
|
||||
if (child.value === panel.channel_id) {
|
||||
select.selectedIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setActiveCategory(panel) {
|
||||
const select = document.getElementById('edit-category-container');
|
||||
for (let i = 0; i < select.children.length; i++) {
|
||||
const child = select.children[i];
|
||||
if (child.value === panel.category_id) {
|
||||
select.selectedIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setActiveMentions(panel) {
|
||||
if (panel.mentions !== null) {
|
||||
$('#edit-mentions').selectpicker('val', panel.mentions);
|
||||
}
|
||||
}
|
||||
|
||||
async function updatePanel() {
|
||||
const messageId = document.getElementById('edit-message-id').value;
|
||||
const title = document.getElementById('edit-title').value;
|
||||
const content = document.getElementById('edit-content').value;
|
||||
const emote = document.getElementById('edit-reaction').value.replace(':', '');
|
||||
const welcomeMessage = document.getElementById('edit-welcome-message').value;
|
||||
|
||||
const data = {
|
||||
message_id: messageId,
|
||||
title: title === '' ? 'Open a ticket!' : title,
|
||||
content: content === '' ? 'By reacting to this ticket, a message will be opened for you.' : content,
|
||||
emote: emote === '' ? 'envelope_with_arrow' : emote,
|
||||
colour: parseInt(`0x${document.getElementById('colour').value.slice(1)}`),
|
||||
channel_id: document.getElementById('edit-channel-container').options[document.getElementById('edit-channel-container').selectedIndex].value,
|
||||
category_id: document.getElementById('edit-category-container').options[document.getElementById('edit-category-container').selectedIndex].value,
|
||||
welcome_message: welcomeMessage === '' ? null : welcomeMessage,
|
||||
mentions: $('#edit-mentions').val()
|
||||
};
|
||||
|
||||
const res = await axios.put('/api/{{.guildId}}/panels/' + messageId, data);
|
||||
if (res.status === 200 && res.data.success) {
|
||||
showToast('Success', 'Panel updated successfully')
|
||||
$('#editmodal').modal('hide');
|
||||
resetEditModal();
|
||||
|
||||
// remove old data
|
||||
// TODO: Don't remove just update, looks cleaner
|
||||
const el = document.getElementById(messageId);
|
||||
el.parentNode.removeChild(el);
|
||||
|
||||
data.message_id = res.data.message_id;
|
||||
appendPanel(data, await getChannels());
|
||||
} else {
|
||||
showToast('Error', res.data.error);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{{end}}
|
@ -31,4 +31,13 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
registerHideListener('modal-substitutions');
|
||||
|
||||
function showSubstitutionModal() {
|
||||
$('#modal-substitutions').modal('show');
|
||||
showBackdrop();
|
||||
}
|
||||
</script>
|
||||
{{end}}
|
@ -5,7 +5,6 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrapper">
|
||||
{{template "substitutions" .}} <!-- Has to be here for some reason -->
|
||||
<div class="main-panel" style="width: 100% !important;">
|
||||
{{template "navbar" .}}
|
||||
{{template "loadingscreen" .}}
|
||||
|
@ -1,4 +1,8 @@
|
||||
{{define "content"}}
|
||||
<script src="/assets/js/modalbackdrop.js"></script>
|
||||
{{template "substitutions" .}}
|
||||
{{template "paneleditmodal" .}}
|
||||
|
||||
<div class="content">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
@ -18,6 +22,7 @@
|
||||
<th>Panel Title</th>
|
||||
<th>Panel Content</th>
|
||||
<th>Ticket Channel Category</th>
|
||||
<th>Edit</th>
|
||||
<th>Delete</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@ -69,9 +74,6 @@
|
||||
<div class="col-md-3 pr-1">
|
||||
<label class="black">Ticket Channel Category</label>
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<div class="input-group-text">#</div>
|
||||
</div>
|
||||
<select class="form-control" name="categories" id="category-container">
|
||||
</select>
|
||||
</div>
|
||||
@ -102,7 +104,7 @@
|
||||
<div class="col-md-6 pr-1">
|
||||
<div class="form-group">
|
||||
<label class="black">Welcome Message
|
||||
<i class="fas fa-question pointer" data-toggle="modal" data-target="#modal-substitutions"></i>
|
||||
<i class="fas fa-question pointer" onclick="showSubstitutionModal()"></i>
|
||||
</label>
|
||||
<textarea type="text" class="form-control" placeholder="If not provided, your server's default welcome message will be used" id="welcome_message"></textarea>
|
||||
</div>
|
||||
@ -181,7 +183,7 @@
|
||||
channel_id: document.getElementById('channel-container').options[document.getElementById('channel-container').selectedIndex].value,
|
||||
category_id: document.getElementById('category-container').options[document.getElementById('category-container').selectedIndex].value,
|
||||
welcome_message: welcomeMessage === '' ? null : welcomeMessage,
|
||||
mentions: $('.selectpicker').val()
|
||||
mentions: $('#mentions').val()
|
||||
};
|
||||
|
||||
const res = await axios.put('/api/{{.guildId}}/panels', data);
|
||||
@ -194,8 +196,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function fillChannels(channels) {
|
||||
const container = document.getElementById('channel-container');
|
||||
async function fillChannels(elementId, channels) {
|
||||
const container = document.getElementById(elementId);
|
||||
|
||||
channels.filter(ch => ch.type === 0).forEach(ch => {
|
||||
const el = document.createElement('option');
|
||||
@ -205,8 +207,8 @@
|
||||
});
|
||||
}
|
||||
|
||||
async function fillCategories(channels) {
|
||||
const container = document.getElementById('category-container');
|
||||
async function fillCategories(elementId, channels) {
|
||||
const container = document.getElementById(elementId);
|
||||
|
||||
channels.filter(ch => ch.type === 4).forEach(ch => {
|
||||
const el = document.createElement('option');
|
||||
@ -242,6 +244,16 @@
|
||||
appendTd(tr, panel.content);
|
||||
appendTd(tr, getChannelName(channels, panel.category_id));
|
||||
|
||||
// build edit button
|
||||
const editTd = document.createElement('td');
|
||||
const editButton = document.createElement('button');
|
||||
editButton.type = 'button';
|
||||
editButton.classList.add('btn', 'btn-primary', 'btn-fill', 'mx-auto');
|
||||
editButton.appendChild(document.createTextNode('Edit'));
|
||||
editButton.onclick = () => { openEditModal(panel.message_id) };
|
||||
editTd.appendChild(editButton);
|
||||
tr.appendChild(editTd);
|
||||
|
||||
// build remove button
|
||||
const deleteTd = document.createElement('td');
|
||||
const deleteButton = document.createElement('button');
|
||||
@ -269,8 +281,8 @@
|
||||
return res.data.length;
|
||||
}
|
||||
|
||||
async function fillMentions() {
|
||||
const select = document.getElementById('mentions');
|
||||
async function fillMentions(elementId) {
|
||||
const select = document.getElementById(elementId);
|
||||
|
||||
// ticket opener
|
||||
const ticketOpener = document.createElement('option');
|
||||
@ -294,7 +306,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
$('.selectpicker').selectpicker('refresh');
|
||||
$('#mentions').selectpicker('refresh');
|
||||
}
|
||||
|
||||
async function loadData() {
|
||||
@ -302,13 +314,12 @@
|
||||
const panelCount = await fillPanels(channels);
|
||||
|
||||
await fillPanelQuota(panelCount);
|
||||
await fillChannels(channels);
|
||||
await fillCategories(channels);
|
||||
await fillMentions();
|
||||
await fillChannels('channel-container', channels);
|
||||
await fillCategories('category-container', channels);
|
||||
await fillMentions('mentions');
|
||||
}
|
||||
|
||||
withLoadingScreen(loadData);
|
||||
</script>
|
||||
</div>
|
||||
|
||||
{{end}}
|
@ -1,4 +1,7 @@
|
||||
{{define "content"}}
|
||||
<script src="/assets/js/modalbackdrop.js"></script>
|
||||
{{template "substitutions" .}}
|
||||
|
||||
<div class="content">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
@ -79,7 +82,7 @@
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<label>Welcome Message (Max len. 1000)
|
||||
<i class="fas fa-question pointer" data-toggle="modal" data-target="#modal-substitutions"></i>
|
||||
<i class="fas fa-question pointer" onclick="showSubstitutionModal()"></i>
|
||||
</label>
|
||||
<textarea name="welcomeMessage" class="form-control" rows="3" id="welcome_message"></textarea>
|
||||
</div>
|
||||
|
@ -6,7 +6,8 @@ import (
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
var emojis map[string]interface{}
|
||||
var emojisByName map[string]string
|
||||
var emojis []string
|
||||
|
||||
func LoadEmoji() {
|
||||
bytes, err := ioutil.ReadFile("emojis.json"); if err != nil {
|
||||
@ -14,17 +15,31 @@ func LoadEmoji() {
|
||||
return
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(bytes, &emojis); err != nil {
|
||||
if err := json.Unmarshal(bytes, &emojisByName); err != nil {
|
||||
log.Error("Couldn't load emoji: " + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
emojis = make([]string, len(emojisByName))
|
||||
i := 0
|
||||
for _, emoji := range emojisByName {
|
||||
emojis[i] = emoji
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
func GetEmojiByName(name string) string {
|
||||
emoji, ok := emojis[name]; if !ok {
|
||||
return ""
|
||||
func GetEmoji(input string) (emoji string, ok bool) {
|
||||
// try by name first
|
||||
emoji, ok = emojisByName[input]
|
||||
if !ok { // else try by the actual unicode char
|
||||
for _, unicode := range emojis {
|
||||
if unicode == input {
|
||||
emoji = unicode
|
||||
ok = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
str, _ := emoji.(string)
|
||||
return str
|
||||
return
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user