gosora/common/forum_actions.go
Azareal c60118e7c4 WIP forum action code. Currently disabled.
Add Http Conn Count tracking.
Move more panel phrases into the panel namespace.
Use a string builder in hookgen.
Use Countf() in a couple of places to eliminate boilerplate.
Reduce prepared stmt boilerplate in forum store with a lambda.
Reduce prepared stmt boilerplate in topic.go with a lambda.
Reduce prepared stmt boilerplate in group.go with a lambda.
Add TestSetCreatedAt method to *Topic.
Add DateOlderThanQ method to *accDeleteBuilder and *accUpdateBuilder.
Add Stmt method to *accUpdateBuilder and *AccSelectBuilder.
Add AccBuilder interface.
Shorten variable names.
Shorten extractPerm name to ep.
Add avatar_visibility setting stub. Implementation coming in a later commit.
Don't set an IP for installer generated posts.

Add counters_perf_tick_row hook.

Add avatar_visibility phrase.
Add avatar_visibility_label phrase.
Rename forums_no_description to forums_no_desc.
Rename panel.forums_create_description_label to panel.forums_create_desc_label.
Rename panel.forums_create_description to panel.forums_create_desc.
Rename panel_forum_description to panel.forum_desc.
Rename panel_forum_description_placeholder to panel.forum_desc_placeholder.
Add panel_debug_http_conns_label phrase.
Add panel.forum_actions_head phrase.
Add panel.forum_actions_create_head phrase.
Add panel.forum_action_run_on_topic_creation phrase.
Add panel.forum_action_run_days_after_topic_creation phrase.
Add panel.forum_action_run_days_after_topic_last_reply phrase.
Add panel.forum_action_action phrase.
Add panel.forum_action_action_delete phrase.
Add panel.forum_action_action_lock phrase.
Add panel.forum_action_action_unlock phrase.
Add panel.forum_action_action_move phrase.
Add panel.forum_action_extra phrase.
Add panel.forum_action_create_button phrase.

You will need to run the patcher / updater for this commit.
2021-04-08 00:23:11 +10:00

400 lines
11 KiB
Go

