Tag management
This commit is contained in:
parent
7328719629
commit
f4e484357f
59
app/http/endpoints/api/tagcreate.go
Normal file
59
app/http/endpoints/api/tagcreate.go
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TicketsBot/GoPanel/database/table"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
type tag struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateTag(ctx *gin.Context) {
|
||||||
|
guildId := ctx.Keys["guildid"].(uint64)
|
||||||
|
var data tag
|
||||||
|
|
||||||
|
if err := ctx.BindJSON(&data); err != nil {
|
||||||
|
ctx.AbortWithStatusJSON(400, gin.H{
|
||||||
|
"success": false,
|
||||||
|
"error": err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !data.verifyIdLength() {
|
||||||
|
ctx.AbortWithStatusJSON(400, gin.H{
|
||||||
|
"success": false,
|
||||||
|
"error": "Tag ID must be 1 - 16 characters in length",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !data.verifyContentLength() {
|
||||||
|
ctx.AbortWithStatusJSON(400, gin.H{
|
||||||
|
"success": false,
|
||||||
|
"error": "Tag content must be 1 - 2000 characters in length",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := table.AddTag(guildId, data.Id, data.Content); err != nil {
|
||||||
|
ctx.AbortWithStatusJSON(500, gin.H{
|
||||||
|
"success": false,
|
||||||
|
"error": err.Error(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
ctx.JSON(200, gin.H{
|
||||||
|
"success": true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tag) verifyIdLength() bool {
|
||||||
|
return len(t.Id) > 0 && len(t.Id) <= 16
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tag) verifyContentLength() bool {
|
||||||
|
return len(t.Content) > 0 && len(t.Content) <= 2000
|
||||||
|
}
|
30
app/http/endpoints/api/tagdelete.go
Normal file
30
app/http/endpoints/api/tagdelete.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TicketsBot/GoPanel/database/table"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DeleteTag(ctx *gin.Context) {
|
||||||
|
guildId := ctx.Keys["guildid"].(uint64)
|
||||||
|
tagId := ctx.Param("tag")
|
||||||
|
|
||||||
|
if tagId == "" || len(tagId) > 16 {
|
||||||
|
ctx.JSON(400, gin.H{
|
||||||
|
"success": false,
|
||||||
|
"error": "Invalid tag",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := table.DeleteTag(guildId, tagId); err != nil {
|
||||||
|
ctx.JSON(500, gin.H{
|
||||||
|
"success": false,
|
||||||
|
"error": err.Error(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
ctx.JSON(200, gin.H{
|
||||||
|
"success": true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
23
app/http/endpoints/api/tagslist.go
Normal file
23
app/http/endpoints/api/tagslist.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TicketsBot/GoPanel/database/table"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TagsListHandler(ctx *gin.Context) {
|
||||||
|
guildId := ctx.Keys["guildid"].(uint64)
|
||||||
|
|
||||||
|
wrapped := make([]tag, 0)
|
||||||
|
|
||||||
|
tags := make(chan []table.Tag)
|
||||||
|
go table.GetTags(guildId, tags)
|
||||||
|
for _, t := range <-tags {
|
||||||
|
wrapped = append(wrapped, tag{
|
||||||
|
Id: t.Id,
|
||||||
|
Content: t.Content,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(200, wrapped)
|
||||||
|
}
|
19
app/http/endpoints/manage/tags.go
Normal file
19
app/http/endpoints/manage/tags.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package manage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TicketsBot/GoPanel/config"
|
||||||
|
"github.com/gin-gonic/contrib/sessions"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TagsHandler(ctx *gin.Context) {
|
||||||
|
store := sessions.Default(ctx)
|
||||||
|
guildId := ctx.Keys["guildid"].(uint64)
|
||||||
|
|
||||||
|
ctx.HTML(200, "manage/tags", gin.H{
|
||||||
|
"name": store.Get("name").(string),
|
||||||
|
"guildId": guildId,
|
||||||
|
"avatar": store.Get("avatar").(string),
|
||||||
|
"baseUrl": config.Conf.Server.BaseUrl,
|
||||||
|
})
|
||||||
|
}
|
@ -63,6 +63,7 @@ func StartServer() {
|
|||||||
authenticateGuild.GET("/manage/:id/logs/modmail", manage.ModmailLogsHandler)
|
authenticateGuild.GET("/manage/:id/logs/modmail", manage.ModmailLogsHandler)
|
||||||
authenticateGuild.GET("/manage/:id/blacklist", manage.BlacklistHandler)
|
authenticateGuild.GET("/manage/:id/blacklist", manage.BlacklistHandler)
|
||||||
authenticateGuild.GET("/manage/:id/panels", manage.PanelHandler)
|
authenticateGuild.GET("/manage/:id/panels", manage.PanelHandler)
|
||||||
|
authenticateGuild.GET("/manage/:id/tags", manage.TagsHandler)
|
||||||
|
|
||||||
authenticateGuild.GET("/manage/:id/tickets", manage.TicketListHandler)
|
authenticateGuild.GET("/manage/:id/tickets", manage.TicketListHandler)
|
||||||
authenticateGuild.GET("/manage/:id/tickets/view/:uuid", manage.TicketViewHandler)
|
authenticateGuild.GET("/manage/:id/tickets/view/:uuid", manage.TicketViewHandler)
|
||||||
@ -96,6 +97,10 @@ func StartServer() {
|
|||||||
guildAuthApi.GET("/:id/tickets/:uuid", api.GetTicket)
|
guildAuthApi.GET("/:id/tickets/:uuid", api.GetTicket)
|
||||||
guildAuthApi.POST("/:id/tickets/:uuid", api.SendMessage)
|
guildAuthApi.POST("/:id/tickets/:uuid", api.SendMessage)
|
||||||
guildAuthApi.DELETE("/:id/tickets/:uuid", api.CloseTicket)
|
guildAuthApi.DELETE("/:id/tickets/:uuid", api.CloseTicket)
|
||||||
|
|
||||||
|
guildAuthApi.GET("/:id/tags", api.TagsListHandler)
|
||||||
|
guildAuthApi.PUT("/:id/tags", api.CreateTag)
|
||||||
|
guildAuthApi.DELETE("/:id/tags/:tag", api.DeleteTag)
|
||||||
}
|
}
|
||||||
|
|
||||||
userGroup := router.Group("/user", middleware.AuthenticateToken)
|
userGroup := router.Group("/user", middleware.AuthenticateToken)
|
||||||
@ -120,6 +125,7 @@ func createRenderer() multitemplate.Renderer {
|
|||||||
r = addManageTemplate(r, "ticketlist")
|
r = addManageTemplate(r, "ticketlist")
|
||||||
r = addManageTemplate(r, "ticketview")
|
r = addManageTemplate(r, "ticketview")
|
||||||
r = addManageTemplate(r, "panels")
|
r = addManageTemplate(r, "panels")
|
||||||
|
r = addManageTemplate(r, "tags")
|
||||||
|
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
42
database/table/tags.go
Normal file
42
database/table/tags.go
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package table
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TicketsBot/GoPanel/database"
|
||||||
|
uuid "github.com/satori/go.uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Tag struct {
|
||||||
|
Uuid string `gorm:"column:UUID;type:varchar(36);unique;primary_key"`
|
||||||
|
Id string `gorm:"column:ID;type:varchar(16)"`
|
||||||
|
Guild uint64 `gorm:"column:GUILDID"`
|
||||||
|
Content string `gorm:"column:TEXT;type:TEXT"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Tag) TableName() string {
|
||||||
|
return "cannedresponses"
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetTag(guild uint64, id string, ch chan string) {
|
||||||
|
var node Tag
|
||||||
|
database.Database.Where(Tag{Id: id, Guild: guild}).Take(&node)
|
||||||
|
ch <- node.Content
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetTags(guild uint64, ch chan []Tag) {
|
||||||
|
var rows []Tag
|
||||||
|
database.Database.Where(Tag{Guild: guild}).Find(&rows)
|
||||||
|
ch <- rows
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddTag(guild uint64, id string, content string) error {
|
||||||
|
return database.Database.Create(&Tag{
|
||||||
|
Uuid: uuid.NewV4().String(),
|
||||||
|
Id: id,
|
||||||
|
Guild: guild,
|
||||||
|
Content: content,
|
||||||
|
}).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteTag(guild uint64, id string) error {
|
||||||
|
return database.Database.Where(Tag{Id: id, Guild: guild}).Delete(&Tag{}).Error
|
||||||
|
}
|
1
go.mod
1
go.mod
@ -22,6 +22,7 @@ require (
|
|||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/robfig/go-cache v0.0.0-20130306151617-9fc39e0dbf62
|
github.com/robfig/go-cache v0.0.0-20130306151617-9fc39e0dbf62
|
||||||
github.com/rxdn/gdl v0.0.0-20200421193445-f200b9f466d7
|
github.com/rxdn/gdl v0.0.0-20200421193445-f200b9f466d7
|
||||||
|
github.com/satori/go.uuid v1.2.0
|
||||||
github.com/ulule/limiter/v3 v3.5.0
|
github.com/ulule/limiter/v3 v3.5.0
|
||||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a
|
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a
|
||||||
)
|
)
|
||||||
|
@ -111,3 +111,9 @@ body {
|
|||||||
#premium-ad {
|
#premium-ad {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tag-content {
|
||||||
|
min-width: 300px;
|
||||||
|
max-width: 300px;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
@ -122,6 +122,7 @@
|
|||||||
td.appendChild(document.createTextNode(content));
|
td.appendChild(document.createTextNode(content));
|
||||||
td.classList.add('white');
|
td.classList.add('white');
|
||||||
tr.appendChild(td);
|
tr.appendChild(td);
|
||||||
|
return td
|
||||||
}
|
}
|
||||||
|
|
||||||
function appendButton(tr, content, onclick) {
|
function appendButton(tr, content, onclick) {
|
||||||
|
@ -19,6 +19,9 @@
|
|||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/manage/{{.guildId}}/panels"><i class="fas fa-mouse-pointer icon"></i>Reaction Panels</a>
|
<a class="nav-link" href="/manage/{{.guildId}}/panels"><i class="fas fa-mouse-pointer icon"></i>Reaction Panels</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="/manage/{{.guildId}}/tags"><i class="fas fa-tags icon"></i>Tags</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<ul class="navbar-nav navbar-right">
|
<ul class="navbar-nav navbar-right">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
|
123
public/templates/views/tags.tmpl
Normal file
123
public/templates/views/tags.tmpl
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
{{define "content"}}
|
||||||
|
<div class="content">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h4 class="card-title">Tags</h4>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<table class="table table-hover table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Content</th>
|
||||||
|
<th>Delete</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="tag-container">
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h4 class="card-title">Create A Tag</h4>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form onsubmit="createTag(); return false;">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-4 pr-1">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="black">Tag ID</label>
|
||||||
|
<input name="title" type="text" class="form-control" placeholder="My Tag" id="id">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-8 pr-1">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="black">Tag Response</label>
|
||||||
|
<textarea name="content" type="text" class="form-control"
|
||||||
|
placeholder="Response to the tag" id="content"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-2 pr-1 offset-md-5">
|
||||||
|
<div class="form-group">
|
||||||
|
<button type="submit" class="btn btn-primary btn-fill"><i class="fas fa-paper-plane"></i> Submit</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div aria-live="polite" aria-atomic="true" style="position: relative; min-height: 200px;">
|
||||||
|
<div style="position: absolute; right: 10px" id="toast-container">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
async function createTag() {
|
||||||
|
const id = document.getElementById('id').value;
|
||||||
|
|
||||||
|
const content = document.getElementById('content').value;
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
id: id,
|
||||||
|
content: content
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await axios.put('/api/{{.guildId}}/tags', data);
|
||||||
|
|
||||||
|
if (res.status === 200 && res.data.success) {
|
||||||
|
document.getElementById('id').value = '';
|
||||||
|
document.getElementById('content').value = '';
|
||||||
|
|
||||||
|
appendTag(data);
|
||||||
|
} else {
|
||||||
|
showToast('Error', res.data.error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deleteTag(id) {
|
||||||
|
const res = await axios.delete('/api/{{.guildId}}/tags/' + id);
|
||||||
|
if (res.status === 200 && res.data.success) {
|
||||||
|
const tr = document.getElementById(id);
|
||||||
|
tr.parentNode.removeChild(tr);
|
||||||
|
} else {
|
||||||
|
showToast('Error', res.data.error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function appendTag(tag) {
|
||||||
|
const container = document.getElementById('tag-container');
|
||||||
|
const tr = document.createElement('tr');
|
||||||
|
tr.id = tag.id;
|
||||||
|
|
||||||
|
appendTd(tr, tag.id);
|
||||||
|
appendTd(tr, tag.content).classList.add('tag-content');
|
||||||
|
appendButton(tr, 'Delete', () => { deleteTag(tag.id); });
|
||||||
|
|
||||||
|
container.appendChild(tr);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadData() {
|
||||||
|
const res = await axios.get('/api/{{.guildId}}/tags');
|
||||||
|
|
||||||
|
if (res.status === 200) {
|
||||||
|
for (tag of res.data) {
|
||||||
|
appendTag(tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loadData();
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
Loading…
x
Reference in New Issue
Block a user