Improve ban commands

This commit is contained in:
Eccentric 2024-02-10 01:55:56 +00:00
parent 33bfef4da8
commit 0a63dd8fe4
10 changed files with 499 additions and 130 deletions

View File

@ -56,3 +56,12 @@ func (s *GenericSyncMap[T]) ChangeKey(oldKey, newKey string) {
s.Set(newKey, v)
s.Delete(oldKey)
}
func (s *GenericSyncMap[T]) Len() int {
count := 0
s.m.Range(func(_, _ interface{}) bool {
count++
return true
})
return count
}

View File

@ -1,6 +1,9 @@
package aid
import "time"
import (
"errors"
"time"
)
func TimeStartOfDay() string {
return time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), 0, 0, 0, 0, time.Now().Location()).Format("2006-01-02T15:04:05.999Z")
@ -13,3 +16,172 @@ func TimeEndOfDay() string {
func TimeEndOfWeekString() string {
return time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), 23, 59, 59, 999999999, time.Now().Location()).AddDate(0, 0, 7).Format("2006-01-02T15:04:05.999Z")
}
// everything below is taken from the golang standard library I just added the extra units to the map
var unitMap = map[string]uint64{
"ns": uint64(time.Nanosecond),
"us": uint64(time.Microsecond),
"µs": uint64(time.Microsecond), // U+00B5 = micro symbol
"μs": uint64(time.Microsecond), // U+03BC = Greek letter mu
"ms": uint64(time.Millisecond),
"s": uint64(time.Second),
"m": uint64(time.Minute),
"h": uint64(time.Hour),
"d": uint64(time.Hour * 24),
"w": uint64(time.Hour * 24 * 7),
"y": uint64(time.Hour * 24 * 365), // no leap year
"c": uint64(time.Hour * 24 * 365 * 100), // no leap year
}
// ParseDuration parses a duration string.
// A duration string is a possibly signed sequence of
// decimal numbers, each with optional fraction and a unit suffix,
// such as "300ms", "-1.5h" or "2h45m".
// Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
func leadingFraction(s string) (x uint64, scale float64, rem string) {
i := 0
scale = 1
overflow := false
for ; i < len(s); i++ {
c := s[i]
if c < '0' || c > '9' {
break
}
if overflow {
continue
}
if x > (1<<63-1)/10 {
// It's possible for overflow to give a positive number, so take care.
overflow = true
continue
}
y := x*10 + uint64(c) - '0'
if y > 1<<63 {
overflow = true
continue
}
x = y
scale *= 10
}
return x, scale, s[i:]
}
func leadingInt[bytes []byte | string](s bytes) (x uint64, rem bytes, err error) {
i := 0
for ; i < len(s); i++ {
c := s[i]
if c < '0' || c > '9' {
break
}
if x > 1<<63/10 {
// overflow
return 0, rem, errors.New("time: invalid duration ")
}
x = x*10 + uint64(c) - '0'
if x > 1<<63 {
// overflow
return 0, rem, errors.New("time: invalid duration ")
}
}
return x, s[i:], nil
}
func ParseDuration(s string) (time.Duration, error) {
// [-+]?([0-9]*(\.[0-9]*)?[a-z]+)+
var d uint64
neg := false
// Consume [-+]?
if s != "" {
c := s[0]
if c == '-' || c == '+' {
neg = c == '-'
s = s[1:]
}
}
// Special case: if all that is left is "0", this is zero.
if s == "0" {
return 0, nil
}
if s == "" {
return 0, errors.New("time: invalid duration")
}
for s != "" {
var (
v, f uint64 // integers before, after decimal point
scale float64 = 1 // value = v + f/scale
)
var err error
// The next character must be [0-9.]
if !(s[0] == '.' || '0' <= s[0] && s[0] <= '9') {
return 0, errors.New("time: invalid duration")
}
// Consume [0-9]*
pl := len(s)
v, s, err = leadingInt(s)
if err != nil {
return 0, errors.New("time: invalid duration")
}
pre := pl != len(s) // whether we consumed anything before a period
// Consume (\.[0-9]*)?
post := false
if s != "" && s[0] == '.' {
s = s[1:]
pl := len(s)
f, scale, s = leadingFraction(s)
post = pl != len(s)
}
if !pre && !post {
// no digits (e.g. ".s" or "-.s")
return 0, errors.New("time: invalid duration")
}
// Consume unit.
i := 0
for ; i < len(s); i++ {
c := s[i]
if c == '.' || '0' <= c && c <= '9' {
break
}
}
if i == 0 {
return 0, errors.New("time: missing unit in duration")
}
u := s[:i]
s = s[i:]
unit, ok := unitMap[u]
if !ok {
return 0, errors.New("time: unknown unit in duration")
}
if v > 1<<63/unit {
// overflow
return 0, errors.New("time: invalid duration ")
}
v *= unit
if f > 0 {
// float64 is needed to be nanosecond accurate for fractions of hours.
// v >= 0 && (f*unit/scale) <= 3.6e+12 (ns/h, h is the largest unit)
v += uint64(float64(f) * (float64(unit) / scale))
if v > 1<<63 {
// overflow
return 0, errors.New("time: invalid duration")
}
}
d += v
if d > 1<<63 {
return 0, errors.New("time: invalid duration")
}
}
if neg {
return -time.Duration(d), nil
}
if d > 1<<63-1 {
return 0, errors.New("time: invalid duration")
}
return time.Duration(d), nil
}

