github.com/Azareal/Gosora@v0.0.0-20210729070923-553e66b59003/common/promotions.go (about) 1 package common 2 3 import ( 4 "database/sql" 5 //"log" 6 "time" 7 8 qgen "github.com/Azareal/Gosora/query_gen" 9 ) 10 11 var GroupPromotions GroupPromotionStore 12 13 type GroupPromotion struct { 14 ID int 15 From int 16 To int 17 TwoWay bool 18 19 Level int 20 Posts int 21 MinTime int 22 RegisteredFor int 23 } 24 25 type GroupPromotionStore interface { 26 GetByGroup(gid int) (gps []*GroupPromotion, err error) 27 Get(id int) (*GroupPromotion, error) 28 PromoteIfEligible(u *User, level, posts int, registeredAt time.Time) error 29 Delete(id int) error 30 Create(from, to int, twoWay bool, level, posts, registeredFor int) (int, error) 31 } 32 33 type DefaultGroupPromotionStore struct { 34 getByGroup *sql.Stmt 35 get *sql.Stmt 36 delete *sql.Stmt 37 create *sql.Stmt 38 39 getByUser *sql.Stmt 40 getByUserMins *sql.Stmt 41 updateUser *sql.Stmt 42 updateGeneric *sql.Stmt 43 } 44 45 func NewDefaultGroupPromotionStore(acc *qgen.Accumulator) (*DefaultGroupPromotionStore, error) { 46 ugp := "users_groups_promotions" 47 prs := &DefaultGroupPromotionStore{ 48 getByGroup: acc.Select(ugp).Columns("pid, from_gid, to_gid, two_way, level, posts, minTime, registeredFor").Where("from_gid=? OR to_gid=?").Prepare(), 49 get: acc.Select(ugp).Columns("from_gid, to_gid, two_way, level, posts, minTime, registeredFor").Where("pid=?").Prepare(), 50 delete: acc.Delete(ugp).Where("pid=?").Prepare(), 51 create: acc.Insert(ugp).Columns("from_gid, to_gid, two_way, level, posts, minTime, registeredFor").Fields("?,?,?,?,?,?,?").Prepare(), 52 53 getByUserMins: acc.Select(ugp).Columns("pid, to_gid, two_way, level, posts, minTime, registeredFor").Where("from_gid=? AND level<=? AND posts<=? AND registeredFor<=?").Orderby("level DESC").Limit("1").Prepare(), 54 getByUser: acc.Select(ugp).Columns("pid, to_gid, two_way, level, posts, minTime, registeredFor").Where("from_gid=? AND level<=? AND posts<=?").Orderby("level DESC").Limit("1").Prepare(), 55 updateUser: acc.Update("users").Set("group=?").Where("group=? AND uid=?").Prepare(), 56 updateGeneric: acc.Update("users").Set("group=?").Where("group=? AND level>=? AND posts>=?").Prepare(), 57 } 58 Tasks.FifteenMin.Add(prs.Tick) 59 return prs, acc.FirstError() 60 } 61 62 func (s *DefaultGroupPromotionStore) Tick() error { 63 return nil 64 } 65 66 func (s *DefaultGroupPromotionStore) GetByGroup(gid int) (gps []*GroupPromotion, err error) { 67 rows, err := s.getByGroup.Query(gid, gid) 68 if err != nil { 69 return nil, err 70 } 71 defer rows.Close() 72 73 for rows.Next() { 74 g := &GroupPromotion{} 75 err := rows.Scan(&g.ID, &g.From, &g.To, &g.TwoWay, &g.Level, &g.Posts, &g.MinTime, &g.RegisteredFor) 76 if err != nil { 77 return nil, err 78 } 79 gps = append(gps, g) 80 } 81 return gps, rows.Err() 82 } 83 84 // TODO: Cache the group promotions to avoid hitting the database as much 85 func (s *DefaultGroupPromotionStore) Get(id int) (*GroupPromotion, error) { 86 /*g, err := s.cache.Get(id) 87 if err == nil { 88 return u, nil 89 }*/ 90 91 g := &GroupPromotion{ID: id} 92 err := s.get.QueryRow(id).Scan(&g.From, &g.To, &g.TwoWay, &g.Level, &g.Posts, &g.MinTime, &g.RegisteredFor) 93 if err == nil { 94 //s.cache.Set(u) 95 } 96 return g, err 97 } 98 99 // TODO: Optimise this to avoid the query 100 func (s *DefaultGroupPromotionStore) PromoteIfEligible(u *User, level, posts int, registeredAt time.Time) error { 101 mins := time.Since(registeredAt).Minutes() 102 g := &GroupPromotion{From: u.Group} 103 //log.Printf("pre getByUserMins: %+v\n", u) 104 err := s.getByUserMins.QueryRow(u.Group, level, posts, mins).Scan(&g.ID, &g.To, &g.TwoWay, &g.Level, &g.Posts, &g.MinTime, &g.RegisteredFor) 105 if err == sql.ErrNoRows { 106 //log.Print("no matches found") 107 return nil 108 } else if err != nil { 109 return err 110 } 111 //log.Printf("g: %+v\n", g) 112 if g.RegisteredFor == 0 { 113 _, err = s.updateGeneric.Exec(g.To, g.From, g.Level, g.Posts) 114 } else { 115 _, err = s.updateUser.Exec(g.To, g.From, u.ID) 116 } 117 return err 118 } 119 120 func (s *DefaultGroupPromotionStore) Delete(id int) error { 121 _, err := s.delete.Exec(id) 122 return err 123 } 124 125 func (s *DefaultGroupPromotionStore) Create(from, to int, twoWay bool, level, posts, registeredFor int) (int, error) { 126 res, err := s.create.Exec(from, to, twoWay, level, posts, 0, registeredFor) 127 if err != nil { 128 return 0, err 129 } 130 lastID, err := res.LastInsertId() 131 return int(lastID), err 132 }