package common
import (
"database/sql"
"fmt"
"strconv"
qgen "github.com/Azareal/Gosora/query_gen"
)
var ForumActionStore ForumActionStoreInt
//var ForumActionRunnableStore ForumActionRunnableStoreInt
const (
ForumActionDelete = iota
ForumActionLock
ForumActionUnlock
ForumActionMove
)
func ConvStringToAct(s string) int {
switch s {
case "delete":
return ForumActionDelete
case "lock":
return ForumActionLock
case "unlock":
return ForumActionUnlock
case "move":
return ForumActionMove
}
return -1
}
func ConvActToString(a int) string {
switch a {
case ForumActionDelete:
return "delete"
case ForumActionLock:
return "lock"
case ForumActionUnlock:
return "unlock"
case ForumActionMove:
return "move"
}
return ""
}
var forumActionStmts ForumActionStmts
type ForumActionStmts struct {
get1 *sql.Stmt
get2 *sql.Stmt
lock1 *sql.Stmt
lock2 *sql.Stmt
unlock1 *sql.Stmt
unlock2 *sql.Stmt
}
type ForumAction struct {
ID int
Forum int
RunOnTopicCreation bool
RunDaysAfterTopicCreation int
RunDaysAfterTopicLastReply int
Action int
Extra string
}
func init() {
DbInits.Add(func(acc *qgen.Accumulator) error {
t := "topics"
forumActionStmts = ForumActionStmts{
get1: acc.Select(t).Cols("tid,createdBy,poll").Where("parentID=?").DateOlderThanQ("createdAt", "day").Stmt(),
get2: acc.Select(t).Cols("tid,createdBy,poll").Where("parentID=?").DateOlderThanQ("lastReplyAt", "day").Stmt(),
/*lock1: acc.Update(t).Set("is_closed=1").Where("parentID=?").DateOlderThanQ("createdAt", "day").Stmt(),
lock2: acc.Update(t).Set("is_closed=1").Where("parentID=?").DateOlderThanQ("lastReplyAt", "day").Stmt(),
unlock1: acc.Update(t).Set("is_closed=0").Where("parentID=?").DateOlderThanQ("createdAt", "day").Stmt(),
unlock2: acc.Update(t).Set("is_closed=0").Where("parentID=?").DateOlderThanQ("lastReplyAt", "day").Stmt(),*/
}
return acc.FirstError()
})
}
func (a *ForumAction) Run() error {
if a.RunDaysAfterTopicCreation > 0 {
if e := a.runDaysAfterTopicCreation(); e != nil {
return e
}
}
if a.RunDaysAfterTopicLastReply > 0 {
if e := a.runDaysAfterTopicLastReply(); e != nil {
return e
}
}
return nil
}
func (a *ForumAction) runQ(stmt *sql.Stmt, days int, f func(t *Topic) error) error {
rows, e := stmt.Query(days, a.Forum)
if e != nil {
return e
}
defer rows.Close()
for rows.Next() {
// TODO: Decouple this
t := &Topic{ParentID: a.Forum}
if e := rows.Scan(&t.ID, &t.CreatedBy, &t.Poll); e != nil {
return e
}
if e = f(t); e != nil {
return e
}
}
return rows.Err()
}
func (a *ForumAction) runDaysAfterTopicCreation() (e error) {
switch a.Action {
case ForumActionDelete:
// TODO: Bulk delete?
e = a.runQ(forumActionStmts.get1, a.RunDaysAfterTopicCreation, func(t *Topic) error {
return t.Delete()
})
case ForumActionLock:
/*_, e := forumActionStmts.lock1.Exec(a.Forum)
if e != nil {
return e
}*/
// TODO: Bulk lock? Lock and get resultset of changed topics somehow?
fmt.Println("ForumActionLock")
e = a.runQ(forumActionStmts.get1, a.RunDaysAfterTopicCreation, func(t *Topic) error {
fmt.Printf("t: %+v\n", t)
return t.Lock()
})
case ForumActionUnlock:
// TODO: Bulk unlock? Unlock and get resultset of changed topics somehow?
e = a.runQ(forumActionStmts.get1, a.RunDaysAfterTopicCreation, func(t *Topic) error {
return t.Unlock()
})
case ForumActionMove:
destForum, e := strconv.Atoi(a.Extra)
if e != nil {
return e
}
e = a.runQ(forumActionStmts.get1, a.RunDaysAfterTopicCreation, func(t *Topic) error {
return t.MoveTo(destForum)
})
}
return e
}
func (a *ForumAction) runDaysAfterTopicLastReply() (e error) {
switch a.Action {
case ForumActionDelete:
e = a.runQ(forumActionStmts.get2, a.RunDaysAfterTopicLastReply, func(t *Topic) error {
return t.Delete()
})
case ForumActionLock:
// TODO: Bulk lock? Lock and get resultset of changed topics somehow?
e = a.runQ(forumActionStmts.get2, a.RunDaysAfterTopicLastReply, func(t *Topic) error {
return t.Lock()
})
case ForumActionUnlock:
// TODO: Bulk unlock? Unlock and get resultset of changed topics somehow?
e = a.runQ(forumActionStmts.get2, a.RunDaysAfterTopicLastReply, func(t *Topic) error {
return t.Unlock()
})
case ForumActionMove:
destForum, e := strconv.Atoi(a.Extra)
if e != nil {
return e
}
e = a.runQ(forumActionStmts.get2, a.RunDaysAfterTopicLastReply, func(t *Topic) error {
return t.MoveTo(destForum)
})
}
return nil
}
func (a *ForumAction) TopicCreation(tid int) error {
if !a.RunOnTopicCreation {
return nil
}
return nil
}
type ForumActionStoreInt interface {
Get(faid int) (*ForumAction, error)
GetInForum(fid int) ([]*ForumAction, error)
GetAll() ([]*ForumAction, error)
GetNewTopicActions(fid int) ([]*ForumAction, error)
Add(fa *ForumAction) (int, error)
Delete(faid int) error
Exists(faid int) bool
Count() int
CountInForum(fid int) int
DailyTick() error
}
type DefaultForumActionStore struct {
get *sql.Stmt
getInForum *sql.Stmt
getAll *sql.Stmt
getNewTopicActions *sql.Stmt
add *sql.Stmt
delete *sql.Stmt
exists *sql.Stmt
count *sql.Stmt
countInForum *sql.Stmt
}
func NewDefaultForumActionStore(acc *qgen.Accumulator) (*DefaultForumActionStore, error) {
fa := "forums_actions"
allCols := "faid,fid,runOnTopicCreation,runDaysAfterTopicCreation,runDaysAfterTopicLastReply,action,extra"
return &DefaultForumActionStore{
get: acc.Select(fa).Columns("fid,runOnTopicCreation,runDaysAfterTopicCreation,runDaysAfterTopicLastReply,action,extra").Where("faid=?").Prepare(),
getInForum: acc.Select(fa).Columns("faid,runOnTopicCreation,runDaysAfterTopicCreation,runDaysAfterTopicLastReply,action,extra").Where("fid=?").Prepare(),
getAll: acc.Select(fa).Columns(allCols).Prepare(),
getNewTopicActions: acc.Select(fa).Columns(allCols).Where("fid=? AND runOnTopicCreation=1").Prepare(),
add: acc.Insert(fa).Columns("fid,runOnTopicCreation,runDaysAfterTopicCreation,runDaysAfterTopicLastReply,action,extra").Fields("?,?,?,?,?,?").Prepare(),
delete: acc.Delete(fa).Where("faid=?").Prepare(),
exists: acc.Exists(fa, "faid").Prepare(),
count: acc.Count(fa).Prepare(),
countInForum: acc.Count(fa).Where("fid=?").Prepare(),
}, acc.FirstError()
}
func (s *DefaultForumActionStore) DailyTick() error {
fas, e := s.GetAll()
if e != nil {
return e
}
for _, fa := range fas {
if e := fa.Run(); e != nil {
return e
}
}
return nil
}
func (s *DefaultForumActionStore) Get(id int) (*ForumAction, error) {
fa := ForumAction{ID: id}
var str string
e := s.get.QueryRow(id).Scan(&fa.Forum, &fa.RunOnTopicCreation, &fa.RunDaysAfterTopicCreation, &fa.RunDaysAfterTopicLastReply, &str, &fa.Extra)
fa.Action = ConvStringToAct(str)
return &fa, e
}
func (s *DefaultForumActionStore) GetInForum(fid int) (fas []*ForumAction, e error) {
rows, e := s.getInForum.Query(fid)
if e != nil {
return nil, e
}
defer rows.Close()
var str string
for rows.Next() {
fa := ForumAction{Forum: fid}
if e := rows.Scan(&fa.ID, &fa.RunOnTopicCreation, &fa.RunDaysAfterTopicCreation, &fa.RunDaysAfterTopicLastReply, &str, &fa.Extra); e != nil {
return nil, e
}
fa.Action = ConvStringToAct(str)
fas = append(fas, &fa)
}
return fas, rows.Err()
}
func (s *DefaultForumActionStore) GetAll() (fas []*ForumAction, e error) {
rows, e := s.getAll.Query()
if e != nil {
return nil, e
}
defer rows.Close()
var str string
for rows.Next() {
fa := ForumAction{}
if e := rows.Scan(&fa.ID, &fa.Forum, &fa.RunOnTopicCreation, &fa.RunDaysAfterTopicCreation, &fa.RunDaysAfterTopicLastReply, &str, &fa.Extra); e != nil {
return nil, e
}
fa.Action = ConvStringToAct(str)
fas = append(fas, &fa)
}
return fas, rows.Err()
}
func (s *DefaultForumActionStore) GetNewTopicActions(fid int) (fas []*ForumAction, e error) {
rows, e := s.getNewTopicActions.Query(fid)
if e != nil {
return nil, e
}
defer rows.Close()
var str string
for rows.Next() {
fa := ForumAction{RunOnTopicCreation: true}
if e := rows.Scan(&fa.ID, &fa.Forum, &fa.RunDaysAfterTopicCreation, &fa.RunDaysAfterTopicLastReply, &str, &fa.Extra); e != nil {
return nil, e
}
fa.Action = ConvStringToAct(str)
fas = append(fas, &fa)
}
return fas, rows.Err()
}
func (s *DefaultForumActionStore) Add(fa *ForumAction) (int, error) {
res, e := s.add.Exec(fa.Forum, fa.RunOnTopicCreation, fa.RunDaysAfterTopicCreation, fa.RunDaysAfterTopicLastReply, ConvActToString(fa.Action), fa.Extra)
if e != nil {
return 0, e
}
lastID, e := res.LastInsertId()
return int(lastID), e
}
func (s *DefaultForumActionStore) Delete(id int) error {
_, e := s.delete.Exec(id)
return e
}
func (s *DefaultForumActionStore) Exists(id int) bool {
err := s.exists.QueryRow(id).Scan(&id)
if err != nil && err != ErrNoRows {
LogError(err)
}
return err != ErrNoRows
}
func (s *DefaultForumActionStore) Count() (count int) {
err := s.count.QueryRow().Scan(&count)
if err != nil {
LogError(err)
}
return count
}
func (s *DefaultForumActionStore) CountInForum(fid int) (count int) {
return Countf(s.countInForum, fid)
}
/*type ForumActionRunnable struct {
ID int
ActionID int
TargetID int
TargetType int // 0 = topic
RunAfter int //unixtime
}
type ForumActionRunnableStoreInt interface {
GetAfterTime(unix int) ([]*ForumActionRunnable, error)
GetInForum(fid int) ([]*ForumActionRunnable, error)
Delete(faid int) error
DeleteInForum(fid int) error
DeleteByActionID(faid int) error
Count() int
CountInForum(fid int) int
}
type DefaultForumActionRunnableStore struct {
delete *sql.Stmt
deleteInForum *sql.Stmt
count *sql.Stmt
countInForum *sql.Stmt
}
func NewDefaultForumActionRunnableStore(acc *qgen.Accumulator) (*DefaultForumActionRunnableStore, error) {
fa := "forums_actions"
return &DefaultForumActionRunnableStore{
delete: acc.Delete(fa).Where("faid=?").Prepare(),
deleteInForum: acc.Delete(fa).Where("fid=?").Prepare(),
count: acc.Count(fa).Prepare(),
countInForum: acc.Count(fa).Where("faid=?").Prepare(),
}, acc.FirstError()
}
func (s *DefaultForumActionRunnableStore) Delete(id int) error {
_, e := s.delete.Exec(id)
return e
}
func (s *DefaultForumActionRunnableStore) DeleteInForum(fid int) error {
_, e := s.deleteInForum.Exec(id)
return e
}
func (s *DefaultForumActionRunnableStore) Count() (count int) {
err := s.count.QueryRow().Scan(&count)
if err != nil {
LogError(err)
}
return count
}
func (s *DefaultForumActionRunnableStore) CountInForum(fid int) (count int) {
return Countf(s.countInForum, fid)
}
*/