From 4b8047ae34b4c38adaef03693186bd92a6eb6b7a Mon Sep 17 00:00:00 2001 From: Eccentric Date: Sun, 4 Feb 2024 15:21:16 +0000 Subject: [PATCH] Item refunding --- fortnite/person.go | 2 +- handlers/client.go | 63 +++++++++++++++++++++++- person/gift.go | 4 +- person/history.go | 117 ++++++++++++++++++++++++++++++++++++++++++++ person/item.go | 26 +++++++++- person/person.go | 36 +++++++++----- person/profile.go | 14 ++++++ person/snapshot.go | 2 +- person/sync.go | 59 +++++++++++++++++++++- storage/postgres.go | 80 +++++++++--------------------- storage/storage.go | 11 +++++ storage/tables.go | 31 ++++++------ 12 files changed, 353 insertions(+), 92 deletions(-) create mode 100644 person/history.go diff --git a/fortnite/person.go b/fortnite/person.go index 8390f34..27e8699 100644 --- a/fortnite/person.go +++ b/fortnite/person.go @@ -151,7 +151,7 @@ func NewFortnitePersonWithId(id string, displayName string, everything bool) *p. person.CommonCoreProfile.Attributes.AddAttribute(p.NewAttribute("allowed_to_send_gifts", true)).Save() person.CommonCoreProfile.Attributes.AddAttribute(p.NewAttribute("gift_history", aid.JSON{})).Save() - loadout := p.NewLoadoutWithID("sandbox_loadout", "", person.AthenaProfile) + loadout := p.NewLoadout("PRESET 1", person.AthenaProfile) person.AthenaProfile.Loadouts.AddLoadout(loadout).Save() person.AthenaProfile.Attributes.AddAttribute(p.NewAttribute("loadouts", []string{loadout.ID})).Save() person.AthenaProfile.Attributes.AddAttribute(p.NewAttribute("last_applied_loadout", loadout.ID)).Save() diff --git a/handlers/client.go b/handlers/client.go index c8bd480..cf1a05c 100644 --- a/handlers/client.go +++ b/handlers/client.go @@ -27,6 +27,7 @@ var ( "CopyCosmeticLoadout": clientCopyCosmeticLoadoutAction, "DeleteCosmeticLoadout": clientDeleteCosmeticLoadoutAction, "PurchaseCatalogEntry": clientPurchaseCatalogEntryAction, + "RefundMtxPurchase": clientRefundMtxPurchaseAction, "GiftCatalogEntry": clientGiftCatalogEntryAction, "RemoveGiftBox": clientRemoveGiftBoxAction, } @@ -449,7 +450,7 @@ func clientCopyCosmeticLoadoutAction(c *fiber.Ctx, person *p.Person, profile *p. return fmt.Errorf("source index out of range") } - sandboxLoadout := profile.Loadouts.GetLoadout("sandbox_loadout") + sandboxLoadout := profile.Loadouts.GetLoadout(loadouts[0]) if sandboxLoadout == nil { return fmt.Errorf("sandbox loadout not found") } @@ -626,6 +627,7 @@ func clientPurchaseCatalogEntryAction(c *fiber.Ctx, person *p.Person, profile *p } loot := []aid.JSON{} + purchase := p.NewPurchase(body.OfferID, body.ExpectedTotalPrice) for i := 0; i < body.PurchaseQuantity; i++ { for _, grant := range offer.Grants { if profile.Items.GetItemByTemplateID(grant) != nil { @@ -638,6 +640,7 @@ func clientPurchaseCatalogEntryAction(c *fiber.Ctx, person *p.Person, profile *p item := p.NewItem(grant, 1) person.AthenaProfile.Items.AddItem(item) + purchase.AddLoot(item) loot = append(loot, aid.JSON{ "itemType": item.TemplateID, @@ -648,6 +651,8 @@ func clientPurchaseCatalogEntryAction(c *fiber.Ctx, person *p.Person, profile *p } } + person.AthenaProfile.Purchases.AddPurchase(purchase).Save() + *notifications = append(*notifications, aid.JSON{ "type": "CatalogPurchase", "lootResult": aid.JSON{ @@ -659,6 +664,62 @@ func clientPurchaseCatalogEntryAction(c *fiber.Ctx, person *p.Person, profile *p return nil } +func clientRefundMtxPurchaseAction(c *fiber.Ctx, person *p.Person, profile *p.Profile, notifications *[]aid.JSON) error { + var body struct { + PurchaseID string `json:"purchaseId" binding:"required"` + } + + if err := c.BodyParser(&body); err != nil { + return fmt.Errorf("invalid Body") + } + + aid.Print(person.AthenaProfile.Purchases.Count()) + aid.Print(person.CommonCoreProfile.Purchases.Count()) + + person.AthenaProfile.Purchases.RangePurchases(func(key string, value *p.Purchase) bool { + aid.Print(key, value.ID) + return true + }) + + purchase := person.AthenaProfile.Purchases.GetPurchase(body.PurchaseID) + if purchase == nil { + return fmt.Errorf("purchase not found") + } + + if person.RefundTickets <= 0 { + return fmt.Errorf("not enough refund tickets") + } + + if time.Now().After(purchase.FreeRefundExpiry) { + person.RefundTickets-- + } + + for _, item := range purchase.Loot { + profile.Items.DeleteItem(item.ID) + } + + purchase.RefundedAt = time.Now() + purchase.Save() + + vbucks := profile.Items.GetItemByTemplateID("Currency:MtxPurchased") + if vbucks == nil { + return fmt.Errorf("vbucks not found") + } + + vbucks.Quantity += purchase.TotalPaid + vbucks.Save() + + profile0Vbucks := person.Profile0Profile.Items.GetItemByTemplateID("Currency:MtxPurchased") + if profile0Vbucks == nil { + return fmt.Errorf("profile0vbucks not found") + } + + profile0Vbucks.Quantity = vbucks.Quantity + profile0Vbucks.Save() + + return nil +} + func clientGiftCatalogEntryAction(c *fiber.Ctx, person *p.Person, profile *p.Profile, notifications *[]aid.JSON) error { var body struct { Currency string `json:"currency" binding:"required"` diff --git a/person/gift.go b/person/gift.go index a5ef365..5179a24 100644 --- a/person/gift.go +++ b/person/gift.go @@ -35,7 +35,7 @@ func FromDatabaseGift(gift *storage.DB_Gift) *Gift { loot := []*Item{} for _, item := range gift.Loot { - loot = append(loot, FromDatabaseLoot(&item)) + loot = append(loot, FromDatabaseGiftLoot(&item)) } return &Gift{ @@ -99,7 +99,7 @@ func (g *Gift) ToDatabase(profileId string) *storage.DB_Gift { profileLoot := []storage.DB_GiftLoot{} for _, item := range g.Loot { - profileLoot = append(profileLoot, *item.ToLootDatabase(g.ID)) + profileLoot = append(profileLoot, *item.ToGiftLootDatabase(g.ID)) } return &storage.DB_Gift{ diff --git a/person/history.go b/person/history.go new file mode 100644 index 0000000..d1b74bf --- /dev/null +++ b/person/history.go @@ -0,0 +1,117 @@ +package person + +import ( + "time" + + "github.com/ectrc/snow/aid" + "github.com/ectrc/snow/storage" + "github.com/google/uuid" +) + +type Purchase struct { + ID string + ProfileID string + PersonID string + Loot []*Item + OfferID string + PurchaseDate time.Time + FreeRefundExpiry time.Time + RefundExpiry time.Time + RefundedAt time.Time + TotalPaid int +} + +func NewPurchase(offerID string, price int) *Purchase { + return &Purchase{ + ID: uuid.New().String(), + OfferID: offerID, + PurchaseDate: time.Now(), + RefundedAt: time.Unix(0, 0), + FreeRefundExpiry: time.Now().Add(time.Hour * 24), + RefundExpiry: time.Now().Add(time.Hour * 24 * 30), + Loot: []*Item{}, + TotalPaid: price, + } +} + +func FromDatabasePurchase(purchase *storage.DB_Purchase) *Purchase { + loot := []*Item{} + + for _, item := range purchase.Loot { + loot = append(loot, FromDatabasePurchaseLoot(&item)) + } + + return &Purchase{ + ID: purchase.ID, + ProfileID: purchase.ProfileID, + Loot: loot, + OfferID: purchase.OfferID, + PurchaseDate: time.Unix(purchase.PurchaseDate, 0), + FreeRefundExpiry: time.Unix(purchase.FreeRefundExpiry, 0), + RefundExpiry: time.Unix(purchase.RefundExpiry, 0), + RefundedAt: time.Unix(purchase.RefundedAt, 0), + } +} + +func (p *Purchase) GenerateFortnitePurchaseEntry() aid.JSON { + json := aid.JSON{ + "offerId": p.OfferID, + "freeRefundEligible": time.Now().Before(p.FreeRefundExpiry), + "purchaseId": p.ID, + "purchaseDate": p.PurchaseDate.Format(time.RFC3339), + "undoTimeout": p.FreeRefundExpiry.Format(time.RFC3339), + "totalMtxPaid": p.TotalPaid, + "lootResult": []aid.JSON{}, + "gameContext": "", + "metadata": aid.JSON{}, + "fulfillments": []aid.JSON{}, + } + + for _, item := range p.Loot { + json["lootResult"] = append(json["lootResult"].([]aid.JSON), aid.JSON{ + "itemGuid": item.ID, + "itemType": item.TemplateID, + "itemProfile": item.ProfileType, + "quantity": item.Quantity, + }) + } + + if p.RefundedAt.Unix() > 0 { + json["refundDate"] = p.RefundedAt.Format(time.RFC3339) + } + + return json +} + +func (p *Purchase) AddLoot(item *Item) { + p.Loot = append(p.Loot, item) +} + +func (p *Purchase) Delete() { + storage.Repo.DeletePurchase(p.ID) +} + +func (p *Purchase) ToDatabase(profileId string) *storage.DB_Purchase { + loot := []storage.DB_PurchaseLoot{} + + for _, item := range p.Loot { + loot = append(loot, *item.ToPurchaseLootDatabase(p.ID)) + } + + return &storage.DB_Purchase{ + ID: p.ID, + ProfileID: profileId, + Loot: loot, + OfferID: p.OfferID, + PurchaseDate: p.PurchaseDate.Unix(), + FreeRefundExpiry: p.FreeRefundExpiry.Unix(), + RefundExpiry: p.RefundExpiry.Unix(), + RefundedAt: p.RefundedAt.Unix(), + TotalPaid: p.TotalPaid, + } +} + +func (p *Purchase) Save() { + storage.Repo.SavePurchase(p.ToDatabase(p.ProfileID)) + Find(p.PersonID).SetPurchaseHistoryAttribute() +} \ No newline at end of file diff --git a/person/item.go b/person/item.go index 488808d..11027ac 100644 --- a/person/item.go +++ b/person/item.go @@ -58,7 +58,19 @@ func FromDatabaseItem(item *storage.DB_Item) *Item { } } -func FromDatabaseLoot(item *storage.DB_GiftLoot) *Item { +func FromDatabaseGiftLoot(item *storage.DB_GiftLoot) *Item { + return &Item{ + ID: item.ID, + TemplateID: item.TemplateID, + Quantity: item.Quantity, + Favorite: false, + HasSeen: false, + Variants: []*VariantChannel{}, + ProfileType: item.ProfileType, + } +} + +func FromDatabasePurchaseLoot(item *storage.DB_PurchaseLoot) *Item { return &Item{ ID: item.ID, TemplateID: item.TemplateID, @@ -202,7 +214,7 @@ func (i *Item) Save() { storage.Repo.SaveItem(i.ToDatabase(i.ProfileID)) } -func (i *Item) ToLootDatabase(giftId string) *storage.DB_GiftLoot { +func (i *Item) ToGiftLootDatabase(giftId string) *storage.DB_GiftLoot { return &storage.DB_GiftLoot{ GiftID: giftId, ProfileType: i.ProfileType, @@ -212,6 +224,16 @@ func (i *Item) ToLootDatabase(giftId string) *storage.DB_GiftLoot { } } +func (i *Item) ToPurchaseLootDatabase(purchaseId string) *storage.DB_PurchaseLoot { + return &storage.DB_PurchaseLoot{ + ID: i.ID, + PurchaseID: purchaseId, + ProfileType: i.ProfileType, + TemplateID: i.TemplateID, + Quantity: i.Quantity, + } +} + func (i *Item) SaveLoot(giftId string) { //storage.Repo.SaveLoot(i.ToLootDatabase(giftId)) } diff --git a/person/person.go b/person/person.go index 5383e8a..67531c5 100644 --- a/person/person.go +++ b/person/person.go @@ -11,6 +11,7 @@ import ( type Person struct { ID string DisplayName string + RefundTickets int Permissions []string AthenaProfile *Profile CommonCoreProfile *Profile @@ -28,6 +29,7 @@ func NewPerson() *Person { ID: uuid.New().String(), DisplayName: uuid.New().String(), Permissions: []string{}, + RefundTickets: 3, AthenaProfile: NewProfile("athena"), CommonCoreProfile: NewProfile("common_core"), CommonPublicProfile: NewProfile("common_public"), @@ -42,6 +44,7 @@ func NewPersonWithCustomID(id string) *Person { ID: id, DisplayName: uuid.New().String(), Permissions: []string{}, + RefundTickets: 3, AthenaProfile: NewProfile("athena"), CommonCoreProfile: NewProfile("common_core"), CommonPublicProfile: NewProfile("common_public"), @@ -193,6 +196,7 @@ func findHelper(databasePerson *storage.DB_Person, shallow bool, save bool) *Per CollectionsProfile: collectionsProfile, CreativeProfile: creativeProfile, Discord: &databasePerson.Discord, + RefundTickets: databasePerson.RefundTickets, Relationships: aid.GenericSyncMap[Relationship]{}, } @@ -313,6 +317,7 @@ func (p *Person) ToDatabase() *storage.DB_Person { DisplayName: p.DisplayName, Permissions: p.Permissions, BanHistory: p.BanHistory, + RefundTickets: p.RefundTickets, Profiles: []storage.DB_Profile{}, Stats: []storage.DB_SeasonStat{}, Discord: storage.DB_DiscordPerson{}, @@ -381,6 +386,7 @@ func (p *Person) ToDatabaseShallow() *storage.DB_Person { DisplayName: p.DisplayName, Permissions: p.Permissions, BanHistory: p.BanHistory, + RefundTickets: p.RefundTickets, Profiles: []storage.DB_Profile{}, Stats: []storage.DB_SeasonStat{}, Discord: storage.DB_DiscordPerson{}, @@ -393,19 +399,6 @@ func (p *Person) ToDatabaseShallow() *storage.DB_Person { return &dbPerson } -func (p *Person) AddAttribute(value *Attribute) { - p.AthenaProfile.Attributes.AddAttribute(value) -} - -func (p *Person) GetAttribute(key string) *Attribute { - attribute := p.AthenaProfile.Attributes.GetAttribute(key) - return attribute -} - -func (p *Person) RemoveAttribute(key string) { - p.AthenaProfile.Attributes.DeleteAttribute(key) -} - func (p *Person) Snapshot() *PersonSnapshot { return &PersonSnapshot{ ID: p.ID, @@ -424,4 +417,21 @@ func (p *Person) Snapshot() *PersonSnapshot { func (p *Person) Delete() { storage.Repo.DeletePerson(p.ID) +} + +func (p *Person) SetPurchaseHistoryAttribute() { + purchases := []aid.JSON{} + + p.AthenaProfile.Purchases.RangePurchases(func(key string, value *Purchase) bool { + purchases = append(purchases, value.GenerateFortnitePurchaseEntry()) + return true + }) + + purchaseAttribute := p.CommonCoreProfile.Attributes.GetAttributeByKey("mtx_purchase_history") + purchaseAttribute.ValueJSON = aid.JSONStringify(aid.JSON{ + "refundsUsed": p.AthenaProfile.Purchases.CountRefunded(), + "refundCredits": p.RefundTickets, + "purchases": purchases, + }) + purchaseAttribute.Save() } \ No newline at end of file diff --git a/person/profile.go b/person/profile.go index aed3475..b2d7b82 100644 --- a/person/profile.go +++ b/person/profile.go @@ -17,6 +17,7 @@ type Profile struct { Quests *QuestMutex Attributes *AttributeMutex Loadouts *LoadoutMutex + Purchases *PurchaseMutex Type string Revision int Changes []interface{} @@ -32,6 +33,7 @@ func NewProfile(profile string) *Profile { Quests: NewQuestMutex(&storage.DB_Profile{ID: id, Type: profile}), Attributes: NewAttributeMutex(&storage.DB_Profile{ID: id, Type: profile}), Loadouts: NewLoadoutMutex(&storage.DB_Profile{ID: id, Type: profile}), + Purchases: NewPurchaseMutex(&storage.DB_Profile{ID: id, Type: profile}), Type: profile, Revision: 0, Changes: []interface{}{}, @@ -44,6 +46,7 @@ func FromDatabaseProfile(profile *storage.DB_Profile) *Profile { quests := NewQuestMutex(profile) attributes := NewAttributeMutex(profile) loadouts := NewLoadoutMutex(profile) + purchases := NewPurchaseMutex(profile) for _, item := range profile.Items { items.AddItem(FromDatabaseItem(&item)) @@ -71,6 +74,10 @@ func FromDatabaseProfile(profile *storage.DB_Profile) *Profile { attributes.AddAttribute(parsed) } + for _, purchase := range profile.Purchases { + purchases.AddPurchase(FromDatabasePurchase(&purchase)) + } + return &Profile{ ID: profile.ID, PersonID: profile.PersonID, @@ -79,6 +86,7 @@ func FromDatabaseProfile(profile *storage.DB_Profile) *Profile { Quests: quests, Attributes: attributes, Loadouts: loadouts, + Purchases: purchases, Type: profile.Type, Revision: profile.Revision, Changes: []interface{}{}, @@ -437,6 +445,7 @@ func (p *Profile) ToDatabase() *storage.DB_Profile { Gifts: []storage.DB_Gift{}, Quests: []storage.DB_Quest{}, Loadouts: []storage.DB_Loadout{}, + Purchases: []storage.DB_Purchase{}, Attributes: []storage.DB_Attribute{}, Revision: p.Revision, } @@ -466,5 +475,10 @@ func (p *Profile) ToDatabase() *storage.DB_Profile { return true }) + p.Purchases.RangePurchases(func(id string, purchase *Purchase) bool { + dbProfile.Purchases = append(dbProfile.Purchases, *purchase.ToDatabase(dbProfile.PersonID)) + return true + }) + return &dbProfile } \ No newline at end of file diff --git a/person/snapshot.go b/person/snapshot.go index 72f3ab0..434bac0 100644 --- a/person/snapshot.go +++ b/person/snapshot.go @@ -6,13 +6,13 @@ type PersonSnapshot struct { ID string DisplayName string Permissions []string - IsBanned bool AthenaProfile ProfileSnapshot CommonCoreProfile ProfileSnapshot CommonPublicProfile ProfileSnapshot Profile0Profile ProfileSnapshot CollectionsProfile ProfileSnapshot CreativeProfile ProfileSnapshot + BanHistory []storage.DB_BanStatus Discord storage.DB_DiscordPerson } diff --git a/person/sync.go b/person/sync.go index 5a16c52..b9ba971 100644 --- a/person/sync.go +++ b/person/sync.go @@ -265,7 +265,6 @@ func (m *LoadoutMutex) DeleteLoadout(id string) { return } - loadout.Delete() m.Delete(id) storage.Repo.DeleteItem(id) } @@ -307,4 +306,62 @@ func (m *LoadoutMutex) Count() int { return true }) return count +} + +type PurchaseMutex struct { + sync.Map + PersonID string + ProfileID string +} + +func NewPurchaseMutex(profile *storage.DB_Profile) *PurchaseMutex { + return &PurchaseMutex{ + PersonID: profile.PersonID, + ProfileID: profile.ID, + } +} + +func (m *PurchaseMutex) AddPurchase(purchase *Purchase) *Purchase { + purchase.ProfileID = m.ProfileID + purchase.PersonID = m.PersonID + m.Store(purchase.ID, purchase) + // storage.Repo.SavePurchase(purchase.ToDatabase(m.ProfileID)) + + // Find(m.PersonID).SetPurchaseHistoryAttribute() + return purchase +} + +func (m *PurchaseMutex) GetPurchase(id string) *Purchase { + purchase, ok := m.Load(id) + if !ok { + return nil + } + + return purchase.(*Purchase) +} + +func (m *PurchaseMutex) RangePurchases(f func(key string, value *Purchase) bool) { + m.Range(func(key, value interface{}) bool { + return f(key.(string), value.(*Purchase)) + }) +} + +func (m *PurchaseMutex) Count() int { + count := 0 + m.Range(func(key, value interface{}) bool { + count++ + return true + }) + return count +} + +func (m *PurchaseMutex) CountRefunded() int { + count := 0 + m.RangePurchases(func(key string, value *Purchase) bool { + if value.RefundedAt.Unix() > 0 { + count++ + } + return true + }) + return count } \ No newline at end of file diff --git a/storage/postgres.go b/storage/postgres.go index 04922d7..1752ca9 100644 --- a/storage/postgres.go +++ b/storage/postgres.go @@ -47,6 +47,7 @@ func (s *PostgresStorage) MigrateAll() { s.Migrate(&DB_Gift{}, "Gifts") s.Migrate(&DB_GiftLoot{}, "GiftLoot") s.Migrate(&DB_DiscordPerson{}, "Discords") + s.Migrate(&DB_BanStatus{}, "Bans") s.Migrate(&DB_SeasonStat{}, "Stats") } @@ -54,9 +55,8 @@ func (s *PostgresStorage) DropTables() { s.Postgres.Exec(`DROP SCHEMA public CASCADE; CREATE SCHEMA public; GRANT ALL ON SCHEMA public TO postgres; GRANT ALL ON SCHEMA public TO public;`) } -func (s *PostgresStorage) GetPerson(personId string) *DB_Person { - var dbPerson DB_Person - s.Postgres. +func (s *PostgresStorage) PreloadPerson() (tx *gorm.DB) { + return s.Postgres. Model(&DB_Person{}). Preload("Profiles"). Preload("Profiles.Loadouts"). @@ -66,9 +66,16 @@ func (s *PostgresStorage) GetPerson(personId string) *DB_Person { Preload("Profiles.Gifts"). Preload("Profiles.Gifts.Loot"). Preload("Profiles.Quests"). + Preload("Profiles.Purchases"). + Preload("Profiles.Purchases.Loot"). Preload("Discord"). - Where("id = ?", personId). - Find(&dbPerson) + Preload("BanHistory"). + Preload("Stats") +} + +func (s *PostgresStorage) GetPerson(personId string) *DB_Person { + var dbPerson DB_Person + s.PreloadPerson().Where("id = ?", personId).Find(&dbPerson) if dbPerson.ID == "" { return nil @@ -79,19 +86,7 @@ func (s *PostgresStorage) GetPerson(personId string) *DB_Person { func (s *PostgresStorage) GetPersonByDisplay(displayName string) *DB_Person { var dbPerson DB_Person - s.Postgres. - Model(&DB_Person{}). - Preload("Profiles"). - Preload("Profiles.Loadouts"). - Preload("Profiles.Attributes"). - Preload("Profiles.Items"). - Preload("Profiles.Items.Variants"). - Preload("Profiles.Gifts"). - Preload("Profiles.Gifts.Loot"). - Preload("Profiles.Quests"). - Preload("Discord"). - Where("display_name = ?", displayName). - Find(&dbPerson) + s.PreloadPerson().Where("display_name = ?", displayName).Find(&dbPerson) if dbPerson.ID == "" { return nil @@ -102,19 +97,7 @@ func (s *PostgresStorage) GetPersonByDisplay(displayName string) *DB_Person { func (s *PostgresStorage) GetPersonsByPartialDisplay(displayName string) []*DB_Person { var dbPersons []*DB_Person - s.Postgres. - Model(&DB_Person{}). - Preload("Profiles"). - Preload("Profiles.Loadouts"). - Preload("Profiles.Attributes"). - Preload("Profiles.Items"). - Preload("Profiles.Items.Variants"). - Preload("Profiles.Gifts"). - Preload("Profiles.Gifts.Loot"). - Preload("Profiles.Quests"). - Preload("Discord"). - Where("display_name LIKE ?", "%" + displayName + "%"). - Find(&dbPersons) + s.PreloadPerson().Where("display_name LIKE ?", "%" + displayName + "%").Find(&dbPersons) if len(dbPersons) == 0 { return nil @@ -136,19 +119,7 @@ func (s *PostgresStorage) GetPersonByDiscordID(discordId string) *DB_Person { func (s *PostgresStorage) GetAllPersons() []*DB_Person { var dbPersons []*DB_Person - - s.Postgres. - Model(&DB_Person{}). - Preload("Profiles"). - Preload("Profiles.Loadouts"). - Preload("Profiles.Attributes"). - Preload("Profiles.Items"). - Preload("Profiles.Items.Variants"). - Preload("Profiles.Gifts"). - Preload("Profiles.Gifts.Loot"). - Preload("Profiles.Quests"). - Preload("Discord"). - Find(&dbPersons) + s.PreloadPerson().Find(&dbPersons) return dbPersons } @@ -170,18 +141,7 @@ func (s *PostgresStorage) SavePerson(person *DB_Person) { } func (s *PostgresStorage) DeletePerson(personId string) { - s.Postgres. - Model(&DB_Person{}). - Preload("Profiles"). - Preload("Profiles.Loadouts"). - Preload("Profiles.Attributes"). - Preload("Profiles.Items"). - Preload("Profiles.Items.Variants"). - Preload("Profiles.Gifts"). - Preload("Profiles.Gifts.Loot"). - Preload("Profiles.Quests"). - Preload("Discord"). - Delete(&DB_Person{}, "id = ?", personId) + s.PreloadPerson().Delete(&DB_Person{}, "id = ?", personId) } func (s *PostgresStorage) GetIncomingRelationships(personId string) []*DB_Relationship { @@ -276,6 +236,14 @@ func (s *PostgresStorage) DeleteLoadout(loadoutId string) { s.Postgres.Delete(&DB_Loadout{}, "id = ?", loadoutId) } +func (s *PostgresStorage) SavePurchase(purchase *DB_Purchase) { + s.Postgres.Save(purchase) +} + +func (s *PostgresStorage) DeletePurchase(purchaseId string) { + s.Postgres.Delete(&DB_Purchase{}, "id = ?", purchaseId) +} + func (s *PostgresStorage) SaveDiscordPerson(discordPerson *DB_DiscordPerson) { s.Postgres.Save(discordPerson) } diff --git a/storage/storage.go b/storage/storage.go index 7d7f938..e9b5a07 100644 --- a/storage/storage.go +++ b/storage/storage.go @@ -49,6 +49,9 @@ type Storage interface { SaveLoadout(loadout *DB_Loadout) DeleteLoadout(loadoutId string) + SavePurchase(purchase *DB_Purchase) + DeletePurchase(purchaseId string) + SaveDiscordPerson(person *DB_DiscordPerson) DeleteDiscordPerson(personId string) } @@ -207,6 +210,14 @@ func (r *Repository) DeleteLoadout(loadoutId string) { r.Storage.DeleteLoadout(loadoutId) } +func (r *Repository) SavePurchase(purchase *DB_Purchase) { + r.Storage.SavePurchase(purchase) +} + +func (r *Repository) DeletePurchase(purchaseId string) { + r.Storage.DeletePurchase(purchaseId) +} + func (r *Repository) SaveDiscordPerson(person *DB_DiscordPerson) { r.Storage.SaveDiscordPerson(person) } diff --git a/storage/tables.go b/storage/tables.go index 1c2d9ed..e61e26e 100644 --- a/storage/tables.go +++ b/storage/tables.go @@ -9,12 +9,12 @@ type Tabler interface { type DB_Person struct { ID string DisplayName string + RefundTickets int Permissions pq.StringArray `gorm:"type:text[]"` Profiles []DB_Profile `gorm:"foreignkey:PersonID"` Stats []DB_SeasonStat `gorm:"foreignkey:PersonID"` - Purchases []DB_Purchase `gorm:"foreignkey:ProfileID"` Discord DB_DiscordPerson `gorm:"foreignkey:PersonID"` - BanHistory []DB_BanStatus `gorm:"foreignkey:PersonID"` + BanHistory []DB_BanStatus `gorm:"foreignkey:PersonID"` } func (DB_Person) TableName() string { @@ -39,6 +39,7 @@ type DB_Profile struct { Quests []DB_Quest `gorm:"foreignkey:ProfileID"` Attributes []DB_Attribute `gorm:"foreignkey:ProfileID"` Loadouts []DB_Loadout `gorm:"foreignkey:ProfileID"` + Purchases []DB_Purchase `gorm:"foreignkey:ProfileID"` Type string Revision int } @@ -95,16 +96,28 @@ func (DB_Item) TableName() string { return "Items" } +type DB_VariantChannel struct { + ID string `gorm:"primary_key"` + ItemID string `gorm:"index"` + Channel string + Owned pq.StringArray `gorm:"type:text[]"` + Active string +} + +func (DB_VariantChannel) TableName() string { + return "Variants" +} + type DB_Purchase struct { ID string `gorm:"primary_key"` ProfileID string `gorm:"index"` - Loot []DB_PurchaseLoot `gorm:"foreignkey:PurchaseID"` OfferID string PurchaseDate int64 FreeRefundExpiry int64 RefundExpiry int64 RefundedAt int64 TotalPaid int + Loot []DB_PurchaseLoot `gorm:"foreignkey:PurchaseID"` } func (DB_Purchase) TableName() string { @@ -123,18 +136,6 @@ func (DB_PurchaseLoot) TableName() string { return "PurchaseLoot" } -type DB_VariantChannel struct { - ID string `gorm:"primary_key"` - ItemID string `gorm:"index"` - Channel string - Owned pq.StringArray `gorm:"type:text[]"` - Active string -} - -func (DB_VariantChannel) TableName() string { - return "Variants" -} - type DB_Quest struct { ID string `gorm:"primary_key"` ProfileID string `gorm:"index"`