View File

@ -1,6 +1,7 @@
package discord
import (
"fmt"
"strings"
"github.com/bwmarrin/discordgo"
@ -107,64 +108,117 @@ func whoHandler(s *discordgo.Session, i *discordgo.InteractionCreate) {
})
}
func banHandler(s *discordgo.Session, i *discordgo.InteractionCreate) {
func bansHandler(s *discordgo.Session, i *discordgo.InteractionCreate) {
looker := person.FindByDiscord(i.Member.User.ID)
if looker == nil {
s.InteractionRespond(i.Interaction, &ErrorNoPermission)
return
}
if !looker.HasPermission(person.PermissionBan) {
if !looker.HasPermission(person.PermissionBansControl) {
s.InteractionRespond(i.Interaction, &ErrorNoPermission)
return
}
player := getPersonFromOptions(i.ApplicationCommandData().Options, s)
if len(i.ApplicationCommandData().Options) <= 0 {
s.InteractionRespond(i.Interaction, &ErrorInvalidArguments)
return
}
subCommand := i.ApplicationCommandData().Options[0]
if len(subCommand.Options) <= 0 {
s.InteractionRespond(i.Interaction, &ErrorInvalidArguments)
return
}
player := getPersonFromOptions(subCommand.Options, s)
if player == nil {
s.InteractionRespond(i.Interaction, &ErrorInvalidDisplayOrDiscord)
return
}
player.Ban()
lookup := map[string]func(s *discordgo.Session, i *discordgo.InteractionCreate, looker *person.Person, player *person.Person, options []*discordgo.ApplicationCommandInteractionDataOption){
"add": addBanHandler,
"clear": clearBansHandler,
"list": listBansHandler,
}
if handler, ok := lookup[subCommand.Name]; ok {
handler(s, i, looker, player, subCommand.Options)
return
}
s.InteractionRespond(i.Interaction, &ErrorInvalidArguments)
}
func addBanHandler(s *discordgo.Session, i *discordgo.InteractionCreate, looker *person.Person, player *person.Person, options []*discordgo.ApplicationCommandInteractionDataOption) {
reason := options[0].StringValue()
if reason == "" {
s.InteractionRespond(i.Interaction, &ErrorInvalidArguments)
return
}
var expiry string
for _, option := range options {
if option.Name == "expires" {
expiry = option.StringValue()
break
}
}
aid.Print(expiry)
player.AddBan(reason, looker.ID, expiry)
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: player.DisplayName + " has been banned.",
Content: player.DisplayName + " has been banned for `" + reason + "`.",
},
})
}
func unbanHandler(s *discordgo.Session, i *discordgo.InteractionCreate) {
looker := person.FindByDiscord(i.Member.User.ID)
if looker == nil {
s.InteractionRespond(i.Interaction, &ErrorNoPermission)
return
}
if !looker.HasPermission(person.PermissionBan) {
s.InteractionRespond(i.Interaction, &ErrorNoPermission)
return
}
player := getPersonFromOptions(i.ApplicationCommandData().Options, s)
if player == nil {
s.InteractionRespond(i.Interaction, &ErrorInvalidDisplayOrDiscord)
return
}
player.Unban()
func clearBansHandler(s *discordgo.Session, i *discordgo.InteractionCreate, looker *person.Person, player *person.Person, options []*discordgo.ApplicationCommandInteractionDataOption) {
player.ClearBans()
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: player.DisplayName + " has been unbanned.",
Content: player.DisplayName + " has had all bans cleared.",
},
})
}
func giveItemHandler(s *discordgo.Session, i *discordgo.InteractionCreate) {
func listBansHandler(s *discordgo.Session, i *discordgo.InteractionCreate, looker *person.Person, player *person.Person, options []*discordgo.ApplicationCommandInteractionDataOption) {
embed := NewEmbedBuilder().
SetTitle("Ban History").
SetColor(0x2b2d31)
player.BanHistory.Range(func(key string, ban *storage.DB_BanStatus) bool {
banIssuer := person.Find(ban.IssuedBy)
if banIssuer == nil {
banIssuer = &person.Person{Discord: &storage.DB_DiscordPerson{ID: "0"}}
}
embed.AddField(ban.Reason, "Banned by <@"+banIssuer.Discord.ID+"> on <t:"+fmt.Sprintf("%d", ban.Expiry.Unix())+":D>", false)
return true
})
if player.BanHistory.Len() <= 0 {
embed.SetDescription("No bans found.")
}
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Embeds: []*discordgo.MessageEmbed{embed.Build()},
Flags: discordgo.MessageFlagsEphemeral,
},
})
}
func itemsHandler(s *discordgo.Session, i *discordgo.InteractionCreate) {
looker := person.FindByDiscord(i.Member.User.ID)
if looker == nil {
s.InteractionRespond(i.Interaction, &ErrorNoAccount)
s.InteractionRespond(i.Interaction, &ErrorNoPermission)
return
}
@ -173,25 +227,56 @@ func giveItemHandler(s *discordgo.Session, i *discordgo.InteractionCreate) {
return
}
player := getPersonFromOptions(i.ApplicationCommandData().Options, s)
if len(i.ApplicationCommandData().Options) <= 0 {
s.InteractionRespond(i.Interaction, &ErrorInvalidArguments)
return
}
subCommand := i.ApplicationCommandData().Options[0]
if len(subCommand.Options) <= 0 {
s.InteractionRespond(i.Interaction, &ErrorInvalidArguments)
return
}
player := getPersonFromOptions(subCommand.Options, s)
if player == nil {
s.InteractionRespond(i.Interaction, &ErrorInvalidDisplayOrDiscord)
return
}
item := i.ApplicationCommandData().Options[0].StringValue()
lookup := map[string]func(s *discordgo.Session, i *discordgo.InteractionCreate, looker *person.Person, player *person.Person, options []*discordgo.ApplicationCommandInteractionDataOption){
"add": addItemHandler,
"remove": removeItemHandler,
"fill": fillItemsHandler,
}
if handler, ok := lookup[subCommand.Name]; ok {
handler(s, i, looker, player, subCommand.Options)
return
}
s.InteractionRespond(i.Interaction, &ErrorInvalidArguments)
}
func addItemHandler(s *discordgo.Session, i *discordgo.InteractionCreate, looker *person.Person, player *person.Person, options []*discordgo.ApplicationCommandInteractionDataOption) {
if !looker.HasPermission(person.PermissionItemControl) {
s.InteractionRespond(i.Interaction, &ErrorNoPermission)
return
}
item := options[0].StringValue()
if item == "" {
s.InteractionRespond(i.Interaction, &ErrorInvalidArguments)
return
}
qty := i.ApplicationCommandData().Options[1].IntValue()
qty := options[1].IntValue()
if qty <= 0 {
s.InteractionRespond(i.Interaction, &ErrorInvalidArguments)
return
}
profile := i.ApplicationCommandData().Options[2].StringValue()
profile := options[2].StringValue()
if profile == "" {
s.InteractionRespond(i.Interaction, &ErrorInvalidArguments)
return
@ -222,37 +307,25 @@ func giveItemHandler(s *discordgo.Session, i *discordgo.InteractionCreate) {
})
}
func takeItemHandler(s *discordgo.Session, i *discordgo.InteractionCreate) {
looker := person.FindByDiscord(i.Member.User.ID)
if looker == nil {
s.InteractionRespond(i.Interaction, &ErrorNoAccount)
return
}
func removeItemHandler(s *discordgo.Session, i *discordgo.InteractionCreate, looker *person.Person, player *person.Person, options []*discordgo.ApplicationCommandInteractionDataOption) {
if !looker.HasPermission(person.PermissionItemControl) {
s.InteractionRespond(i.Interaction, &ErrorNoPermission)
return
}
player := getPersonFromOptions(i.ApplicationCommandData().Options, s)
if player == nil {
s.InteractionRespond(i.Interaction, &ErrorInvalidDisplayOrDiscord)
return
}
item := i.ApplicationCommandData().Options[0].StringValue()
item := options[0].StringValue()
if item == "" {
s.InteractionRespond(i.Interaction, &ErrorInvalidArguments)
return
}
qty := i.ApplicationCommandData().Options[1].IntValue()
qty := options[1].IntValue()
if qty <= 0 {
s.InteractionRespond(i.Interaction, &ErrorInvalidArguments)
return
}
profile := i.ApplicationCommandData().Options[2].StringValue()
profile := options[2].StringValue()
if profile == "" {
s.InteractionRespond(i.Interaction, &ErrorInvalidArguments)
return
@ -273,7 +346,6 @@ func takeItemHandler(s *discordgo.Session, i *discordgo.InteractionCreate) {
default:
foundItem.Quantity -= int(qty)
foundItem.Save()
if foundItem.Quantity <= 0 {
player.GetProfileFromType(profile).Items.DeleteItem(foundItem.ID)
remove = true
@ -294,31 +366,18 @@ func takeItemHandler(s *discordgo.Session, i *discordgo.InteractionCreate) {
})
}
func giveEverythingHandler(s *discordgo.Session, i *discordgo.InteractionCreate) {
looker := person.FindByDiscord(i.Member.User.ID)
if looker == nil {
s.InteractionRespond(i.Interaction, &ErrorNoPermission)
return
}
func fillItemsHandler(s *discordgo.Session, i *discordgo.InteractionCreate, looker *person.Person, player *person.Person, options []*discordgo.ApplicationCommandInteractionDataOption) {
if !looker.HasPermission(person.PermissionItemControl) || !looker.HasPermission(person.PermissionLockerControl) {
s.InteractionRespond(i.Interaction, &ErrorNoPermission)
return
}
player := getPersonFromOptions(i.ApplicationCommandData().Options, s)
if player == nil {
s.InteractionRespond(i.Interaction, &ErrorInvalidDisplayOrDiscord)
return
}
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseDeferredChannelMessageWithSource,
})
fortnite.GiveEverything(player)
str := player.DisplayName + "has been granted everything."
str := player.DisplayName + "has been granted all items."
s.InteractionResponseEdit(i.Interaction, &discordgo.WebhookEdit{
Content: &str,
})

View File

@ -48,7 +48,7 @@ func addCommands() {
addCommand(&DiscordCommand{
Command: &discordgo.ApplicationCommand{
Name: "me",
Name: "account",
Description: "Lookup your own information.",
},
Handler: meHandler,
@ -89,23 +89,49 @@ func addCommands() {
AdminOnly: true,
})
addCommand(&DiscordCommand{
Command: &discordgo.ApplicationCommand{
Name: "ban",
Description: "Ban a player from using the bot.",
bansOptions := append([]*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionString,
Name: "reason",
Description: "The reason for the ban.",
Required: true,
},
{
Type: discordgo.ApplicationCommandOptionString,
Name: "expires",
Description: "The time the ban expires. (e.g. 1y, 1w, 1d, 1h, 1m, 1s) (default: 1w)",
Required: false,
},
}, personOptions...)
bansSubCommands := []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionSubCommand,
Name: "add",
Description: "Ban a player from using this service.",
Options: bansOptions,
},
{
Type: discordgo.ApplicationCommandOptionSubCommand,
Name: "clear",
Description: "Clear all bans from a player.",
Options: personOptions,
},
Handler: banHandler,
AdminOnly: true,
})
{
Type: discordgo.ApplicationCommandOptionSubCommand,
Name: "list",
Description: "List all previous bans from a player.",
Options: personOptions,
},
}
addCommand(&DiscordCommand{
Command: &discordgo.ApplicationCommand{
Name: "unban",
Description: "Unban a player from using the bot.",
Options: personOptions,
Name: "bans",
Description: "Perform an action on a player's bans.",
Options: bansSubCommands,
},
Handler: unbanHandler,
Handler: bansHandler,
AdminOnly: true,
})
@ -125,38 +151,71 @@ func addCommands() {
{
Type: discordgo.ApplicationCommandOptionString,
Name: "profile",
Description: "common_core, athena, common_public, profile0, collections, creative",
Description: "The profile to give/take the item from.",
Required: true,
Choices: []*discordgo.ApplicationCommandOptionChoice{
{
Name: "Athena",
Value: "athena",
},
{
Name: "Common Core",
Value: "common_core",
},
{
Name: "Profile0",
Value: "profile0",
},
{
Name: "Creative",
Value: "creative",
},
{
Name: "Collections",
Value: "collections",
},
{
Name: "Common Public",
Value: "common_public",
},
},
},
}, personOptions...)
addCommand(&DiscordCommand{
Command: &discordgo.ApplicationCommand{
Name: "give",
grantSubCommands := []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionSubCommand,
Name: "add",
Description: "Grant a player an item in the game.",
Options: grantOptions,
},
Handler: giveItemHandler,
AdminOnly: true,
})
addCommand(&DiscordCommand{
Command: &discordgo.ApplicationCommand{
Name: "take",
{
Type: discordgo.ApplicationCommandOptionSubCommand,
Name: "remove",
Description: "Take an item from a player in the game.",
Options: grantOptions,
},
Handler: takeItemHandler,
AdminOnly: true,
})
{
Type: discordgo.ApplicationCommandOptionSubCommand,
Name: "fill",
Description: "Grant a player all items in the game.",
Options: personOptions,
},
{
Type: discordgo.ApplicationCommandOptionSubCommand,
Name: "clear",
Description: "Reset their locker to default.",
Options: personOptions,
},
}
addCommand(&DiscordCommand{
Command: &discordgo.ApplicationCommand{
Name: "everything",
Description: "Give a player full locker",
Options: personOptions,
Name: "items",
Description: "Perform an action on a player's items.",
Options: grantSubCommands,
},
Handler: giveEverythingHandler,
Handler: itemsHandler,
AdminOnly: true,
})
@ -215,7 +274,7 @@ func addCommands() {
{
Type: discordgo.ApplicationCommandOptionSubCommand,
Name: "remove",
Description: "Rake a permission from a player.",
Description: "Remove a permission from a player.",
Options: permissionOptions,
},
}

View File

@ -14,14 +14,7 @@ import (
func GetLightswitchBulkStatus(c *fiber.Ctx) error {
person := c.Locals("person").(*person.Person)
isBanned := false
for _, ban := range person.BanHistory {
expres := time.Unix(ban.Expiry, 0)
if time.Now().Before(expres) {
isBanned = true
break
}
}
ban := person.GetLatestActiveBan()
return c.Status(fiber.StatusOK).JSON([]aid.JSON{{
"serviceInstanceId": "fortnite",
@ -29,7 +22,7 @@ func GetLightswitchBulkStatus(c *fiber.Ctx) error {
"message": "fortnite is up.",
"maintenanceUri": nil,
"allowedActions": []string{"PLAY","DOWNLOAD"},
"banned": isBanned,
"banned": ban != nil && time.Now().Before(ban.Expiry),
"launcherInfoDTO": aid.JSON{
"appName":"Fortnite",
"namespace":"fn",

View File

@ -4,18 +4,22 @@ type Permission int64
// DO NOT MOVE THE ORDER OF THESE PERMISSIONS AS THEY ARE USED IN THE DATABASE
const (
// random utility permissions
PermissionLookup Permission = 1 << iota
PermissionBan
PermissionInformation
// control permissions
PermissionBansControl
PermissionItemControl
PermissionLockerControl
PermissionPermissionControl
// user roles, not really permissions but implemented as such
PermissionOwner
PermissionDonator
// special permissions
PermissionAll = PermissionLookup | PermissionBan | PermissionInformation | PermissionItemControl | PermissionLockerControl | PermissionPermissionControl
PermissionAll = PermissionLookup | PermissionBansControl | PermissionInformation | PermissionItemControl | PermissionLockerControl | PermissionPermissionControl
PermissionAllWithRoles = PermissionAll | PermissionOwner | PermissionDonator
)
@ -36,7 +40,7 @@ func (p Permission) GetName() string {
return "Lookup"
}
if p&PermissionBan != 0 {
if p&PermissionBansControl != 0 {
return "Ban"
}

View File

@ -20,7 +20,7 @@ type Person struct {
CollectionsProfile *Profile
CreativeProfile *Profile
Discord *storage.DB_DiscordPerson
BanHistory []storage.DB_BanStatus
BanHistory aid.GenericSyncMap[storage.DB_BanStatus]
Relationships aid.GenericSyncMap[Relationship]
}
@ -188,7 +188,7 @@ func findHelper(databasePerson *storage.DB_Person, shallow bool, save bool) *Per
ID: databasePerson.ID,
DisplayName: databasePerson.DisplayName,
Permissions: Permission(databasePerson.Permissions),
BanHistory: databasePerson.BanHistory,
BanHistory: aid.GenericSyncMap[storage.DB_BanStatus]{},
AthenaProfile: athenaProfile,
CommonCoreProfile: commonCoreProfile,
CommonPublicProfile: commonPublicProfile,
@ -200,6 +200,10 @@ func findHelper(databasePerson *storage.DB_Person, shallow bool, save bool) *Per
Relationships: aid.GenericSyncMap[Relationship]{},
}
for _, ban := range databasePerson.BanHistory {
person.BanHistory.Set(ban.ID, &ban)
}
if !shallow {
person.LoadRelationships()
}
@ -262,24 +266,53 @@ func (p *Person) SaveShallow() {
storage.Repo.SavePerson(dbPerson)
}
func (p *Person) Ban() {
p.BanHistory = append(p.BanHistory, storage.DB_BanStatus{
ID: uuid.New().String(),
PersonID: p.ID,
IssuedBy: "system",
Reason: "Banned by system",
Expiry: time.Now().AddDate(0, 0, 7).Unix(),
})
func (p *Person) AddBan(reason string, issuedBy string, expiry ...string) {
t := time.Now().AddDate(0, 0, 7)
p.SaveShallow()
}
func (p *Person) Unban() {
for _, ban := range p.BanHistory {
ban.Expiry = time.Now().Unix()
if len(expiry) > 0 && expiry[0] != "" {
parsed, err := aid.ParseDuration(expiry[0])
if err == nil {
t = time.Now().Add(parsed)
aid.Print("Parsed duration for ban expiry:", t.Format("2006-01-02T15:04:05.999Z"))
} else {
aid.Print("Failed to parse duration for ban expiry:", err)
}
}
p.SaveShallow()
ban := &storage.DB_BanStatus{
ID: uuid.New().String(),
PersonID: p.ID,
IssuedBy: issuedBy,
Reason: reason,
Expiry: t,
}
p.BanHistory.Set(ban.ID, ban)
storage.Repo.SaveBanStatus(ban)
}
func (p *Person) ClearBans() {
p.BanHistory.Range(func(key string, ban *storage.DB_BanStatus) bool {
ban.Expiry = time.Now()
storage.Repo.SaveBanStatus(ban)
return true
})
}
func (p *Person) GetLatestActiveBan() *storage.DB_BanStatus {
var latestBan *storage.DB_BanStatus
p.BanHistory.Range(func(key string, ban *storage.DB_BanStatus) bool {
if latestBan == nil || ban.Expiry.After(latestBan.Expiry) {
latestBan = ban
}
return true
})
if latestBan != nil && latestBan.Expiry.Before(time.Now()) {
return nil
}
return latestBan
}
func (p *Person) AddPermission(permission Permission) {
@ -305,7 +338,7 @@ func (p *Person) ToDatabase() *storage.DB_Person {
ID: p.ID,
DisplayName: p.DisplayName,
Permissions: int64(p.Permissions),
BanHistory: p.BanHistory,
BanHistory: []storage.DB_BanStatus{},
RefundTickets: p.RefundTickets,
Profiles: []storage.DB_Profile{},
Stats: []storage.DB_SeasonStat{},
@ -325,6 +358,11 @@ func (p *Person) ToDatabase() *storage.DB_Person {
"creative": p.CreativeProfile,
}
p.BanHistory.Range(func(key string, ban *storage.DB_BanStatus) bool {
dbPerson.BanHistory = append(dbPerson.BanHistory, *ban)
return true
})
for profileType, profile := range profilesToConvert {
dbProfile := storage.DB_Profile{
ID: profile.ID,
@ -374,7 +412,7 @@ func (p *Person) ToDatabaseShallow() *storage.DB_Person {
ID: p.ID,
DisplayName: p.DisplayName,
Permissions: int64(p.Permissions),
BanHistory: p.BanHistory,
BanHistory: []storage.DB_BanStatus{},
RefundTickets: p.RefundTickets,
Profiles: []storage.DB_Profile{},
Stats: []storage.DB_SeasonStat{},
@ -385,11 +423,16 @@ func (p *Person) ToDatabaseShallow() *storage.DB_Person {
dbPerson.Discord = *p.Discord
}
p.BanHistory.Range(func(key string, ban *storage.DB_BanStatus) bool {
dbPerson.BanHistory = append(dbPerson.BanHistory, *ban)
return true
})
return &dbPerson
}
func (p *Person) Snapshot() *PersonSnapshot {
return &PersonSnapshot{
snapshot := &PersonSnapshot{
ID: p.ID,
DisplayName: p.DisplayName,
Permissions: int64(p.Permissions),
@ -399,9 +442,16 @@ func (p *Person) Snapshot() *PersonSnapshot {
Profile0Profile: *p.Profile0Profile.Snapshot(),
CollectionsProfile: *p.CollectionsProfile.Snapshot(),
CreativeProfile: *p.CreativeProfile.Snapshot(),
BanHistory: p.BanHistory,
BanHistory: []storage.DB_BanStatus{},
Discord: *p.Discord,
}
p.BanHistory.Range(func(key string, ban *storage.DB_BanStatus) bool {
snapshot.BanHistory = append(snapshot.BanHistory, *ban)
return true
})
return snapshot
}
func (p *Person) Delete() {

View File

@ -251,3 +251,11 @@ func (s *PostgresStorage) SaveDiscordPerson(discordPerson *DB_DiscordPerson) {
func (s *PostgresStorage) DeleteDiscordPerson(discordPersonId string) {
s.Postgres.Delete(&DB_DiscordPerson{}, "id = ?", discordPersonId)
}
func (s *PostgresStorage) SaveBanStatus(banStatus *DB_BanStatus) {
s.Postgres.Save(banStatus)
}
func (s *PostgresStorage) DeleteBanStatus(banStatusId string) {
s.Postgres.Delete(&DB_BanStatus{}, "id = ?", banStatusId)
}

View File

@ -54,6 +54,9 @@ type Storage interface {
SaveDiscordPerson(person *DB_DiscordPerson)
DeleteDiscordPerson(personId string)
SaveBanStatus(ban *DB_BanStatus)
DeleteBanStatus(banId string)
}
type Repository struct {
@ -226,3 +229,11 @@ func (r *Repository) SaveDiscordPerson(person *DB_DiscordPerson) {
func (r *Repository) DeleteDiscordPerson(personId string) {
r.Storage.DeleteDiscordPerson(personId)
}
func (r *Repository) SaveBanStatus(ban *DB_BanStatus) {
r.Storage.SaveBanStatus(ban)
}
func (r *Repository) DeleteBanStatus(banId string) {
r.Storage.DeleteBanStatus(banId)
}

View File

@ -1,6 +1,10 @@
package storage
import "github.com/lib/pq"
import (
"time"
"github.com/lib/pq"
)
type Tabler interface {
TableName() string
@ -210,7 +214,7 @@ type DB_BanStatus struct {
ID string `gorm:"primary_key"`
PersonID string `gorm:"index"`
IssuedBy string
Expiry int64
Expiry time.Time
Reason string
}