Improve time complexity
This commit is contained in:
parent
49ce52283c
commit
1ec71e586a
@ -1,57 +1,28 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"github.com/TicketsBot/GoPanel/utils"
|
"github.com/TicketsBot/GoPanel/utils"
|
||||||
"github.com/TicketsBot/common/permission"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"golang.org/x/sync/errgroup"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetPermissionLevel(ctx *gin.Context) {
|
func GetPermissionLevel(ctx *gin.Context) {
|
||||||
userId := ctx.Keys["userid"].(uint64)
|
userId := ctx.Keys["userid"].(uint64)
|
||||||
|
|
||||||
guilds := strings.Split(ctx.Query("guilds"), ",")
|
guildId, err := strconv.ParseUint(ctx.Query("guild"), 10, 64)
|
||||||
if len(guilds) > 100 {
|
if err != nil {
|
||||||
ctx.JSON(400, gin.H{
|
ctx.JSON(400, utils.ErrorStr("Invalid guild ID"))
|
||||||
"success": false,
|
|
||||||
"error": "too many guilds",
|
|
||||||
})
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: This is insanely inefficient
|
permissionLevel, err := utils.GetPermissionLevel(guildId, userId)
|
||||||
|
if err != nil {
|
||||||
levels := make(map[string]permission.PermissionLevel)
|
|
||||||
|
|
||||||
group, _ := errgroup.WithContext(context.Background())
|
|
||||||
for _, raw := range guilds {
|
|
||||||
guildId, err := strconv.ParseUint(raw, 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
ctx.JSON(400, gin.H{
|
|
||||||
"success": false,
|
|
||||||
"error": fmt.Sprintf("invalid guild id: %s", raw),
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
group.Go(func() error {
|
|
||||||
level, err := utils.GetPermissionLevel(guildId, userId)
|
|
||||||
levels[strconv.FormatUint(guildId, 10)] = level
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := group.Wait(); err != nil {
|
|
||||||
ctx.JSON(500, utils.ErrorJson(err))
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.JSON(200, gin.H{
|
ctx.JSON(200, gin.H{
|
||||||
"success": true,
|
"success": true,
|
||||||
"levels": levels,
|
"permission_level": permissionLevel,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,14 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/TicketsBot/GoPanel/database"
|
dbclient "github.com/TicketsBot/GoPanel/database"
|
||||||
"github.com/TicketsBot/GoPanel/rpc/cache"
|
"github.com/TicketsBot/GoPanel/rpc/cache"
|
||||||
"github.com/TicketsBot/GoPanel/utils"
|
"github.com/TicketsBot/GoPanel/utils"
|
||||||
"github.com/TicketsBot/common/permission"
|
"github.com/TicketsBot/common/permission"
|
||||||
syncutils "github.com/TicketsBot/common/utils"
|
syncutils "github.com/TicketsBot/common/utils"
|
||||||
|
"github.com/TicketsBot/database"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/jackc/pgx/v4"
|
"github.com/jackc/pgtype"
|
||||||
"github.com/rxdn/gdl/objects/guild"
|
|
||||||
"github.com/rxdn/gdl/rest/request"
|
"github.com/rxdn/gdl/rest/request"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
"sort"
|
"sort"
|
||||||
@ -24,47 +24,50 @@ type wrappedGuild struct {
|
|||||||
func GetGuilds(ctx *gin.Context) {
|
func GetGuilds(ctx *gin.Context) {
|
||||||
userId := ctx.Keys["userid"].(uint64)
|
userId := ctx.Keys["userid"].(uint64)
|
||||||
|
|
||||||
guilds, err := database.Client.UserGuilds.Get(userId)
|
// Get all guilds the user is in
|
||||||
|
guilds, err := dbclient.Client.UserGuilds.Get(userId)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the subset of guilds that the user is in that the bot is also in
|
||||||
|
guildIds := make([]uint64, len(guilds))
|
||||||
|
guildMap := make(map[uint64]database.UserGuild) // Make a map of all guilds for O(1) access
|
||||||
|
for i, guild := range guilds {
|
||||||
|
guildIds[i] = guild.GuildId
|
||||||
|
guildMap[guild.GuildId] = guild
|
||||||
|
}
|
||||||
|
|
||||||
|
botGuilds, err := getExistingGuilds(guildIds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.JSON(500, utils.ErrorJson(err))
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
wg := syncutils.NewChannelWaitGroup()
|
wg := syncutils.NewChannelWaitGroup()
|
||||||
wg.Add(len(guilds))
|
wg.Add(len(botGuilds))
|
||||||
|
|
||||||
group, _ := errgroup.WithContext(context.Background())
|
group, _ := errgroup.WithContext(context.Background())
|
||||||
ch := make(chan wrappedGuild)
|
ch := make(chan wrappedGuild)
|
||||||
for _, g := range guilds {
|
for _, guildId := range botGuilds {
|
||||||
g := g
|
guildId := guildId
|
||||||
|
g := guildMap[guildId]
|
||||||
|
|
||||||
group.Go(func() error {
|
group.Go(func() error {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
|
||||||
// verify bot is in guild
|
// Determine the user's permission level in this guild
|
||||||
if err := cache.Instance.QueryRow(context.Background(), `SELECT 1 from guilds WHERE "guild_id" = $1`, g.GuildId).Scan(nil); err != nil {
|
var permLevel permission.PermissionLevel
|
||||||
if err == pgx.ErrNoRows {
|
|
||||||
return nil
|
|
||||||
} else {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fakeGuild := guild.Guild{
|
|
||||||
Id: g.GuildId,
|
|
||||||
Owner: g.Owner,
|
|
||||||
Permissions: g.UserPermissions,
|
|
||||||
}
|
|
||||||
|
|
||||||
if g.Owner {
|
if g.Owner {
|
||||||
fakeGuild.OwnerId = userId
|
permLevel = permission.Admin
|
||||||
}
|
} else {
|
||||||
|
permLevel, err = utils.GetPermissionLevel(g.GuildId, userId)
|
||||||
permLevel, err := utils.GetPermissionLevel(g.GuildId, userId)
|
if err != nil {
|
||||||
if err != nil {
|
// If a Discord error occurs, just skip the server
|
||||||
// If a Discord error occurs, just skip the server
|
if _, ok := err.(request.RestError); !ok {
|
||||||
if _, ok := err.(request.RestError); !ok {
|
return err
|
||||||
return err
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,7 +99,10 @@ func GetGuilds(ctx *gin.Context) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
_ = group.Wait() // error not possible
|
if err := group.Wait(); err != nil {
|
||||||
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// sort
|
// sort
|
||||||
sort.Slice(adminGuilds, func(i, j int) bool {
|
sort.Slice(adminGuilds, func(i, j int) bool {
|
||||||
@ -106,24 +112,30 @@ func GetGuilds(ctx *gin.Context) {
|
|||||||
ctx.JSON(200, adminGuilds)
|
ctx.JSON(200, adminGuilds)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*func getAdminGuilds(userId uint64) ([]uint64, error) {
|
func getExistingGuilds(userGuilds []uint64) ([]uint64, error) {
|
||||||
var guilds []uint64
|
query := `SELECT "guild_id" from guilds WHERE "guild_id" = ANY($1);`
|
||||||
|
|
||||||
// get guilds owned by user
|
userGuildsArray := &pgtype.Int8Array{}
|
||||||
query := `SELECT "guild_id" FROM guilds WHERE "data"->'owner_id' = '$1';`
|
if err := userGuildsArray.Set(userGuilds); err != nil {
|
||||||
rows, err := cache.Instance.Query(context.Background(), query, userId)
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rows, err := cache.Instance.Query(context.Background(), query, userGuildsArray)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var existingGuilds []uint64
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var guildId uint64
|
var guildId uint64
|
||||||
if err := rows.Scan(&guildId); err != nil {
|
if err := rows.Scan(&guildId); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
guilds = append(guilds, guildId)
|
existingGuilds = append(existingGuilds, guildId)
|
||||||
}
|
}
|
||||||
|
|
||||||
database.Client.Permissions.GetSupport()
|
return existingGuilds, nil
|
||||||
}*/
|
}
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"github.com/TicketsBot/GoPanel/database"
|
"github.com/TicketsBot/GoPanel/database"
|
||||||
"github.com/TicketsBot/GoPanel/rpc/cache"
|
"github.com/TicketsBot/GoPanel/rpc/cache"
|
||||||
|
"github.com/TicketsBot/GoPanel/utils"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/rxdn/gdl/objects/user"
|
"github.com/rxdn/gdl/objects/user"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
@ -19,10 +20,7 @@ func GetTickets(ctx *gin.Context) {
|
|||||||
|
|
||||||
tickets, err := database.Client.Tickets.GetGuildOpenTickets(guildId)
|
tickets, err := database.Client.Tickets.GetGuildOpenTickets(guildId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.AbortWithStatusJSON(500, gin.H{
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
"success": false,
|
|
||||||
"error": err.Error(),
|
|
||||||
})
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,10 +48,7 @@ func GetTickets(ctx *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := group.Wait(); err != nil {
|
if err := group.Wait(); err != nil {
|
||||||
ctx.AbortWithStatusJSON(500, gin.H{
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
"success": false,
|
|
||||||
"error": err.Error(),
|
|
||||||
})
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,8 +38,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function goto(guildId) {
|
async function goto(guildId) {
|
||||||
const permissionLevels = await getPermissionLevel(guildId);
|
const permissionLevel = await getPermissionLevel(guildId);
|
||||||
if (permissionLevels[guildId] === 2) {
|
if (permissionLevel === 2) {
|
||||||
window.location.href = `/manage/${guildId}/settings`;
|
window.location.href = `/manage/${guildId}/settings`;
|
||||||
} else {
|
} else {
|
||||||
window.location.href = `/manage/${guildId}/transcripts`;
|
window.location.href = `/manage/${guildId}/transcripts`;
|
||||||
@ -47,13 +47,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function getPermissionLevel(guildId) {
|
async function getPermissionLevel(guildId) {
|
||||||
const res = await axios.get(`${API_URL}/user/permissionlevel?guilds=${guildId}`);
|
const res = await axios.get(`${API_URL}/user/permissionlevel?guild=${guildId}`);
|
||||||
if (res.status !== 200 || !res.data.success) {
|
if (res.status !== 200 || !res.data.success) {
|
||||||
notifyError(res.data.error);
|
notifyError(res.data.error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.data.levels;
|
return res.data.permission_level;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -5,14 +5,14 @@ import (
|
|||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ErrorJson(err error) map[string]interface{} {
|
func ErrorJson(err error) map[string]any {
|
||||||
return ErrorStr(err.Error())
|
return ErrorStr(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
func ErrorStr(err string, format ...interface{}) map[string]interface{} {
|
func ErrorStr(err string, format ...any) map[string]any {
|
||||||
return gin.H {
|
return gin.H{
|
||||||
"success": false,
|
"success": false,
|
||||||
"error": fmt.Sprintf(err, format...),
|
"error": fmt.Sprintf(err, format...),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user