Staff override
This commit is contained in:
parent
ec3b721b40
commit
1a6b50d293
23
app/http/endpoints/api/admin/botstaff/add.go
Normal file
23
app/http/endpoints/api/admin/botstaff/add.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package botstaff
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TicketsBot/GoPanel/database"
|
||||||
|
"github.com/TicketsBot/GoPanel/utils"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AddBotStaffHandler(ctx *gin.Context) {
|
||||||
|
userId, err := strconv.ParseUint(ctx.Param("userid"), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(400, utils.ErrorJson(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := database.Client.BotStaff.Add(userId); err != nil {
|
||||||
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Status(204)
|
||||||
|
}
|
57
app/http/endpoints/api/admin/botstaff/list.go
Normal file
57
app/http/endpoints/api/admin/botstaff/list.go
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package botstaff
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/TicketsBot/GoPanel/database"
|
||||||
|
"github.com/TicketsBot/GoPanel/rpc/cache"
|
||||||
|
"github.com/TicketsBot/GoPanel/utils"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/rxdn/gdl/objects/user"
|
||||||
|
"golang.org/x/sync/errgroup"
|
||||||
|
)
|
||||||
|
|
||||||
|
type userData struct {
|
||||||
|
Id uint64 `json:"id,string"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Discriminator user.Discriminator `json:"discriminator"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func ListBotStaffHandler(ctx *gin.Context) {
|
||||||
|
staff, err := database.Client.BotStaff.GetAll()
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get usernames
|
||||||
|
group, _ := errgroup.WithContext(context.Background())
|
||||||
|
|
||||||
|
users := make([]userData, len(staff))
|
||||||
|
for i, userId := range staff {
|
||||||
|
i := i
|
||||||
|
userId := userId
|
||||||
|
|
||||||
|
group.Go(func() error {
|
||||||
|
user, ok := cache.Instance.GetUser(userId)
|
||||||
|
|
||||||
|
data := userData{
|
||||||
|
Id: userId,
|
||||||
|
}
|
||||||
|
|
||||||
|
if ok {
|
||||||
|
data.Username = user.Username
|
||||||
|
data.Discriminator = user.Discriminator
|
||||||
|
} else {
|
||||||
|
data.Username = "Unknown User"
|
||||||
|
}
|
||||||
|
|
||||||
|
users[i] = data
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = group.Wait() // error not possible
|
||||||
|
|
||||||
|
ctx.JSON(200, users)
|
||||||
|
}
|
23
app/http/endpoints/api/admin/botstaff/remove.go
Normal file
23
app/http/endpoints/api/admin/botstaff/remove.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package botstaff
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TicketsBot/GoPanel/database"
|
||||||
|
"github.com/TicketsBot/GoPanel/utils"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func RemoveBotStaffHandler(ctx *gin.Context) {
|
||||||
|
userId, err := strconv.ParseUint(ctx.Param("userid"), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(400, utils.ErrorJson(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := database.Client.BotStaff.Delete(userId); err != nil {
|
||||||
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Status(204)
|
||||||
|
}
|
@ -33,17 +33,12 @@ func SessionHandler(ctx *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var whitelabelOverride bool
|
whitelabelOverride := utils.Contains(config.Conf.ForceWhitelabel, userId)
|
||||||
for _, id := range config.Conf.ForceWhitelabel {
|
|
||||||
if id == userId {
|
|
||||||
whitelabelOverride = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.JSON(200, gin.H{
|
ctx.JSON(200, gin.H{
|
||||||
"username": store.Name,
|
"username": store.Name,
|
||||||
"avatar": store.Avatar,
|
"avatar": store.Avatar,
|
||||||
"whitelabel": tier >= premium.Whitelabel || whitelabelOverride,
|
"whitelabel": tier >= premium.Whitelabel || whitelabelOverride,
|
||||||
|
"admin": utils.Contains(config.Conf.Admins, userId),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
32
app/http/endpoints/api/staffoverride/createoverride.go
Normal file
32
app/http/endpoints/api/staffoverride/createoverride.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/TicketsBot/GoPanel/database"
|
||||||
|
"github.com/TicketsBot/GoPanel/utils"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type createOverrideBody struct {
|
||||||
|
TimePeriod int `json:"time_period"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateOverrideHandler(ctx *gin.Context) {
|
||||||
|
guildId := ctx.Keys["guildid"].(uint64)
|
||||||
|
|
||||||
|
var body createOverrideBody
|
||||||
|
if err := ctx.BindJSON(&body); err != nil {
|
||||||
|
ctx.JSON(400, utils.ErrorStr("Invalid request body"))
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
expires := time.Now().Add(time.Hour * time.Duration(body.TimePeriod))
|
||||||
|
if err := database.Client.StaffOverride.Set(guildId, expires); err != nil {
|
||||||
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Status(204)
|
||||||
|
}
|
18
app/http/endpoints/api/staffoverride/deleteoverride.go
Normal file
18
app/http/endpoints/api/staffoverride/deleteoverride.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TicketsBot/GoPanel/database"
|
||||||
|
"github.com/TicketsBot/GoPanel/utils"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DeleteOverrideHandler(ctx *gin.Context) {
|
||||||
|
guildId := ctx.Keys["guildid"].(uint64)
|
||||||
|
|
||||||
|
if err := database.Client.StaffOverride.Delete(guildId); err != nil {
|
||||||
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Status(204)
|
||||||
|
}
|
21
app/http/endpoints/api/staffoverride/getoverride.go
Normal file
21
app/http/endpoints/api/staffoverride/getoverride.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TicketsBot/GoPanel/database"
|
||||||
|
"github.com/TicketsBot/GoPanel/utils"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetOverrideHandler(ctx *gin.Context) {
|
||||||
|
guildId := ctx.Keys["guildid"].(uint64)
|
||||||
|
|
||||||
|
hasOverride, err := database.Client.StaffOverride.HasActiveOverride(guildId)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(200, gin.H{
|
||||||
|
"has_override": hasOverride,
|
||||||
|
})
|
||||||
|
}
|
17
app/http/middleware/adminonly.go
Normal file
17
app/http/middleware/adminonly.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TicketsBot/GoPanel/config"
|
||||||
|
"github.com/TicketsBot/GoPanel/utils"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AdminOnly(ctx *gin.Context) {
|
||||||
|
userId := ctx.Keys["userid"].(uint64)
|
||||||
|
|
||||||
|
if !utils.Contains(config.Conf.Admins, userId) {
|
||||||
|
ctx.JSON(401, utils.ErrorStr("Unauthorized"))
|
||||||
|
ctx.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
@ -42,10 +42,12 @@ func AuthenticateGuild(requiredPermissionLevel permission.PermissionLevel) gin.H
|
|||||||
if permLevel < requiredPermissionLevel {
|
if permLevel < requiredPermissionLevel {
|
||||||
ctx.JSON(403, utils.ErrorStr("Unauthorized"))
|
ctx.JSON(403, utils.ErrorStr("Unauthorized"))
|
||||||
ctx.Abort()
|
ctx.Abort()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ctx.JSON(400, utils.ErrorStr("Invalid guild ID"))
|
ctx.JSON(400, utils.ErrorStr("Invalid guild ID"))
|
||||||
ctx.Abort()
|
ctx.Abort()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"github.com/getsentry/sentry-go"
|
"github.com/getsentry/sentry-go"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"runtime/debug"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -46,6 +47,7 @@ func Logging(minLevel sentry.Level) gin.HandlerFunc {
|
|||||||
"user_id": ctx.Keys["userid"],
|
"user_id": ctx.Keys["userid"],
|
||||||
"request_body": string(requestBody),
|
"request_body": string(requestBody),
|
||||||
"response": string(responseBody),
|
"response": string(responseBody),
|
||||||
|
"stacktrace": string(debug.Stack()),
|
||||||
},
|
},
|
||||||
Level: level,
|
Level: level,
|
||||||
Message: fmt.Sprintf("HTTP %d on %s %s", statusCode, ctx.Request.Method, ctx.FullPath()),
|
Message: fmt.Sprintf("HTTP %d on %s %s", statusCode, ctx.Request.Method, ctx.FullPath()),
|
||||||
|
@ -2,12 +2,14 @@ package http
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TicketsBot/GoPanel/app/http/endpoints/api"
|
"github.com/TicketsBot/GoPanel/app/http/endpoints/api"
|
||||||
|
"github.com/TicketsBot/GoPanel/app/http/endpoints/api/admin/botstaff"
|
||||||
api_autoclose "github.com/TicketsBot/GoPanel/app/http/endpoints/api/autoclose"
|
api_autoclose "github.com/TicketsBot/GoPanel/app/http/endpoints/api/autoclose"
|
||||||
api_blacklist "github.com/TicketsBot/GoPanel/app/http/endpoints/api/blacklist"
|
api_blacklist "github.com/TicketsBot/GoPanel/app/http/endpoints/api/blacklist"
|
||||||
api_customisation "github.com/TicketsBot/GoPanel/app/http/endpoints/api/customisation"
|
api_customisation "github.com/TicketsBot/GoPanel/app/http/endpoints/api/customisation"
|
||||||
api_forms "github.com/TicketsBot/GoPanel/app/http/endpoints/api/forms"
|
api_forms "github.com/TicketsBot/GoPanel/app/http/endpoints/api/forms"
|
||||||
api_panels "github.com/TicketsBot/GoPanel/app/http/endpoints/api/panel"
|
api_panels "github.com/TicketsBot/GoPanel/app/http/endpoints/api/panel"
|
||||||
api_settings "github.com/TicketsBot/GoPanel/app/http/endpoints/api/settings"
|
api_settings "github.com/TicketsBot/GoPanel/app/http/endpoints/api/settings"
|
||||||
|
api_override "github.com/TicketsBot/GoPanel/app/http/endpoints/api/staffoverride"
|
||||||
api_tags "github.com/TicketsBot/GoPanel/app/http/endpoints/api/tags"
|
api_tags "github.com/TicketsBot/GoPanel/app/http/endpoints/api/tags"
|
||||||
api_team "github.com/TicketsBot/GoPanel/app/http/endpoints/api/team"
|
api_team "github.com/TicketsBot/GoPanel/app/http/endpoints/api/team"
|
||||||
api_ticket "github.com/TicketsBot/GoPanel/app/http/endpoints/api/ticket"
|
api_ticket "github.com/TicketsBot/GoPanel/app/http/endpoints/api/ticket"
|
||||||
@ -67,8 +69,8 @@ func StartServer() {
|
|||||||
apiGroup.GET("/session", api.SessionHandler)
|
apiGroup.GET("/session", api.SessionHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
guildAuthApiAdmin := apiGroup.Group("/:id", middleware.AuthenticateGuild(true, permission.Admin))
|
guildAuthApiAdmin := apiGroup.Group("/:id", middleware.AuthenticateGuild(permission.Admin))
|
||||||
guildAuthApiSupport := apiGroup.Group("/:id", middleware.AuthenticateGuild(true, permission.Support))
|
guildAuthApiSupport := apiGroup.Group("/:id", middleware.AuthenticateGuild(permission.Support))
|
||||||
guildApiNoAuth := apiGroup.Group("/:id", middleware.ParseGuildId)
|
guildApiNoAuth := apiGroup.Group("/:id", middleware.ParseGuildId)
|
||||||
{
|
{
|
||||||
guildAuthApiSupport.GET("/channels", api.ChannelsHandler)
|
guildAuthApiSupport.GET("/channels", api.ChannelsHandler)
|
||||||
@ -150,6 +152,10 @@ func StartServer() {
|
|||||||
guildAuthApiAdmin.PUT("/team/:teamid/:snowflake", rl(middleware.RateLimitTypeGuild, 5, time.Second*10), api_team.AddMember)
|
guildAuthApiAdmin.PUT("/team/:teamid/:snowflake", rl(middleware.RateLimitTypeGuild, 5, time.Second*10), api_team.AddMember)
|
||||||
guildAuthApiAdmin.DELETE("/team/:teamid", api_team.DeleteTeam)
|
guildAuthApiAdmin.DELETE("/team/:teamid", api_team.DeleteTeam)
|
||||||
guildAuthApiAdmin.DELETE("/team/:teamid/:snowflake", rl(middleware.RateLimitTypeGuild, 30, time.Minute), api_team.RemoveMember)
|
guildAuthApiAdmin.DELETE("/team/:teamid/:snowflake", rl(middleware.RateLimitTypeGuild, 30, time.Minute), api_team.RemoveMember)
|
||||||
|
|
||||||
|
guildAuthApiAdmin.GET("/staff-override", api_override.GetOverrideHandler)
|
||||||
|
guildAuthApiAdmin.POST("/staff-override", api_override.CreateOverrideHandler)
|
||||||
|
guildAuthApiAdmin.DELETE("/staff-override", api_override.DeleteOverrideHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
userGroup := router.Group("/user", middleware.AuthenticateToken)
|
userGroup := router.Group("/user", middleware.AuthenticateToken)
|
||||||
@ -173,6 +179,13 @@ func StartServer() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
adminGroup := apiGroup.Group("/admin", middleware.AdminOnly)
|
||||||
|
{
|
||||||
|
adminGroup.GET("/bot-staff", botstaff.ListBotStaffHandler)
|
||||||
|
adminGroup.POST("/bot-staff/:userid", botstaff.AddBotStaffHandler)
|
||||||
|
adminGroup.DELETE("/bot-staff/:userid", botstaff.RemoveBotStaffHandler)
|
||||||
|
}
|
||||||
|
|
||||||
if err := router.Run(config.Conf.Server.Host); err != nil {
|
if err := router.Run(config.Conf.Server.Host); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -3,66 +3,66 @@
|
|||||||
<i class="{icon}"></i>
|
<i class="{icon}"></i>
|
||||||
{/if}
|
{/if}
|
||||||
<span class="content">
|
<span class="content">
|
||||||
<slot />
|
<slot/>
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export let icon;
|
export let icon;
|
||||||
export let fullWidth = false;
|
export let fullWidth = false;
|
||||||
export let disabled = false;
|
export let disabled = false;
|
||||||
export let type = "submit";
|
export let type = "submit";
|
||||||
export let danger = false;
|
export let danger = false;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
button {
|
button {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
color: white;
|
color: white;
|
||||||
background-color: #3472f7;
|
background-color: #3472f7;
|
||||||
border-color: #3472f7;
|
border-color: #3472f7;
|
||||||
border-width: 2px;
|
border-width: 2px;
|
||||||
border-radius: .25rem;
|
border-radius: .25rem;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background-color 150ms ease-in-out, border-color 150ms ease-in-out;
|
transition: background-color 150ms ease-in-out, border-color 150ms ease-in-out;
|
||||||
box-shadow: 0 4px 4px rgb(0 0 0 / 25%);
|
box-shadow: 0 4px 4px rgb(0 0 0 / 25%);
|
||||||
}
|
}
|
||||||
|
|
||||||
button:active, button:hover:enabled {
|
button:active, button:hover:enabled {
|
||||||
background-color: #0062cc;
|
background-color: #0062cc;
|
||||||
border-color: #0062cc;
|
border-color: #0062cc;
|
||||||
}
|
}
|
||||||
|
|
||||||
button:disabled {
|
button:disabled {
|
||||||
background-color: #6c757d;
|
background-color: #6c757d;
|
||||||
border-color: #6c757d;
|
border-color: #6c757d;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fullWidth {
|
.fullWidth {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.danger {
|
.danger {
|
||||||
background-color: #dc3545 !important;
|
background-color: #dc3545 !important;
|
||||||
border-color: #dc3545 !important;
|
border-color: #dc3545 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.danger:hover:enabled, .danger:active {
|
.danger:hover:enabled, .danger:active {
|
||||||
background-color: #c32232 !important;
|
background-color: #c32232 !important;
|
||||||
border-color: #c32232 !important;
|
border-color: #c32232 !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -1,6 +1,6 @@
|
|||||||
`{#if label !== undefined}
|
{#if label !== undefined}
|
||||||
<label class="form-label">{label}</label>
|
<label class="form-label">{label}</label>
|
||||||
{/if}`
|
{/if}
|
||||||
|
|
||||||
<div class="multiselect-super">
|
<div class="multiselect-super">
|
||||||
<Select placeholder="Search..." optionIdentifier="id" items={roles}
|
<Select placeholder="Search..." optionIdentifier="id" items={roles}
|
||||||
|
107
frontend/src/components/manage/StaffOverrideModal.svelte
Normal file
107
frontend/src/components/manage/StaffOverrideModal.svelte
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
<div class="modal" transition:fade>
|
||||||
|
<div class="modal-wrapper">
|
||||||
|
<Card footer="{true}" footerRight="{true}" fill="{false}">
|
||||||
|
<span slot="title">Grant Permissions To Tickets Team</span>
|
||||||
|
|
||||||
|
<div slot="body" class="body-wrapper">
|
||||||
|
Grant permission for
|
||||||
|
<Dropdown bind:value={timePeriod}>
|
||||||
|
<option value="1">1 hour</option>
|
||||||
|
<option value="6">6 hours</option>
|
||||||
|
<option value="24">1 day</option>
|
||||||
|
<option value="72">3 days</option>
|
||||||
|
</Dropdown>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div slot="footer" class="footer-wrapper">
|
||||||
|
<Button danger={true} on:click={dispatchClose}>Cancel</Button>
|
||||||
|
<div style="">
|
||||||
|
<Button on:click={dispatchConfirm}>Confirm</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 Dropdown from "../form/Dropdown.svelte";
|
||||||
|
|
||||||
|
export let guildId;
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
|
let timePeriod = "1";
|
||||||
|
|
||||||
|
function dispatchClose() {
|
||||||
|
dispatch('close', {});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dispatch with data
|
||||||
|
function dispatchConfirm() {
|
||||||
|
dispatch('confirm', {timePeriod: parseInt(timePeriod)});
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleKeydown(e) {
|
||||||
|
if (e.key === "Escape") {
|
||||||
|
dispatchClose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.modal {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 501;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-wrapper {
|
||||||
|
display: flex;
|
||||||
|
width: 40%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.body-wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
</style>
|
100
frontend/src/includes/AdminSidebar.svelte
Normal file
100
frontend/src/includes/AdminSidebar.svelte
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
<script>
|
||||||
|
import {Navigate} from 'svelte-router-spa'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="sidebar">
|
||||||
|
<div class="sidebar-container" id="sidebar-nav">
|
||||||
|
<div class="inner">
|
||||||
|
<Navigate to="/admin/bot-staff" styles="sidebar-link">
|
||||||
|
<div class="sidebar-element">
|
||||||
|
<i class="fas fa-user-group sidebar-icon"></i>
|
||||||
|
<span class="sidebar-text">Bot Staff</span>
|
||||||
|
</div>
|
||||||
|
</Navigate>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="sidebar-container">
|
||||||
|
<div class="sidebar-element">
|
||||||
|
<Navigate to="/" styles="sidebar-link">
|
||||||
|
<i class="sidebar-icon fas fa-home sidebar-icon"></i>
|
||||||
|
<span class="sidebar-text">Home</span>
|
||||||
|
</Navigate>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.sidebar {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
width: 16.6%;
|
||||||
|
background-color: #272727;
|
||||||
|
float: left;
|
||||||
|
background-size: cover;
|
||||||
|
overflow-x: hidden !important;
|
||||||
|
min-width: 250px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-container {
|
||||||
|
margin-bottom: 2%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-element {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 5px 0 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-element:hover {
|
||||||
|
background-color: #121212;
|
||||||
|
transition: background-color 0.5s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
#custom-image {
|
||||||
|
max-height: 70px;
|
||||||
|
max-width: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-text {
|
||||||
|
margin-left: 4%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sidebar-nav {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 950px) {
|
||||||
|
.sidebar {
|
||||||
|
flex-direction: row;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
height: unset;
|
||||||
|
min-width: unset;
|
||||||
|
|
||||||
|
overflow: visible !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-container {
|
||||||
|
margin-bottom: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-element {
|
||||||
|
width: unset;
|
||||||
|
padding: 20px 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -5,6 +5,7 @@
|
|||||||
export let avatar;
|
export let avatar;
|
||||||
|
|
||||||
export let isWhitelabel = false;
|
export let isWhitelabel = false;
|
||||||
|
export let isAdmin = false;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="sidebar">
|
<div class="sidebar">
|
||||||
@ -31,6 +32,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
{/if}
|
{/if}
|
||||||
|
{#if isAdmin}
|
||||||
|
<Navigate to="/admin/bot-staff" styles="sidebar-link">
|
||||||
|
<div class="sidebar-element">
|
||||||
|
<i class="fa-solid fa-user-secret sidebar-icon"></i>
|
||||||
|
<span class="sidebar-text">Admin</span>
|
||||||
|
</div>
|
||||||
|
</Navigate>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sidebar-container">
|
<div class="sidebar-container">
|
||||||
|
93
frontend/src/layouts/AdminLayout.svelte
Normal file
93
frontend/src/layouts/AdminLayout.svelte
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
<Head/>
|
||||||
|
|
||||||
|
<div class="wrapper">
|
||||||
|
<AdminSidebar />
|
||||||
|
<div class="super-container">
|
||||||
|
<LoadingScreen/>
|
||||||
|
<NotifyModal/>
|
||||||
|
<div class="content-container" class:hide={$loadingScreen}>
|
||||||
|
<Route {currentRoute} {params}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {navigateTo, Route} from 'svelte-router-spa'
|
||||||
|
import Head from '../includes/Head.svelte'
|
||||||
|
import Sidebar from '../includes/Sidebar.svelte'
|
||||||
|
import LoadingScreen from '../includes/LoadingScreen.svelte'
|
||||||
|
import NotifyModal from '../includes/NotifyModal.svelte'
|
||||||
|
import axios from "axios";
|
||||||
|
import {API_URL} from '../js/constants'
|
||||||
|
import {notifyError} from '../js/util'
|
||||||
|
import {loadingScreen} from "../js/stores"
|
||||||
|
import {redirectLogin, setDefaultHeaders} from '../includes/Auth.svelte'
|
||||||
|
import AdminSidebar from "../includes/AdminSidebar.svelte";
|
||||||
|
|
||||||
|
export let currentRoute;
|
||||||
|
export let params = {};
|
||||||
|
|
||||||
|
setDefaultHeaders()
|
||||||
|
|
||||||
|
let name;
|
||||||
|
let avatar;
|
||||||
|
|
||||||
|
let isWhitelabel = false;
|
||||||
|
let isAdmin = false;
|
||||||
|
|
||||||
|
async function loadData() {
|
||||||
|
const res = await axios.get(`${API_URL}/api/session`);
|
||||||
|
if (res.status !== 200) {
|
||||||
|
if (res.data.auth === true) {
|
||||||
|
redirectLogin();
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyError(res.data.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
isAdmin = res.data.admin;
|
||||||
|
|
||||||
|
if (!isAdmin) {
|
||||||
|
navigateTo(`/`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loadData();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0 !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.super-container {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-container {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hide {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 950px) {
|
||||||
|
.wrapper {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,7 +1,7 @@
|
|||||||
<Head/>
|
<Head/>
|
||||||
|
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<Sidebar name="{name}" avatar="{avatar}" {isWhitelabel} />
|
<Sidebar {name} {avatar} {isWhitelabel} {isAdmin} />
|
||||||
<div class="super-container">
|
<div class="super-container">
|
||||||
<LoadingScreen/>
|
<LoadingScreen/>
|
||||||
<NotifyModal/>
|
<NotifyModal/>
|
||||||
@ -32,6 +32,7 @@
|
|||||||
let avatar;
|
let avatar;
|
||||||
|
|
||||||
let isWhitelabel = false;
|
let isWhitelabel = false;
|
||||||
|
let isAdmin = false;
|
||||||
|
|
||||||
async function loadData() {
|
async function loadData() {
|
||||||
const res = await axios.get(`${API_URL}/api/session`);
|
const res = await axios.get(`${API_URL}/api/session`);
|
||||||
@ -47,6 +48,7 @@
|
|||||||
name = res.data.username;
|
name = res.data.username;
|
||||||
avatar = res.data.avatar;
|
avatar = res.data.avatar;
|
||||||
isWhitelabel = res.data.whitelabel;
|
isWhitelabel = res.data.whitelabel;
|
||||||
|
isAdmin = res.data.admin;
|
||||||
}
|
}
|
||||||
|
|
||||||
loadData();
|
loadData();
|
||||||
|
@ -2,6 +2,7 @@ import IndexLayout from './layouts/IndexLayout.svelte'
|
|||||||
import ManageLayout from './layouts/ManageLayout.svelte'
|
import ManageLayout from './layouts/ManageLayout.svelte'
|
||||||
import ErrorLayout from './layouts/ErrorPage.svelte'
|
import ErrorLayout from './layouts/ErrorPage.svelte'
|
||||||
import TranscriptViewLayout from './layouts/TranscriptViewLayout.svelte'
|
import TranscriptViewLayout from './layouts/TranscriptViewLayout.svelte'
|
||||||
|
import AdminLayout from './layouts/AdminLayout.svelte';
|
||||||
|
|
||||||
import Index from './views/Index.svelte'
|
import Index from './views/Index.svelte'
|
||||||
import LoginCallback from './views/LoginCallback.svelte'
|
import LoginCallback from './views/LoginCallback.svelte'
|
||||||
@ -21,6 +22,8 @@ import Tickets from './views/Tickets.svelte'
|
|||||||
import TicketView from './views/TicketView.svelte'
|
import TicketView from './views/TicketView.svelte'
|
||||||
import Appearance from './views/Appearance.svelte';
|
import Appearance from './views/Appearance.svelte';
|
||||||
import Forms from './views/Forms.svelte';
|
import Forms from './views/Forms.svelte';
|
||||||
|
import StaffOverride from './views/StaffOverride.svelte';
|
||||||
|
import BotStaff from './views/admin/BotStaff.svelte';
|
||||||
|
|
||||||
export const routes = [
|
export const routes = [
|
||||||
{name: '/', component: Index, layout: IndexLayout},
|
{name: '/', component: Index, layout: IndexLayout},
|
||||||
@ -30,6 +33,12 @@ export const routes = [
|
|||||||
{name: '/logout', component: Logout},
|
{name: '/logout', component: Logout},
|
||||||
{name: '/error', component: Error, layout: ErrorLayout},
|
{name: '/error', component: Error, layout: ErrorLayout},
|
||||||
{name: '/whitelabel', component: Whitelabel, layout: IndexLayout},
|
{name: '/whitelabel', component: Whitelabel, layout: IndexLayout},
|
||||||
|
{
|
||||||
|
name: 'admin',
|
||||||
|
nestedRoutes: [
|
||||||
|
{name: 'bot-staff', component: BotStaff, layout: AdminLayout},
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'manage/:id',
|
name: 'manage/:id',
|
||||||
nestedRoutes: [
|
nestedRoutes: [
|
||||||
@ -67,6 +76,7 @@ export const routes = [
|
|||||||
{name: 'tags', component: Tags, layout: ManageLayout},
|
{name: 'tags', component: Tags, layout: ManageLayout},
|
||||||
{name: 'teams', component: Teams, layout: ManageLayout},
|
{name: 'teams', component: Teams, layout: ManageLayout},
|
||||||
{name: 'forms', component: Forms, layout: ManageLayout},
|
{name: 'forms', component: Forms, layout: ManageLayout},
|
||||||
|
{name: 'staffoverride', component: StaffOverride, layout: ManageLayout},
|
||||||
{
|
{
|
||||||
name: 'tickets',
|
name: 'tickets',
|
||||||
nestedRoutes: [
|
nestedRoutes: [
|
||||||
|
134
frontend/src/views/StaffOverride.svelte
Normal file
134
frontend/src/views/StaffOverride.svelte
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
{#if modal}
|
||||||
|
<StaffOverrideModal {guildId} on:close={() => modal = false} on:confirm={handleConfirm}/>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<div class="parent">
|
||||||
|
<div class="content">
|
||||||
|
<div class="main-col">
|
||||||
|
<Card footer footerRight>
|
||||||
|
<span slot="title">Staff Override</span>
|
||||||
|
<div slot="body" class="body-wrapper">
|
||||||
|
You can grant access to the Tickets support team to temporarily access the dashboard for your server to help
|
||||||
|
you resolve issues. You can revoke access at any time by visiting this page.
|
||||||
|
</div>
|
||||||
|
<div slot="footer" class="footer-wrapper">
|
||||||
|
{#if activeOverride}
|
||||||
|
<Button danger on:click={removeOverride}>Revoke Access</Button>
|
||||||
|
{/if}
|
||||||
|
<Button on:click={() => modal = true}>Grant Access</Button>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Card from "../components/Card.svelte";
|
||||||
|
import {notifyError, notifySuccess, withLoadingScreen} from '../js/util'
|
||||||
|
import axios from "axios";
|
||||||
|
import {API_URL} from "../js/constants";
|
||||||
|
import {setDefaultHeaders} from '../includes/Auth.svelte'
|
||||||
|
import Button from "../components/Button.svelte";
|
||||||
|
import StaffOverrideModal from "../components/manage/StaffOverrideModal.svelte";
|
||||||
|
|
||||||
|
export let currentRoute;
|
||||||
|
let guildId = currentRoute.namedParams.id;
|
||||||
|
|
||||||
|
let modal = false;
|
||||||
|
let activeOverride = false;
|
||||||
|
|
||||||
|
async function handleConfirm(e) {
|
||||||
|
await createOverride(e.detail.timePeriod);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadActiveOverride() {
|
||||||
|
const res = await axios.get(`${API_URL}/api/${guildId}/staff-override`);
|
||||||
|
if (res.status !== 200) {
|
||||||
|
notifyError(res.data.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
activeOverride = res.data.has_override;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createOverride(timePeriod) {
|
||||||
|
let data = {
|
||||||
|
time_period: timePeriod
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await axios.post(`${API_URL}/api/${guildId}/staff-override`, data);
|
||||||
|
if (res.status !== 204) {
|
||||||
|
notifyError(res.data.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
modal = false;
|
||||||
|
activeOverride = true;
|
||||||
|
notifySuccess('Staff access override has been granted');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function removeOverride() {
|
||||||
|
const res = await axios.delete(`${API_URL}/api/${guildId}/staff-override`);
|
||||||
|
if (res.status !== 204) {
|
||||||
|
notifyError(res.data.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
activeOverride = false;
|
||||||
|
notifySuccess('Staff access override has been revoked');
|
||||||
|
}
|
||||||
|
|
||||||
|
withLoadingScreen(async () => {
|
||||||
|
setDefaultHeaders();
|
||||||
|
await loadActiveOverride();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.parent {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
width: 96%;
|
||||||
|
height: 100%;
|
||||||
|
margin-top: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-col {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 64%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.body-wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 10px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 950px) {
|
||||||
|
.content {
|
||||||
|
flex-direction: column-reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-col {
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 4%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
127
frontend/src/views/admin/BotStaff.svelte
Normal file
127
frontend/src/views/admin/BotStaff.svelte
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
<div class="wrapper">
|
||||||
|
<div class="content">
|
||||||
|
<Card footer="{false}" fill="{false}">
|
||||||
|
<h4 slot="title">Bot Staff</h4>
|
||||||
|
<div slot="body" class="full-width body-wrapper">
|
||||||
|
<form class="form-wrapper" on:submit|preventDefault={addStaff}>
|
||||||
|
<Input label="User ID" placeholder="585576154958921739" bind:value={tempUserId} />
|
||||||
|
<Button type="submit">Add</Button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<table class="nice">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Username</th>
|
||||||
|
<th>Remove</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{#each staff as user}
|
||||||
|
<tr>
|
||||||
|
<td>{user.username}#{user.discriminator} ({user.id})</td>
|
||||||
|
<td>
|
||||||
|
<Button type="button" danger on:click={() => removeStaff(user.id)}>
|
||||||
|
Delete
|
||||||
|
</Button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{/each}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {notifyError, withLoadingScreen} from '../../js/util'
|
||||||
|
import axios from "axios";
|
||||||
|
import Card from '../../components/Card.svelte'
|
||||||
|
import {API_URL} from "../../js/constants";
|
||||||
|
import {setDefaultHeaders} from '../../includes/Auth.svelte'
|
||||||
|
import Button from "../../components/Button.svelte";
|
||||||
|
import Input from "../../components/form/Input.svelte";
|
||||||
|
|
||||||
|
setDefaultHeaders()
|
||||||
|
|
||||||
|
let staff = [];
|
||||||
|
let tempUserId = "";
|
||||||
|
|
||||||
|
async function addStaff() {
|
||||||
|
if (tempUserId.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await axios.post(`${API_URL}/api/admin/bot-staff/${tempUserId}`);
|
||||||
|
if (res.status !== 204) {
|
||||||
|
notifyError(res.data.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tempUserId = "";
|
||||||
|
await loadData(); // TODO: Return user data with response
|
||||||
|
}
|
||||||
|
|
||||||
|
async function removeStaff(userId) {
|
||||||
|
const res = await axios.delete(`${API_URL}/api/admin/bot-staff/${userId}`);
|
||||||
|
if (res.status !== 204) {
|
||||||
|
notifyError(res.data.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
staff = staff.filter(user => user.id !== userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadData() {
|
||||||
|
const res = await axios.get(`${API_URL}/api/admin/bot-staff`);
|
||||||
|
if (res.status !== 200) {
|
||||||
|
notifyError(res.data.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
staff = res.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
withLoadingScreen(async () => {
|
||||||
|
await loadData();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
flex-direction: row;
|
||||||
|
width: 95%;
|
||||||
|
|
||||||
|
margin-top: 2%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 900px) {
|
||||||
|
.content {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.body-wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
gap: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
2
go.mod
2
go.mod
@ -6,7 +6,7 @@ require (
|
|||||||
github.com/BurntSushi/toml v0.3.1
|
github.com/BurntSushi/toml v0.3.1
|
||||||
github.com/TicketsBot/archiverclient v0.0.0-20220326163414-558fd52746dc
|
github.com/TicketsBot/archiverclient v0.0.0-20220326163414-558fd52746dc
|
||||||
github.com/TicketsBot/common v0.0.0-20220615205931-a6a31e73b52a
|
github.com/TicketsBot/common v0.0.0-20220615205931-a6a31e73b52a
|
||||||
github.com/TicketsBot/database v0.0.0-20220621182433-accd1b2b81de
|
github.com/TicketsBot/database v0.0.0-20220623160906-a56dc9dfda90
|
||||||
github.com/TicketsBot/logarchiver v0.0.0-20220326162808-cdf0310f5e1c
|
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-20220621165800-203b0004b733
|
||||||
github.com/apex/log v1.1.2
|
github.com/apex/log v1.1.2
|
||||||
|
2
go.sum
2
go.sum
@ -7,6 +7,8 @@ github.com/TicketsBot/common v0.0.0-20220615205931-a6a31e73b52a h1:SwA18cDURmnXS
|
|||||||
github.com/TicketsBot/common v0.0.0-20220615205931-a6a31e73b52a/go.mod h1:ZAoYcDD7SQLTsZT7dbo/X0J256+pogVRAReunCGng+U=
|
github.com/TicketsBot/common v0.0.0-20220615205931-a6a31e73b52a/go.mod h1:ZAoYcDD7SQLTsZT7dbo/X0J256+pogVRAReunCGng+U=
|
||||||
github.com/TicketsBot/database v0.0.0-20220621182433-accd1b2b81de h1:UsRiB3KIwqIF92huRBFKAnCoGLyT9kBYYUycsapBZk0=
|
github.com/TicketsBot/database v0.0.0-20220621182433-accd1b2b81de h1:UsRiB3KIwqIF92huRBFKAnCoGLyT9kBYYUycsapBZk0=
|
||||||
github.com/TicketsBot/database v0.0.0-20220621182433-accd1b2b81de/go.mod h1:F57cywrZsnper1cy56Bx0c/HEsxQBLHz3Pl98WXblWw=
|
github.com/TicketsBot/database v0.0.0-20220621182433-accd1b2b81de/go.mod h1:F57cywrZsnper1cy56Bx0c/HEsxQBLHz3Pl98WXblWw=
|
||||||
|
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/logarchiver v0.0.0-20220326162808-cdf0310f5e1c h1:OqGjFH6mbE6gd+NqI2ARJdtH3UUvhiAkD0r0fhGJK2s=
|
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/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 h1:NHD5GB6cjlkpZFjC76Yli2S63/J2nhr8MuE6KlYJpQM=
|
||||||
|
@ -20,6 +20,24 @@ func GetPermissionLevel(guildId, userId uint64) (permission.PermissionLevel, err
|
|||||||
return permission.Admin, nil
|
return permission.Admin, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check staff override
|
||||||
|
staffOverride, err := dbclient.Client.StaffOverride.HasActiveOverride(guildId)
|
||||||
|
if err != nil {
|
||||||
|
return permission.Everyone, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If staff override enabled and the user is bot staff, grant admin permissions
|
||||||
|
if staffOverride {
|
||||||
|
isBotStaff, err := dbclient.Client.BotStaff.IsStaff(userId)
|
||||||
|
if err != nil {
|
||||||
|
return permission.Everyone, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if isBotStaff {
|
||||||
|
return permission.Admin, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// get member
|
// get member
|
||||||
member, err := botContext.GetGuildMember(guildId, userId)
|
member, err := botContext.GetGuildMember(guildId, userId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user