Add posts as a criteria for group promotions.

Load the posts column when loading users.
Make DefaultUserStore.Reload a wrapper around DefaultUserStore.BypassGet.
Use the OO style query builder more in common/user.go
GroupPromotions is now bound to an interface rather than the concrete type.
Fix some issues in the GroupPromotionStore interface.
Improve error handling for table creation and reduce boilerplate.
Shorten some more things.

Add panel_group_promotions_posts phrase.

You will need to run the patcher / updater for this commit.
This commit is contained in:
Azareal 2019-10-07 08:20:37 +10:00
parent a5f77c376b
commit 2e28ae39f3
17 changed files with 230 additions and 205 deletions

View File

@ -9,8 +9,14 @@ type tblColumn = qgen.DBTableColumn
type tC = tblColumn
type tblKey = qgen.DBTableKey
func createTables(adapter qgen.Adapter) error {
qgen.Install.CreateTable("users", mysqlPre, mysqlCol,
func createTables(adapter qgen.Adapter) (err error) {
createTable := func(table string, charset string, collation string, columns []qgen.DBTableColumn, keys []qgen.DBTableKey) {
if err != nil {
return
}
err = qgen.Install.CreateTable(table, charset, collation, columns, keys)
}
createTable("users", mysqlPre, mysqlCol,
[]tC{
tC{"uid", "int", 0, false, true, ""},
tC{"name", "varchar", 100, false, false, ""},
@ -51,7 +57,7 @@ func createTables(adapter qgen.Adapter) error {
},
)
qgen.Install.CreateTable("users_groups", mysqlPre, mysqlCol,
createTable("users_groups", mysqlPre, mysqlCol,
[]tC{
tC{"gid", "int", 0, false, true, ""},
tC{"name", "varchar", 100, false, false, ""},
@ -69,7 +75,7 @@ func createTables(adapter qgen.Adapter) error {
},
)
qgen.Install.CreateTable("users_groups_promotions", mysqlPre, mysqlCol,
createTable("users_groups_promotions", mysqlPre, mysqlCol,
[]tC{
tC{"pid", "int", 0, false, true, ""},
tC{"from_gid", "int", 0, false, false, ""},
@ -78,6 +84,7 @@ func createTables(adapter qgen.Adapter) error {
// Requirements
tC{"level", "int", 0, false, false, ""},
tC{"posts", "int", 0, false, false, "0"},
tC{"minTime", "int", 0, false, false, ""}, // How long someone needs to have been in their current group before being promoted
},
[]tblKey{
@ -85,7 +92,7 @@ func createTables(adapter qgen.Adapter) error {
},
)
qgen.Install.CreateTable("users_2fa_keys", mysqlPre, mysqlCol,
createTable("users_2fa_keys", mysqlPre, mysqlCol,
[]tC{
tC{"uid", "int", 0, false, false, ""},
tC{"secret", "varchar", 100, false, false, ""},
@ -110,7 +117,7 @@ func createTables(adapter qgen.Adapter) error {
// TODO: Add a mod-queue and other basic auto-mod features. This is needed for awaiting activation and the mod_queue penalty flag
// TODO: Add a penalty type where a user is stopped from creating plugin_guilds social groups
// TODO: Shadow bans. We will probably have a CanShadowBan permission for this, as we *really* don't want people using this lightly.
/*qgen.Install.CreateTable("users_penalties","","",
/*createTable("users_penalties","","",
[]tC{
tC{"uid","int",0,false,false,""},
tC{"element_id","int",0,false,false,""},
@ -134,7 +141,7 @@ func createTables(adapter qgen.Adapter) error {
}, nil,
)*/
qgen.Install.CreateTable("users_groups_scheduler", "", "",
createTable("users_groups_scheduler", "", "",
[]tC{
tC{"uid", "int", 0, false, false, ""},
tC{"set_group", "int", 0, false, false, ""},
@ -150,7 +157,7 @@ func createTables(adapter qgen.Adapter) error {
)
// TODO: Can we use a piece of software dedicated to persistent queues for this rather than relying on the database for it?
qgen.Install.CreateTable("users_avatar_queue", "", "",
createTable("users_avatar_queue", "", "",
[]tC{
tC{"uid", "int", 0, false, false, ""}, // TODO: Make this a foreign key
},
@ -160,7 +167,7 @@ func createTables(adapter qgen.Adapter) error {
)
// TODO: Should we add a users prefix to this table to fit the "unofficial convention"?
qgen.Install.CreateTable("emails", "", "",
createTable("emails", "", "",
[]tC{
tC{"email", "varchar", 200, false, false, ""},
tC{"uid", "int", 0, false, false, ""}, // TODO: Make this a foreign key
@ -171,7 +178,7 @@ func createTables(adapter qgen.Adapter) error {
// TODO: Allow for patterns in domains, if the bots try to shake things up there?
/*
qgen.Install.CreateTable("email_domain_blacklist", "", "",
createTable("email_domain_blacklist", "", "",
[]tC{
tC{"domain", "varchar", 200, false, false, ""},
tC{"gtld", "boolean", 0, false, false, "0"},
@ -183,7 +190,7 @@ func createTables(adapter qgen.Adapter) error {
*/
// TODO: Implement password resets
qgen.Install.CreateTable("password_resets", "", "",
createTable("password_resets", "", "",
[]tC{
tC{"email", "varchar", 200, false, false, ""},
tC{"uid", "int", 0, false, false, ""}, // TODO: Make this a foreign key
@ -193,7 +200,7 @@ func createTables(adapter qgen.Adapter) error {
}, nil,
)
qgen.Install.CreateTable("forums", mysqlPre, mysqlCol,
createTable("forums", mysqlPre, mysqlCol,
[]tC{
tC{"fid", "int", 0, false, true, ""},
tC{"name", "varchar", 100, false, false, ""},
@ -213,7 +220,7 @@ func createTables(adapter qgen.Adapter) error {
},
)
qgen.Install.CreateTable("forums_permissions", "", "",
createTable("forums_permissions", "", "",
[]tC{
tC{"fid", "int", 0, false, false, ""},
tC{"gid", "int", 0, false, false, ""},
@ -226,7 +233,7 @@ func createTables(adapter qgen.Adapter) error {
},
)
qgen.Install.CreateTable("topics", mysqlPre, mysqlCol,
createTable("topics", mysqlPre, mysqlCol,
[]tC{
tC{"tid", "int", 0, false, true, ""},
tC{"title", "varchar", 100, false, false, ""}, // TODO: Increase the max length to 200?
@ -263,7 +270,7 @@ func createTables(adapter qgen.Adapter) error {
},
)
qgen.Install.CreateTable("replies", mysqlPre, mysqlCol,
createTable("replies", mysqlPre, mysqlCol,
[]tC{
tC{"rid", "int", 0, false, true, ""}, // TODO: Rename to replyID?
tC{"tid", "int", 0, false, false, ""}, // TODO: Rename to topicID?
@ -287,7 +294,7 @@ func createTables(adapter qgen.Adapter) error {
},
)
qgen.Install.CreateTable("attachments", mysqlPre, mysqlCol,
createTable("attachments", mysqlPre, mysqlCol,
[]tC{
tC{"attachID", "int", 0, false, true, ""},
tC{"sectionID", "int", 0, false, false, "0"},
@ -303,7 +310,7 @@ func createTables(adapter qgen.Adapter) error {
},
)
qgen.Install.CreateTable("revisions", mysqlPre, mysqlCol,
createTable("revisions", mysqlPre, mysqlCol,
[]tC{
tC{"reviseID", "int", 0, false, true, ""},
tC{"content", "text", 0, false, false, ""},
@ -317,7 +324,7 @@ func createTables(adapter qgen.Adapter) error {
},
)
qgen.Install.CreateTable("polls", mysqlPre, mysqlCol,
createTable("polls", mysqlPre, mysqlCol,
[]tC{
tC{"pollID", "int", 0, false, true, ""},
tC{"parentID", "int", 0, false, false, "0"},
@ -331,7 +338,7 @@ func createTables(adapter qgen.Adapter) error {
},
)
qgen.Install.CreateTable("polls_options", "", "",
createTable("polls_options", "", "",
[]tC{
tC{"pollID", "int", 0, false, false, ""},
tC{"option", "int", 0, false, false, "0"},
@ -339,7 +346,7 @@ func createTables(adapter qgen.Adapter) error {
}, nil,
)
qgen.Install.CreateTable("polls_votes", mysqlPre, mysqlCol,
createTable("polls_votes", mysqlPre, mysqlCol,
[]tC{
tC{"pollID", "int", 0, false, false, ""},
tC{"uid", "int", 0, false, false, ""}, // TODO: Make this a foreign key
@ -349,7 +356,7 @@ func createTables(adapter qgen.Adapter) error {
}, nil,
)
qgen.Install.CreateTable("users_replies", mysqlPre, mysqlCol,
createTable("users_replies", mysqlPre, mysqlCol,
[]tC{
tC{"rid", "int", 0, false, true, ""},
tC{"uid", "int", 0, false, false, ""}, // TODO: Make this a foreign key
@ -366,7 +373,7 @@ func createTables(adapter qgen.Adapter) error {
},
)
qgen.Install.CreateTable("likes", "", "",
createTable("likes", "", "",
[]tC{
tC{"weight", "tinyint", 0, false, false, "1"},
tC{"targetItem", "int", 0, false, false, ""},
@ -378,7 +385,7 @@ func createTables(adapter qgen.Adapter) error {
)
//columns("participants, createdBy, createdAt, lastReplyBy, lastReplyAt").Where("cid = ?")
qgen.Install.CreateTable("conversations", "", "",
createTable("conversations", "", "",
[]tC{
tC{"cid", "int", 0, false, true, ""},
tC{"createdBy", "int", 0, false, false, ""}, // TODO: Make this a foreign key
@ -391,7 +398,7 @@ func createTables(adapter qgen.Adapter) error {
},
)
qgen.Install.CreateTable("conversations_posts", "", "",
createTable("conversations_posts", "", "",
[]tC{
tC{"pid", "int", 0, false, true, ""},
tC{"cid", "int", 0, false, false, ""},
@ -404,14 +411,14 @@ func createTables(adapter qgen.Adapter) error {
},
)
qgen.Install.CreateTable("conversations_participants", "", "",
createTable("conversations_participants", "", "",
[]tC{
tC{"uid", "int", 0, false, false, ""},
tC{"cid", "int", 0, false, false, ""},
}, nil,
)
qgen.Install.CreateTable("activity_stream_matches", "", "",
createTable("activity_stream_matches", "", "",
[]tC{
tC{"watcher", "int", 0, false, false, ""}, // TODO: Make this a foreign key
tC{"asid", "int", 0, false, false, ""}, // TODO: Make this a foreign key
@ -421,7 +428,7 @@ func createTables(adapter qgen.Adapter) error {
},
)
qgen.Install.CreateTable("activity_stream", "", "",
createTable("activity_stream", "", "",
[]tC{
tC{"asid", "int", 0, false, true, ""},
tC{"actor", "int", 0, false, false, ""}, /* the one doing the act */ // TODO: Make this a foreign key
@ -436,7 +443,7 @@ func createTables(adapter qgen.Adapter) error {
},
)
qgen.Install.CreateTable("activity_subscriptions", "", "",
createTable("activity_subscriptions", "", "",
[]tC{
tC{"user", "int", 0, false, false, ""}, // TODO: Make this a foreign key
tC{"targetID", "int", 0, false, false, ""}, /* the ID of the element being acted upon */
@ -446,7 +453,7 @@ func createTables(adapter qgen.Adapter) error {
)
/* Due to MySQL's design, we have to drop the unique keys for table settings, plugins, and themes down from 200 to 180 or it will error */
qgen.Install.CreateTable("settings", "", "",
createTable("settings", "", "",
[]tC{
tC{"name", "varchar", 180, false, false, ""},
tC{"content", "varchar", 250, false, false, ""},
@ -458,7 +465,7 @@ func createTables(adapter qgen.Adapter) error {
},
)
qgen.Install.CreateTable("word_filters", "", "",
createTable("word_filters", "", "",
[]tC{
tC{"wfid", "int", 0, false, true, ""},
tC{"find", "varchar", 200, false, false, ""},
@ -469,7 +476,7 @@ func createTables(adapter qgen.Adapter) error {
},
)
qgen.Install.CreateTable("plugins", "", "",
createTable("plugins", "", "",
[]tC{
tC{"uname", "varchar", 180, false, false, ""},
tC{"active", "boolean", 0, false, false, "0"},
@ -480,7 +487,7 @@ func createTables(adapter qgen.Adapter) error {
},
)
qgen.Install.CreateTable("themes", "", "",
createTable("themes", "", "",
[]tC{
tC{"uname", "varchar", 180, false, false, ""},
tC{"default", "boolean", 0, false, false, "0"},
@ -491,7 +498,7 @@ func createTables(adapter qgen.Adapter) error {
},
)
qgen.Install.CreateTable("widgets", "", "",
createTable("widgets", "", "",
[]tC{
tC{"wid", "int", 0, false, true, ""},
tC{"position", "int", 0, false, false, ""},
@ -506,7 +513,7 @@ func createTables(adapter qgen.Adapter) error {
},
)
qgen.Install.CreateTable("menus", "", "",
createTable("menus", "", "",
[]tC{
tC{"mid", "int", 0, false, true, ""},
},
@ -515,7 +522,7 @@ func createTables(adapter qgen.Adapter) error {
},
)
qgen.Install.CreateTable("menu_items", "", "",
createTable("menu_items", "", "",
[]tC{
tC{"miid", "int", 0, false, true, ""},
tC{"mid", "int", 0, false, false, ""},
@ -539,7 +546,7 @@ func createTables(adapter qgen.Adapter) error {
},
)
qgen.Install.CreateTable("pages", mysqlPre, mysqlCol,
createTable("pages", mysqlPre, mysqlCol,
[]tC{
tC{"pid", "int", 0, false, true, ""},
//tC{"path", "varchar", 200, false, false, ""},
@ -555,7 +562,7 @@ func createTables(adapter qgen.Adapter) error {
},
)
qgen.Install.CreateTable("registration_logs", "", "",
createTable("registration_logs", "", "",
[]tC{
tC{"rlid", "int", 0, false, true, ""},
tC{"username", "varchar", 100, false, false, ""},
@ -570,7 +577,7 @@ func createTables(adapter qgen.Adapter) error {
},
)
qgen.Install.CreateTable("login_logs", "", "",
createTable("login_logs", "", "",
[]tC{
tC{"lid", "int", 0, false, true, ""},
tC{"uid", "int", 0, false, false, ""},
@ -583,7 +590,7 @@ func createTables(adapter qgen.Adapter) error {
},
)
qgen.Install.CreateTable("moderation_logs", "", "",
createTable("moderation_logs", "", "",
[]tC{
tC{"action", "varchar", 100, false, false, ""},
tC{"elementID", "int", 0, false, false, ""},
@ -594,7 +601,7 @@ func createTables(adapter qgen.Adapter) error {
}, nil,
)
qgen.Install.CreateTable("administration_logs", "", "",
createTable("administration_logs", "", "",
[]tC{
tC{"action", "varchar", 100, false, false, ""},
tC{"elementID", "int", 0, false, false, ""},
@ -605,7 +612,7 @@ func createTables(adapter qgen.Adapter) error {
}, nil,
)
qgen.Install.CreateTable("viewchunks", "", "",
createTable("viewchunks", "", "",
[]tC{
tC{"count", "int", 0, false, false, "0"},
tC{"createdAt", "datetime", 0, false, false, ""},
@ -613,7 +620,7 @@ func createTables(adapter qgen.Adapter) error {
}, nil,
)
qgen.Install.CreateTable("viewchunks_agents", "", "",
createTable("viewchunks_agents", "", "",
[]tC{
tC{"count", "int", 0, false, false, "0"},
tC{"createdAt", "datetime", 0, false, false, ""},
@ -622,7 +629,7 @@ func createTables(adapter qgen.Adapter) error {
}, nil,
)
qgen.Install.CreateTable("viewchunks_systems", "", "",
createTable("viewchunks_systems", "", "",
[]tC{
tC{"count", "int", 0, false, false, "0"},
tC{"createdAt", "datetime", 0, false, false, ""},
@ -630,7 +637,7 @@ func createTables(adapter qgen.Adapter) error {
}, nil,
)
qgen.Install.CreateTable("viewchunks_langs", "", "",
createTable("viewchunks_langs", "", "",
[]tC{
tC{"count", "int", 0, false, false, "0"},
tC{"createdAt", "datetime", 0, false, false, ""},
@ -638,7 +645,7 @@ func createTables(adapter qgen.Adapter) error {
}, nil,
)
qgen.Install.CreateTable("viewchunks_referrers", "", "",
createTable("viewchunks_referrers", "", "",
[]tC{
tC{"count", "int", 0, false, false, "0"},
tC{"createdAt", "datetime", 0, false, false, ""},
@ -646,7 +653,7 @@ func createTables(adapter qgen.Adapter) error {
}, nil,
)
qgen.Install.CreateTable("viewchunks_forums", "", "",
createTable("viewchunks_forums", "", "",
[]tC{
tC{"count", "int", 0, false, false, "0"},
tC{"createdAt", "datetime", 0, false, false, ""},
@ -654,7 +661,7 @@ func createTables(adapter qgen.Adapter) error {
}, nil,
)
qgen.Install.CreateTable("topicchunks", "", "",
createTable("topicchunks", "", "",
[]tC{
tC{"count", "int", 0, false, false, "0"},
tC{"createdAt", "datetime", 0, false, false, ""},
@ -662,7 +669,7 @@ func createTables(adapter qgen.Adapter) error {
}, nil,
)
qgen.Install.CreateTable("postchunks", "", "",
createTable("postchunks", "", "",
[]tC{
tC{"count", "int", 0, false, false, "0"},
tC{"createdAt", "datetime", 0, false, false, ""},
@ -670,7 +677,7 @@ func createTables(adapter qgen.Adapter) error {
}, nil,
)
qgen.Install.CreateTable("memchunks", "", "",
createTable("memchunks", "", "",
[]tC{
tC{"count", "int", 0, false, false, "0"},
tC{"stack", "int", 0, false, false, "0"},
@ -679,24 +686,24 @@ func createTables(adapter qgen.Adapter) error {
}, nil,
)
qgen.Install.CreateTable("sync", "", "",
createTable("sync", "", "",
[]tC{
tC{"last_update", "datetime", 0, false, false, ""},
}, nil,
)
qgen.Install.CreateTable("updates", "", "",
createTable("updates", "", "",
[]tC{
tC{"dbVersion", "int", 0, false, false, "0"},
}, nil,
)
qgen.Install.CreateTable("meta", "", "",
createTable("meta", "", "",
[]tC{
tC{"name", "varchar", 200, false, false, ""},
tC{"value", "varchar", 200, false, false, ""},
}, nil,
)
return nil
return err
}

View File

@ -6,7 +6,7 @@ import (
qgen "github.com/Azareal/Gosora/query_gen"
)
var GroupPromotions *DefaultGroupPromotionStore
var GroupPromotions GroupPromotionStore
type GroupPromotion struct {
ID int
@ -15,15 +15,16 @@ type GroupPromotion struct {
TwoWay bool
Level int
Posts int
MinTime int
}
type GroupPromotionStore interface {
GetByGroup() ([]*GroupPromotion, error)
GetByGroup(gid int) (gps []*GroupPromotion, err error)
Get(id int) (*GroupPromotion, error)
PromoteIfEligible(u *User, level int) error
PromoteIfEligible(u *User, level int, posts int) error
Delete(id int) error
Create(from int, to int, twoWay bool, level int) (int, error)
Create(from int, to int, twoWay bool, level int, posts int) (int, error)
}
type DefaultGroupPromotionStore struct {
@ -39,13 +40,13 @@ type DefaultGroupPromotionStore struct {
func NewDefaultGroupPromotionStore(acc *qgen.Accumulator) (*DefaultGroupPromotionStore, error) {
ugp := "users_groups_promotions"
return &DefaultGroupPromotionStore{
getByGroup: acc.Select(ugp).Columns("pid, from_gid, to_gid, two_way, level, minTime").Where("from_gid=? OR to_gid=?").Prepare(),
get: acc.Select(ugp).Columns("from_gid, to_gid, two_way, level, minTime").Where("pid = ?").Prepare(),
getByGroup: acc.Select(ugp).Columns("pid, from_gid, to_gid, two_way, level, posts, minTime").Where("from_gid=? OR to_gid=?").Prepare(),
get: acc.Select(ugp).Columns("from_gid, to_gid, two_way, level, posts, minTime").Where("pid = ?").Prepare(),
delete: acc.Delete(ugp).Where("pid = ?").Prepare(),
create: acc.Insert(ugp).Columns("from_gid, to_gid, two_way, level, minTime").Fields("?,?,?,?,?").Prepare(),
create: acc.Insert(ugp).Columns("from_gid, to_gid, two_way, level, posts, minTime").Fields("?,?,?,?,?,?").Prepare(),
getByUser: acc.Select(ugp).Columns("pid, to_gid, two_way, level, minTime").Where("from_gid=? AND level>=?").Orderby("level DESC").Limit("1").Prepare(),
updateUser: acc.Update("users").Set("group = ?").Where("level >= ?").Prepare(),
getByUser: acc.Select(ugp).Columns("pid, to_gid, two_way, level, posts, minTime").Where("from_gid=? AND level>=? AND posts>=?").Orderby("level DESC").Limit("1").Prepare(),
updateUser: acc.Update("users").Set("group = ?").Where("level >= ? AND posts >= ?").Prepare(),
}, acc.FirstError()
}
@ -58,7 +59,7 @@ func (s *DefaultGroupPromotionStore) GetByGroup(gid int) (gps []*GroupPromotion,
for rows.Next() {
g := &GroupPromotion{}
err := rows.Scan(&g.ID, &g.From, &g.To, &g.TwoWay, &g.Level, &g.MinTime)
err := rows.Scan(&g.ID, &g.From, &g.To, &g.TwoWay, &g.Level, &g.Posts, &g.MinTime)
if err != nil {
return nil, err
}
@ -75,22 +76,22 @@ func (s *DefaultGroupPromotionStore) Get(id int) (*GroupPromotion, error) {
}*/
g := &GroupPromotion{ID: id}
err := s.get.QueryRow(id).Scan(&g.From, &g.To, &g.TwoWay, &g.Level, &g.MinTime)
err := s.get.QueryRow(id).Scan(&g.From, &g.To, &g.TwoWay, &g.Level, &g.Posts, &g.MinTime)
if err == nil {
//s.cache.Set(u)
}
return g, err
}
func (s *DefaultGroupPromotionStore) PromoteIfEligible(u *User, level int) error {
func (s *DefaultGroupPromotionStore) PromoteIfEligible(u *User, level int, posts int) error {
g := &GroupPromotion{From: u.Group}
err := s.getByUser.QueryRow(u.Group, level).Scan(&g.ID, &g.To, &g.TwoWay, &g.Level, &g.MinTime)
err := s.getByUser.QueryRow(u.Group, level, posts).Scan(&g.ID, &g.To, &g.TwoWay, &g.Level, &g.Posts, &g.MinTime)
if err == sql.ErrNoRows {
return nil
} else if err != nil {
return err
}
_, err = s.updateUser.Exec(g.To, g.Level)
_, err = s.updateUser.Exec(g.To, g.Level, g.Posts)
return err
}
@ -99,8 +100,8 @@ func (s *DefaultGroupPromotionStore) Delete(id int) error {
return err
}
func (s *DefaultGroupPromotionStore) Create(from int, to int, twoWay bool, level int) (int, error) {
res, err := s.create.Exec(from, to, twoWay, level, 0)
func (s *DefaultGroupPromotionStore) Create(from int, to int, twoWay bool, level int, posts int) (int, error) {
res, err := s.create.Exec(from, to, twoWay, level, posts, 0)
if err != nil {
return 0, err
}

View File

@ -113,7 +113,7 @@ func (r *Reply) Like(uid int) (err error) {
if err != nil {
return err
}
_, err = userStmts.incrementLiked.Exec(1, uid)
_, err = userStmts.incLiked.Exec(1, uid)
_ = Rstore.GetCache().Remove(r.ID)
return err
}

View File

@ -91,14 +91,14 @@ var Template_account_handle = genIntTmpl("account")
func tmplInitUsers() (User, User, User) {
avatar, microAvatar := BuildAvatar(62, "")
user := User{62, BuildProfileURL("fake-user", 62), "Fake User", "compiler@localhost", 0, false, false, false, false, false, false, GuestPerms, make(map[string]bool), "", false, "", avatar, microAvatar, "", "", "", "", 0, 0, 0, "0.0.0.0.0", "", 0}
user := User{62, BuildProfileURL("fake-user", 62), "Fake User", "compiler@localhost", 0, false, false, false, false, false, false, GuestPerms, make(map[string]bool), "", false, "", avatar, microAvatar, "", "", "", "", 0, 0, 0, 0,"0.0.0.0.0", "", 0}
// TODO: Do a more accurate level calculation for this?
avatar, microAvatar = BuildAvatar(1, "")
user2 := User{1, BuildProfileURL("admin-alice", 1), "Admin Alice", "alice@localhost", 1, true, true, true, true, false, false, AllPerms, make(map[string]bool), "", true, "", avatar, microAvatar, "", "", "", "", 58, 1000, 0, "127.0.0.1", "", 0}
user2 := User{1, BuildProfileURL("admin-alice", 1), "Admin Alice", "alice@localhost", 1, true, true, true, true, false, false, AllPerms, make(map[string]bool), "", true, "", avatar, microAvatar, "", "", "", "", 58, 1000, 0, 1000, "127.0.0.1", "", 0}
avatar, microAvatar = BuildAvatar(2, "")
user3 := User{2, BuildProfileURL("admin-fred", 62), "Admin Fred", "fred@localhost", 1, true, true, true, true, false, false, AllPerms, make(map[string]bool), "", true, "", avatar, microAvatar, "", "", "", "", 42, 900, 0, "::1", "", 0}
user3 := User{2, BuildProfileURL("admin-fred", 62), "Admin Fred", "fred@localhost", 1, true, true, true, true, false, false, AllPerms, make(map[string]bool), "", true, "", avatar, microAvatar, "", "", "", "", 42, 900, 0, 900, "::1", "", 0}
return user, user2, user3
}

View File

@ -318,7 +318,7 @@ func (t *Topic) Like(score int, uid int) (err error) {
if err != nil {
return err
}
_, err = userStmts.incrementLiked.Exec(1, uid)
_, err = userStmts.incLiked.Exec(1, uid)
t.cacheRemove()
return err
}

View File

@ -13,7 +13,7 @@ import (
"strings"
"time"
"github.com/Azareal/Gosora/query_gen"
qgen "github.com/Azareal/Gosora/query_gen"
"github.com/go-sql-driver/mysql"
)
@ -51,6 +51,7 @@ type User struct {
Tag string
Level int
Score int
Posts int
Liked int
LastIP string // ! This part of the UserCache data might fall out of date
LastAgent string // ! Temporary hack, don't use
@ -119,18 +120,18 @@ type UserStmts struct {
delete *sql.Stmt
setAvatar *sql.Stmt
setUsername *sql.Stmt
incrementTopics *sql.Stmt
incTopics *sql.Stmt
updateLevel *sql.Stmt
update *sql.Stmt
// TODO: Split these into a sub-struct
incrementScore *sql.Stmt
incrementPosts *sql.Stmt
incrementBigposts *sql.Stmt
incrementMegaposts *sql.Stmt
incrementLiked *sql.Stmt
incScore *sql.Stmt
incPosts *sql.Stmt
incBigposts *sql.Stmt
incMegaposts *sql.Stmt
incLiked *sql.Stmt
decrementLiked *sql.Stmt
decLiked *sql.Stmt
updateLastIP *sql.Stmt
setPassword *sql.Stmt
@ -142,23 +143,23 @@ var userStmts UserStmts
func init() {
DbInits.Add(func(acc *qgen.Accumulator) error {
var w = "uid = ?"
w := "uid = ?"
userStmts = UserStmts{
activate: acc.SimpleUpdate("users", "active = 1", w),
changeGroup: acc.SimpleUpdate("users", "group = ?", w), // TODO: Implement user_count for users_groups here
delete: acc.SimpleDelete("users", w),
setAvatar: acc.Update("users").Set("avatar = ?").Where(w).Prepare(),
setUsername: acc.Update("users").Set("name = ?").Where(w).Prepare(),
incrementTopics: acc.SimpleUpdate("users", "topics = topics + ?", w),
incTopics: acc.SimpleUpdate("users", "topics = topics + ?", w),
updateLevel: acc.SimpleUpdate("users", "level = ?", w),
update: acc.Update("users").Set("name = ?, email = ?, group = ?").Where(w).Prepare(), // TODO: Implement user_count for users_groups on things which use this
incrementScore: acc.SimpleUpdate("users", "score = score + ?", w),
incrementPosts: acc.SimpleUpdate("users", "posts = posts + ?", w),
incrementBigposts: acc.SimpleUpdate("users", "posts = posts + ?, bigposts = bigposts + ?", w),
incrementMegaposts: acc.SimpleUpdate("users", "posts = posts + ?, bigposts = bigposts + ?, megaposts = megaposts + ?", w),
incrementLiked: acc.SimpleUpdate("users", "liked = liked + ?, lastLiked = UTC_TIMESTAMP()", w),
decrementLiked: acc.SimpleUpdate("users", "liked = liked - ?", w),
incScore: acc.Update("users").Set("score = score + ?").Where(w).Prepare(),
incPosts: acc.Update("users").Set("posts = posts + ?").Where(w).Prepare(),
incBigposts: acc.Update("users").Set("posts = posts + ?, bigposts = bigposts + ?").Where(w).Prepare(),
incMegaposts: acc.Update("users").Set("posts = posts + ?, bigposts = bigposts + ?, megaposts = megaposts + ?").Where(w).Prepare(),
incLiked: acc.Update("users").Set("liked = liked + ?, lastLiked = UTC_TIMESTAMP()").Where(w).Prepare(),
decLiked: acc.Update("users").Set("liked = liked - ?").Where(w).Prepare(),
//recalcLastLiked: acc...
updateLastIP: acc.SimpleUpdate("users", "last_ip = ?", w),
@ -342,15 +343,15 @@ func (u *User) UpdateIP(host string) error {
return err
}
func (u *User) Update(newname string, newemail string, newgroup int) (err error) {
return u.bindStmt(userStmts.update, newname, newemail, newgroup)
func (u *User) Update(name string, email string, group int) (err error) {
return u.bindStmt(userStmts.update, name, email, group)
}
func (u *User) IncreasePostStats(wcount int, topic bool) (err error) {
var mod int
baseScore := 1
if topic {
_, err = userStmts.incrementTopics.Exec(1, u.ID)
_, err = userStmts.incTopics.Exec(1, u.ID)
if err != nil {
return err
}
@ -359,19 +360,19 @@ func (u *User) IncreasePostStats(wcount int, topic bool) (err error) {
settings := SettingBox.Load().(SettingMap)
if wcount >= settings["megapost_min_words"].(int) {
_, err = userStmts.incrementMegaposts.Exec(1, 1, 1, u.ID)
_, err = userStmts.incMegaposts.Exec(1, 1, 1, u.ID)
mod = 4
} else if wcount >= settings["bigpost_min_words"].(int) {
_, err = userStmts.incrementBigposts.Exec(1, 1, u.ID)
_, err = userStmts.incBigposts.Exec(1, 1, u.ID)
mod = 1
} else {
_, err = userStmts.incrementPosts.Exec(1, u.ID)
_, err = userStmts.incPosts.Exec(1, u.ID)
}
if err != nil {
return err
}
_, err = userStmts.incrementScore.Exec(baseScore+mod, u.ID)
_, err = userStmts.incScore.Exec(baseScore+mod, u.ID)
if err != nil {
return err
}
@ -383,7 +384,7 @@ func (u *User) IncreasePostStats(wcount int, topic bool) (err error) {
if err != nil {
return err
}
err = GroupPromotions.PromoteIfEligible(u,level)
err = GroupPromotions.PromoteIfEligible(u, level, u.Posts+1)
u.CacheRemove()
return err
}
@ -392,7 +393,7 @@ func (u *User) DecreasePostStats(wcount int, topic bool) (err error) {
var mod int
baseScore := -1
if topic {
_, err = userStmts.incrementTopics.Exec(-1, u.ID)
_, err = userStmts.incTopics.Exec(-1, u.ID)
if err != nil {
return err
}
@ -401,19 +402,19 @@ func (u *User) DecreasePostStats(wcount int, topic bool) (err error) {
settings := SettingBox.Load().(SettingMap)
if wcount >= settings["megapost_min_words"].(int) {
_, err = userStmts.incrementMegaposts.Exec(-1, -1, -1, u.ID)
_, err = userStmts.incMegaposts.Exec(-1, -1, -1, u.ID)
mod = 4
} else if wcount >= settings["bigpost_min_words"].(int) {
_, err = userStmts.incrementBigposts.Exec(-1, -1, u.ID)
_, err = userStmts.incBigposts.Exec(-1, -1, u.ID)
mod = 1
} else {
_, err = userStmts.incrementPosts.Exec(-1, u.ID)
_, err = userStmts.incPosts.Exec(-1, u.ID)
}
if err != nil {
return err
}
_, err = userStmts.incrementScore.Exec(baseScore-mod, u.ID)
_, err = userStmts.incScore.Exec(baseScore-mod, u.ID)
if err != nil {
return err
}

View File

@ -53,9 +53,9 @@ func NewDefaultUserStore(cache UserCache) (*DefaultUserStore, error) {
// TODO: Add an admin version of registerStmt with more flexibility?
return &DefaultUserStore{
cache: cache,
get: acc.SimpleSelect("users", "name, group, active, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, liked, last_ip, temp_group", "uid = ?", "", ""),
getByName: acc.Select("users").Columns("uid, name, group, active, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, liked, last_ip, temp_group").Where("name = ?").Prepare(),
getOffset: acc.Select("users").Columns("uid, name, group, active, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, liked, last_ip, temp_group").Orderby("uid ASC").Limit("?,?").Prepare(),
get: acc.SimpleSelect("users", "name, group, active, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, posts, liked, last_ip, temp_group", "uid = ?", "", ""),
getByName: acc.Select("users").Columns("uid, name, group, active, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, posts, liked, last_ip, temp_group").Where("name = ?").Prepare(),
getOffset: acc.Select("users").Columns("uid, name, group, active, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, posts, liked, last_ip, temp_group").Orderby("uid ASC").Limit("?,?").Prepare(),
exists: acc.SimpleSelect("users", "uid", "uid = ?", "", ""),
register: acc.Insert("users").Columns("name, email, password, salt, group, is_super_admin, session, active, message, createdAt, lastActiveAt, lastLiked, oldestItemLikedCreatedAt").Fields("?,?,?,?,?,0,'',?,'',UTC_TIMESTAMP(),UTC_TIMESTAMP(),UTC_TIMESTAMP(),UTC_TIMESTAMP()").Prepare(), // TODO: Implement user_count on users_groups here
usernameExists: acc.SimpleSelect("users", "name", "name = ?", "", ""),
@ -86,7 +86,7 @@ func (s *DefaultUserStore) Get(id int) (*User, error) {
//log.Print("uncached user")
u = &User{ID: id, Loggedin: true}
err = s.get.QueryRow(id).Scan(&u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.URLPrefix, &u.URLName, &u.Level, &u.Score,&u.Liked, &u.LastIP, &u.TempGroup)
err = s.get.QueryRow(id).Scan(&u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.URLPrefix, &u.URLName, &u.Level, &u.Score, &u.Posts,&u.Liked, &u.LastIP, &u.TempGroup)
if err == nil {
u.Init()
s.cache.Set(u)
@ -98,7 +98,7 @@ func (s *DefaultUserStore) Get(id int) (*User, error) {
// ! This bypasses the cache, use frugally
func (s *DefaultUserStore) GetByName(name string) (*User, error) {
u := &User{Loggedin: true}
err := s.getByName.QueryRow(name).Scan(&u.ID, &u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.URLPrefix, &u.URLName, &u.Level, &u.Score, &u.Liked, &u.LastIP, &u.TempGroup)
err := s.getByName.QueryRow(name).Scan(&u.ID, &u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.URLPrefix, &u.URLName, &u.Level, &u.Score, &u.Posts,&u.Liked, &u.LastIP, &u.TempGroup)
if err == nil {
u.Init()
s.cache.Set(u)
@ -117,7 +117,7 @@ func (s *DefaultUserStore) GetOffset(offset int, perPage int) (users []*User, er
for rows.Next() {
u := &User{Loggedin: true}
err := rows.Scan(&u.ID, &u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.URLPrefix, &u.URLName, &u.Level, &u.Score, &u.Liked, &u.LastIP, &u.TempGroup)
err := rows.Scan(&u.ID, &u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.URLPrefix, &u.URLName, &u.Level, &u.Score, &u.Posts, &u.Liked, &u.LastIP, &u.TempGroup)
if err != nil {
return nil, err
}
@ -171,7 +171,7 @@ func (s *DefaultUserStore) BulkGetMap(ids []int) (list map[int]*User, err error)
}
q = q[0 : len(q)-1]
rows, err := qgen.NewAcc().Select("users").Columns("uid,name,group,active,is_super_admin,session,email,avatar,message,url_prefix,url_name,level,score,liked,last_ip,temp_group").Where("uid IN(" + q + ")").Query(idList...)
rows, err := qgen.NewAcc().Select("users").Columns("uid,name,group,active,is_super_admin,session,email,avatar,message,url_prefix,url_name,level,score,posts,liked,last_ip,temp_group").Where("uid IN(" + q + ")").Query(idList...)
if err != nil {
return list, err
}
@ -179,7 +179,7 @@ func (s *DefaultUserStore) BulkGetMap(ids []int) (list map[int]*User, err error)
for rows.Next() {
u := &User{Loggedin: true}
err := rows.Scan(&u.ID, &u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.URLPrefix, &u.URLName, &u.Level, &u.Score, &u.Liked, &u.LastIP, &u.TempGroup)
err := rows.Scan(&u.ID, &u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.URLPrefix, &u.URLName, &u.Level, &u.Score, &u.Posts, &u.Liked, &u.LastIP, &u.TempGroup)
if err != nil {
return list, err
}
@ -212,19 +212,19 @@ func (s *DefaultUserStore) BulkGetMap(ids []int) (list map[int]*User, err error)
func (s *DefaultUserStore) BypassGet(id int) (*User, error) {
u := &User{ID: id, Loggedin: true}
err := s.get.QueryRow(id).Scan(&u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.URLPrefix, &u.URLName, &u.Level, &u.Score, &u.Liked, &u.LastIP, &u.TempGroup)
err := s.get.QueryRow(id).Scan(&u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.URLPrefix, &u.URLName, &u.Level, &u.Score, &u.Posts, &u.Liked, &u.LastIP, &u.TempGroup)
if err == nil {
u.Init()
}
return u, err
}
func (s *DefaultUserStore) Reload(id int) error {
u := &User{ID: id, Loggedin: true}
err := s.get.QueryRow(id).Scan(&u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.URLPrefix, &u.URLName, &u.Level, &u.Score, &u.Liked, &u.LastIP, &u.TempGroup)
u, err := s.BypassGet(id)
if err != nil {
s.cache.Remove(id)
return err
}
u.Init()
_ = s.cache.Set(u)
TopicListThaw.Thaw()
return nil

View File

@ -106,8 +106,7 @@ func gloinit() (err error) {
}
func init() {
err := gloinit()
if err != nil {
if err := gloinit(); err != nil {
log.Print("Something bad happened")
//debug.PrintStack()
log.Fatalf("%+v\n", err)

View File

@ -889,6 +889,7 @@
"panel_group_promotions_to":"To",
"panel_group_promotions_two_way":"Two Way",
"panel_group_promotions_level":"Level",
"panel_group_promotions_posts":"Posts",
"panel_group_promotions_create_button":"Add Promotion",
"panel_word_filters_head":"Word Filters",

View File

@ -38,6 +38,7 @@ func init() {
addPatch(22, patch22)
addPatch(23, patch23)
addPatch(24, patch24)
addPatch(25, patch25)
}
func patch0(scanner *bufio.Scanner) (err error) {
@ -735,3 +736,7 @@ func patch24(scanner *bufio.Scanner) error {
},
))
}
func patch25(scanner *bufio.Scanner) error {
return execStmt(qgen.Builder.AddColumn("users_groups_promotions", tC{"posts", "int", 0, false, false, "0"}, nil))
}

View File

@ -30,81 +30,81 @@ type installer struct {
plugins []QueryPlugin
}
func (install *installer) SetAdapter(name string) error {
func (ins *installer) SetAdapter(name string) error {
adap, err := GetAdapter(name)
if err != nil {
return err
}
install.SetAdapterInstance(adap)
ins.SetAdapterInstance(adap)
return nil
}
func (install *installer) SetAdapterInstance(adapter Adapter) {
install.adapter = adapter
install.instructions = []DBInstallInstruction{}
func (ins *installer) SetAdapterInstance(adapter Adapter) {
ins.adapter = adapter
ins.instructions = []DBInstallInstruction{}
}
func (install *installer) AddPlugins(plugins ...QueryPlugin) {
install.plugins = append(install.plugins, plugins...)
func (ins *installer) AddPlugins(plugins ...QueryPlugin) {
ins.plugins = append(ins.plugins, plugins...)
}
func (install *installer) CreateTable(table string, charset string, collation string, columns []DBTableColumn, keys []DBTableKey) error {
func (ins *installer) CreateTable(table string, charset string, collation string, columns []DBTableColumn, keys []DBTableKey) error {
tableStruct := &DBInstallTable{table, charset, collation, columns, keys}
err := install.RunHook("CreateTableStart", tableStruct)
err := ins.RunHook("CreateTableStart", tableStruct)
if err != nil {
return err
}
res, err := install.adapter.CreateTable("", table, charset, collation, columns, keys)
res, err := ins.adapter.CreateTable("", table, charset, collation, columns, keys)
if err != nil {
return err
}
err = install.RunHook("CreateTableAfter", tableStruct)
err = ins.RunHook("CreateTableAfter", tableStruct)
if err != nil {
return err
}
install.instructions = append(install.instructions, DBInstallInstruction{table, res, "create-table"})
install.tables = append(install.tables, tableStruct)
ins.instructions = append(ins.instructions, DBInstallInstruction{table, res, "create-table"})
ins.tables = append(ins.tables, tableStruct)
return nil
}
// TODO: Let plugins manipulate the parameters like in CreateTable
func (install *installer) AddIndex(table string, iname string, colname string) error {
err := install.RunHook("AddIndexStart", table, iname, colname)
func (ins *installer) AddIndex(table string, iname string, colname string) error {
err := ins.RunHook("AddIndexStart", table, iname, colname)
if err != nil {
return err
}
res, err := install.adapter.AddIndex("", table, iname, colname)
res, err := ins.adapter.AddIndex("", table, iname, colname)
if err != nil {
return err
}
err = install.RunHook("AddIndexAfter", table, iname, colname)
err = ins.RunHook("AddIndexAfter", table, iname, colname)
if err != nil {
return err
}
install.instructions = append(install.instructions, DBInstallInstruction{table, res, "index"})
ins.instructions = append(ins.instructions, DBInstallInstruction{table, res, "index"})
return nil
}
// TODO: Let plugins manipulate the parameters like in CreateTable
func (install *installer) SimpleInsert(table string, columns string, fields string) error {
err := install.RunHook("SimpleInsertStart", table, columns, fields)
func (ins *installer) SimpleInsert(table string, columns string, fields string) error {
err := ins.RunHook("SimpleInsertStart", table, columns, fields)
if err != nil {
return err
}
res, err := install.adapter.SimpleInsert("", table, columns, fields)
res, err := ins.adapter.SimpleInsert("", table, columns, fields)
if err != nil {
return err
}
err = install.RunHook("SimpleInsertAfter", table, columns, fields, res)
err = ins.RunHook("SimpleInsertAfter", table, columns, fields, res)
if err != nil {
return err
}
install.instructions = append(install.instructions, DBInstallInstruction{table, res, "insert"})
ins.instructions = append(ins.instructions, DBInstallInstruction{table, res, "insert"})
return nil
}
func (install *installer) RunHook(name string, args ...interface{}) error {
for _, plugin := range install.plugins {
func (ins *installer) RunHook(name string, args ...interface{}) error {
for _, plugin := range ins.plugins {
err := plugin.Hook(name, args...)
if err != nil {
return err
@ -113,12 +113,12 @@ func (install *installer) RunHook(name string, args ...interface{}) error {
return nil
}
func (install *installer) Write() error {
func (ins *installer) Write() error {
var inserts string
// We can't escape backticks, so we have to dump it out a file at a time
for _, instr := range install.instructions {
for _, instr := range ins.instructions {
if instr.Type == "create-table" {
err := writeFile("./schema/"+install.adapter.GetName()+"/query_"+instr.Table+".sql", instr.Contents)
err := writeFile("./schema/"+ins.adapter.GetName()+"/query_"+instr.Table+".sql", instr.Contents)
if err != nil {
return err
}
@ -127,12 +127,12 @@ func (install *installer) Write() error {
}
}
err := writeFile("./schema/"+install.adapter.GetName()+"/inserts.sql", inserts)
err := writeFile("./schema/"+ins.adapter.GetName()+"/inserts.sql", inserts)
if err != nil {
return err
}
for _, plugin := range install.plugins {
for _, plugin := range ins.plugins {
err := plugin.Write()
if err != nil {
return err

View File

@ -137,7 +137,7 @@ func ForumsOrderSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.Ro
if ferr != nil {
return ferr
}
js := (r.PostFormValue("js") == "1")
js := r.PostFormValue("js") == "1"
if !user.Perms.ManageForums {
return c.NoPermissionsJSQ(w, r, user, js)
}
@ -218,7 +218,7 @@ func ForumsEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, sfid
if !user.Perms.ManageForums {
return c.NoPermissions(w, r, user)
}
js := (r.PostFormValue("js") == "1")
js := r.PostFormValue("js") == "1"
fid, err := strconv.Atoi(sfid)
if err != nil {
@ -260,7 +260,7 @@ func ForumsEditPermsSubmit(w http.ResponseWriter, r *http.Request, user c.User,
if !user.Perms.ManageForums {
return c.NoPermissions(w, r, user)
}
js := (r.PostFormValue("js") == "1")
js := r.PostFormValue("js") == "1"
fid, err := strconv.Atoi(sfid)
if err != nil {

View File

@ -208,6 +208,10 @@ func GroupsPromotionsCreateSubmit(w http.ResponseWriter, r *http.Request, user c
if err != nil {
return c.LocalError("level must be integer", w, r, user)
}
posts, err := strconv.Atoi(r.FormValue("posts"))
if err != nil {
return c.LocalError("posts must be integer", w, r, user)
}
g, err := c.Groups.Get(from)
ferr := groupCheck(w, r, user, g, err)
@ -219,7 +223,7 @@ func GroupsPromotionsCreateSubmit(w http.ResponseWriter, r *http.Request, user c
if err != nil {
return ferr
}
_, err = c.GroupPromotions.Create(from, to, twoWay, level)
_, err = c.GroupPromotions.Create(from, to, twoWay, level, posts)
if err != nil {
return c.InternalError(err, w, r)
}
@ -300,50 +304,50 @@ func GroupsEditPerms(w http.ResponseWriter, r *http.Request, user c.User, sgid s
// TODO: Load the phrases in bulk for efficiency?
var localPerms []c.NameLangToggle
addLocalPerm := func(permStr string, perm bool) {
addPerm := func(permStr string, perm bool) {
localPerms = append(localPerms, c.NameLangToggle{permStr, p.GetPermPhrase(permStr), perm})
}
addLocalPerm("ViewTopic", g.Perms.ViewTopic)
addLocalPerm("LikeItem", g.Perms.LikeItem)
addLocalPerm("CreateTopic", g.Perms.CreateTopic)
addPerm("ViewTopic", g.Perms.ViewTopic)
addPerm("LikeItem", g.Perms.LikeItem)
addPerm("CreateTopic", g.Perms.CreateTopic)
//<--
addLocalPerm("EditTopic", g.Perms.EditTopic)
addLocalPerm("DeleteTopic", g.Perms.DeleteTopic)
addLocalPerm("CreateReply", g.Perms.CreateReply)
addLocalPerm("EditReply", g.Perms.EditReply)
addLocalPerm("DeleteReply", g.Perms.DeleteReply)
addLocalPerm("PinTopic", g.Perms.PinTopic)
addLocalPerm("CloseTopic", g.Perms.CloseTopic)
addLocalPerm("MoveTopic", g.Perms.MoveTopic)
addPerm("EditTopic", g.Perms.EditTopic)
addPerm("DeleteTopic", g.Perms.DeleteTopic)
addPerm("CreateReply", g.Perms.CreateReply)
addPerm("EditReply", g.Perms.EditReply)
addPerm("DeleteReply", g.Perms.DeleteReply)
addPerm("PinTopic", g.Perms.PinTopic)
addPerm("CloseTopic", g.Perms.CloseTopic)
addPerm("MoveTopic", g.Perms.MoveTopic)
var globalPerms []c.NameLangToggle
addGlobalPerm := func(permStr string, perm bool) {
addPerm = func(permStr string, perm bool) {
globalPerms = append(globalPerms, c.NameLangToggle{permStr, p.GetPermPhrase(permStr), perm})
}
addGlobalPerm("BanUsers", g.Perms.BanUsers)
addGlobalPerm("ActivateUsers", g.Perms.ActivateUsers)
addGlobalPerm("EditUser", g.Perms.EditUser)
addGlobalPerm("EditUserEmail", g.Perms.EditUserEmail)
addGlobalPerm("EditUserPassword", g.Perms.EditUserPassword)
addGlobalPerm("EditUserGroup", g.Perms.EditUserGroup)
addGlobalPerm("EditUserGroupSuperMod", g.Perms.EditUserGroupSuperMod)
addGlobalPerm("EditUserGroupAdmin", g.Perms.EditUserGroupAdmin)
addGlobalPerm("EditGroup", g.Perms.EditGroup)
addGlobalPerm("EditGroupLocalPerms", g.Perms.EditGroupLocalPerms)
addGlobalPerm("EditGroupGlobalPerms", g.Perms.EditGroupGlobalPerms)
addGlobalPerm("EditGroupSuperMod", g.Perms.EditGroupSuperMod)
addGlobalPerm("EditGroupAdmin", g.Perms.EditGroupAdmin)
addGlobalPerm("ManageForums", g.Perms.ManageForums)
addGlobalPerm("EditSettings", g.Perms.EditSettings)
addGlobalPerm("ManageThemes", g.Perms.ManageThemes)
addGlobalPerm("ManagePlugins", g.Perms.ManagePlugins)
addGlobalPerm("ViewAdminLogs", g.Perms.ViewAdminLogs)
addGlobalPerm("ViewIPs", g.Perms.ViewIPs)
addGlobalPerm("UploadFiles", g.Perms.UploadFiles)
addGlobalPerm("UploadAvatars", g.Perms.UploadAvatars)
addGlobalPerm("UseConvos", g.Perms.UseConvos)
addPerm("BanUsers", g.Perms.BanUsers)
addPerm("ActivateUsers", g.Perms.ActivateUsers)
addPerm("EditUser", g.Perms.EditUser)
addPerm("EditUserEmail", g.Perms.EditUserEmail)
addPerm("EditUserPassword", g.Perms.EditUserPassword)
addPerm("EditUserGroup", g.Perms.EditUserGroup)
addPerm("EditUserGroupSuperMod", g.Perms.EditUserGroupSuperMod)
addPerm("EditUserGroupAdmin", g.Perms.EditUserGroupAdmin)
addPerm("EditGroup", g.Perms.EditGroup)
addPerm("EditGroupLocalPerms", g.Perms.EditGroupLocalPerms)
addPerm("EditGroupGlobalPerms", g.Perms.EditGroupGlobalPerms)
addPerm("EditGroupSuperMod", g.Perms.EditGroupSuperMod)
addPerm("EditGroupAdmin", g.Perms.EditGroupAdmin)
addPerm("ManageForums", g.Perms.ManageForums)
addPerm("EditSettings", g.Perms.EditSettings)
addPerm("ManageThemes", g.Perms.ManageThemes)
addPerm("ManagePlugins", g.Perms.ManagePlugins)
addPerm("ViewAdminLogs", g.Perms.ViewAdminLogs)
addPerm("ViewIPs", g.Perms.ViewIPs)
addPerm("UploadFiles", g.Perms.UploadFiles)
addPerm("UploadAvatars", g.Perms.UploadAvatars)
addPerm("UseConvos", g.Perms.UseConvos)
pi := c.PanelEditGroupPermsPage{basePage, g.ID, g.Name, localPerms, globalPerms}
return renderTemplate("panel_group_edit_perms", w, r, basePage.Header, pi)

View File

@ -4,6 +4,7 @@ CREATE TABLE [users_groups_promotions] (
[to_gid] int not null,
[two_way] bit DEFAULT 0 not null,
[level] int not null,
[posts] int DEFAULT 0 not null,
[minTime] int not null,
primary key([pid])
);

View File

@ -4,6 +4,7 @@ CREATE TABLE `users_groups_promotions` (
`to_gid` int not null,
`two_way` boolean DEFAULT 0 not null,
`level` int not null,
`posts` int DEFAULT 0 not null,
`minTime` int not null,
primary key(`pid`)
) CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;

View File

@ -4,6 +4,7 @@ CREATE TABLE "users_groups_promotions" (
`to_gid` int not null,
`two_way` boolean DEFAULT 0 not null,
`level` int not null,
`posts` int DEFAULT 0 not null,
`minTime` int not null,
primary key(`pid`)
);

View File

@ -57,6 +57,10 @@
<div class="formitem formlabel"><a>{{lang "panel_group_promotions_level"}}</a></div>
<div class="formitem"><input name="level" type="number" value=0 /></div>
</div>
<div class="formrow">
<div class="formitem formlabel"><a>{{lang "panel_group_promotions_posts"}}</a></div>
<div class="formitem"><input name="posts" type="number" value=0 /></div>
</div>
<div class="formrow form_button_row">
<div class="formitem"><button name="panel-button" class="formbutton">{{lang "panel_group_promotions_create_button"}}</button></div>
</div>