diff --git a/go.mod b/go.mod index eb0fcb0..6b17a34 100644 --- a/go.mod +++ b/go.mod @@ -70,7 +70,6 @@ require ( github.com/cloudwego/iasm v0.2.0 // indirect github.com/dgraph-io/ristretto v1.0.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect - github.com/expr-lang/expr v1.17.3 // indirect github.com/gabriel-vasile/mimetype v1.4.6 // indirect github.com/getlantern/context v0.0.0-20220418194847-3d5e7a086201 // indirect github.com/getlantern/errors v1.0.4 // indirect diff --git a/go.sum b/go.sum index a12698d..c9c85b6 100644 --- a/go.sum +++ b/go.sum @@ -58,8 +58,6 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/expr-lang/expr v1.17.3 h1:myeTTuDFz7k6eFe/JPlep/UsiIjVhG61FMHFu63U7j0= -github.com/expr-lang/expr v1.17.3/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= diff --git a/usercache.go b/usercache.go index 68af907..c04b600 100644 --- a/usercache.go +++ b/usercache.go @@ -1,6 +1,7 @@ package main import ( + "cmp" "sync" "time" ) @@ -17,6 +18,7 @@ type UserCache struct { } func (c *UserCache) Gen(app *appContext) error { + c.Lock.Lock() if !time.Now().After(c.LastSync.Add(WEB_USER_CACHE_SYNC)) { return nil } @@ -24,7 +26,6 @@ func (c *UserCache) Gen(app *appContext) error { if err != nil { return err } - c.Lock.Lock() c.Cache = make([]respUser, len(users)) for i, jfUser := range users { c.Cache[i] = app.userSummary(jfUser) @@ -33,3 +34,116 @@ func (c *UserCache) Gen(app *appContext) error { c.Lock.Unlock() return nil } + +type SortableUserList struct { + Cache []respUser + lessFunc func(a, b *respUser) bool +} + +func (sc *SortableUserList) Len() int { + return len(sc.Cache) +} + +func (sc *SortableUserList) Swap(i, j int) { + sc.Cache[i], sc.Cache[j] = sc.Cache[j], sc.Cache[i] +} + +func (sc *SortableUserList) Less(i, j int) bool { + return sc.lessFunc(&sc.Cache[i], &sc.Cache[j]) +} + +// instead of making a Less for bools, just convert them to integers +// https://0x0f.me/blog/golang-compiler-optimization/ +func bool2int(b bool) int { + var i int + if b { + i = 1 + } else { + i = 0 + } + return i +} + +// Allow sorting by respUser's struct fields (well, it's JSON-representation's fields) +// Ugly I know, but at least cmp.Less exists. +// Done with vim macros, thank god they exist +func SortUsersBy(u []respUser, field string) SortableUserList { + s := SortableUserList{Cache: u} + + switch field { + case "id": + s.lessFunc = func(a, b *respUser) bool { + return cmp.Less(a.ID, b.ID) + } + + case "name": + s.lessFunc = func(a, b *respUser) bool { + return cmp.Less(a.Name, b.Name) + } + case "email": + s.lessFunc = func(a, b *respUser) bool { + return cmp.Less(a.Email, b.Email) + } + case "notify_email": + s.lessFunc = func(a, b *respUser) bool { + return cmp.Less(bool2int(a.NotifyThroughEmail), bool2int(b.NotifyThroughEmail)) + } + case "last_active": + s.lessFunc = func(a, b *respUser) bool { + return cmp.Less(a.LastActive, b.LastActive) + } + case "admin": + s.lessFunc = func(a, b *respUser) bool { + return cmp.Less(bool2int(a.Admin), bool2int(b.Admin)) + } + case "expiry": + s.lessFunc = func(a, b *respUser) bool { + return cmp.Less(a.Expiry, b.Expiry) + } + case "disabled": + s.lessFunc = func(a, b *respUser) bool { + return cmp.Less(bool2int(a.Disabled), bool2int(b.Disabled)) + } + case "telegram": + s.lessFunc = func(a, b *respUser) bool { + return cmp.Less(a.Telegram, b.Telegram) + } + case "notify_telegram": + s.lessFunc = func(a, b *respUser) bool { + return cmp.Less(bool2int(a.NotifyThroughTelegram), bool2int(b.NotifyThroughTelegram)) + } + case "discord": + s.lessFunc = func(a, b *respUser) bool { + return cmp.Less(a.Discord, b.Discord) + } + case "discord_id": + s.lessFunc = func(a, b *respUser) bool { + return cmp.Less(a.DiscordID, b.DiscordID) + } + case "notify_discord": + s.lessFunc = func(a, b *respUser) bool { + return cmp.Less(bool2int(a.NotifyThroughDiscord), bool2int(b.NotifyThroughDiscord)) + } + case "matrix": + s.lessFunc = func(a, b *respUser) bool { + return cmp.Less(a.Matrix, b.Matrix) + } + case "notify_matrix": + s.lessFunc = func(a, b *respUser) bool { + return cmp.Less(bool2int(a.NotifyThroughMatrix), bool2int(b.NotifyThroughMatrix)) + } + case "label": + s.lessFunc = func(a, b *respUser) bool { + return cmp.Less(a.Label, b.Label) + } + case "accounts_admin": + s.lessFunc = func(a, b *respUser) bool { + return cmp.Less(bool2int(a.AccountsAdmin), bool2int(b.AccountsAdmin)) + } + case "referrals_enabled": + s.lessFunc = func(a, b *respUser) bool { + return cmp.Less(bool2int(a.ReferralsEnabled), bool2int(b.ReferralsEnabled)) + } + } + return s +}