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  }