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/blacklist", manage.BlacklistHandler)
|
||||
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/view/:uuid", manage.TicketViewHandler)
|
||||
@ -96,6 +97,10 @@ func StartServer() {
|
||||
guildAuthApi.GET("/:id/tickets/:uuid", api.GetTicket)
|
||||
guildAuthApi.POST("/:id/tickets/:uuid", api.SendMessage)
|
||||
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)
|
||||
@ -120,6 +125,7 @@ func createRenderer() multitemplate.Renderer {
|
||||
r = addManageTemplate(r, "ticketlist")
|
||||
r = addManageTemplate(r, "ticketview")
|
||||
r = addManageTemplate(r, "panels")
|
||||
r = addManageTemplate(r, "tags")
|
||||
|
||||
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/robfig/go-cache v0.0.0-20130306151617-9fc39e0dbf62
|
||||
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
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a
|
||||
)
|
||||
|
@ -111,3 +111,9 @@ body {
|
||||
#premium-ad {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tag-content {
|
||||
min-width: 300px;
|
||||
max-width: 300px;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
@ -122,6 +122,7 @@
|
||||
td.appendChild(document.createTextNode(content));
|
||||
td.classList.add('white');
|
||||
tr.appendChild(td);
|
||||
return td
|
||||
}
|
||||
|
||||
function appendButton(tr, content, onclick) {
|
||||
|
@ -19,6 +19,9 @@
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/manage/{{.guildId}}/panels"><i class="fas fa-mouse-pointer icon"></i>Reaction Panels</a>
|
||||
</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 class="navbar-nav navbar-right">
|
||||
<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