Added support for offsets and max counts to the query generator.

Early draft of the ForumStore. Not much to see here yet!

Fixed a race condition in forum creation.
Fixed a race condition in group creation.
Fixed a race condition in forum deletion.
Moved four queries to the query generator.
Renamed StaticTopicStore to MemoryTopicStore.
Renamed StaticUserStore to MemoryUserStore.
SimpleSessionCheck is now pluggable.

We no longer have any raw queries outside mysql.go or the query generator, yay.
This commit is contained in:
Azareal 2017-06-15 12:40:35 +01:00
parent 8c1d8d5c64
commit 1ccd4479ae
17 changed files with 261 additions and 158 deletions

View File

@ -3,6 +3,11 @@ package main
import "log"
import "fmt"
import "encoding/json"
import "database/sql"
var db *sql.DB
var db_version string
var db_collation string = "utf8mb4_general_ci"
func init_database() (err error) {
// Engine specific code
@ -66,6 +71,7 @@ func init_database() (err error) {
if err != nil {
return err
}
fstore = NewStaticForumStore()
log.Print("Loading the settings.")
err = LoadSettings()

View File

@ -41,16 +41,6 @@ type ForumSimple struct
Preset string
}
/*type ForumStore interface
{
Get(int) (*Forum, error)
CascadeGet(int) (*Forum, error)
Update(Forum) error
CascadeUpdate(Forum) error
Delete(int) error
CascadeDelete(int) error
}*/
func LoadForums() error {
//if debug {
log.Print("Adding the uncategorised forum")
@ -95,6 +85,7 @@ func LoadForums() error {
}
var forum_update_mutex sync.Mutex
var forum_create_mutex sync.Mutex
func create_forum(forum_name string, forum_desc string, active bool, preset string) (int, error) {
var fid int
err := forum_entry_exists_stmt.QueryRow().Scan(&fid)
@ -115,6 +106,7 @@ func create_forum(forum_name string, forum_desc string, active bool, preset stri
return fid, nil
}
forum_create_mutex.Lock()
res, err := create_forum_stmt.Exec(forum_name, forum_desc, active, preset)
if err != nil {
return 0, err
@ -127,15 +119,18 @@ func create_forum(forum_name string, forum_desc string, active bool, preset stri
fid = int(fid64)
forums = append(forums, Forum{fid,forum_name,forum_desc,active,preset,0,"",0,"",0,""})
forum_create_mutex.Unlock()
return fid, nil
}
func delete_forum(fid int) error {
forum_update_mutex.Lock()
_, err := delete_forum_stmt.Exec(fid)
if err != nil {
return err
}
forums[fid].Name = ""
forum_update_mutex.Unlock()
return nil
}

70
forum_store.go Normal file
View File

@ -0,0 +1,70 @@
/* Work in progress. Check back later! */
package main
import "log"
import "errors"
import "database/sql"
import "./query_gen/lib"
var err_noforum = errors.New("This forum doesn't exist")
type ForumStore interface
{
Get(int) (*Forum, error)
CascadeGet(int) (*Forum, error)
BypassGet(int) (*Forum, error)
//Update(Forum) error
//CascadeUpdate(Forum) error
//Delete(int) error
//CascadeDelete(int) error
//QuickCreate(string, string, bool, string) (*Forum, error)
Exists(int) bool
}
type StaticForumStore struct
{
get *sql.Stmt
get_all *sql.Stmt
}
func NewStaticForumStore() *StaticForumStore {
get_stmt, err := qgen.Builder.SimpleSelect("forums","name, desc, active, preset, topicCount, lastTopic, lastTopicID, lastReplyer, lastReplyerID, lastTopicTime","fid = ?","","")
if err != nil {
log.Fatal(err)
}
get_all_stmt, err := qgen.Builder.SimpleSelect("forums","fid, name, desc, active, preset, topicCount, lastTopic, lastTopicID, lastReplyer, lastReplyerID, lastTopicTime","","fid ASC","")
if err != nil {
log.Fatal(err)
}
return &StaticForumStore{
get: get_stmt,
get_all: get_all_stmt,
}
}
func (sfs *StaticForumStore) Get(id int) (*Forum, error) {
if !((id <= forumCapCount) && (id >= 0) && forums[id].Name!="") {
return nil, err_noforum
}
return &forums[id], nil
}
func (sfs *StaticForumStore) CascadeGet(id int) (*Forum, error) {
if !((id <= forumCapCount) && (id >= 0) && forums[id].Name!="") {
return nil, err_noforum
}
return &forums[id], nil
}
func (sfs *StaticForumStore) BypassGet(id int) (*Forum, error) {
var forum Forum = Forum{ID:id}
err := sfs.get.QueryRow(id).Scan(&forum.Name, &forum.Desc, &forum.Active, &forum.Preset, &forum.TopicCount, &forum.LastTopic, &forum.LastTopicID, &forum.LastReplyer, &forum.LastReplyerID, &forum.LastTopicTime)
if err != nil {
return nil, err
}
return &forum, nil
}
func (sfs *StaticForumStore) Exists(id int) bool {
return (id <= forumCapCount) && (id >= 0) && forums[id].Name != ""
}

View File

@ -37,6 +37,10 @@ var get_user_group_stmt *sql.Stmt
var get_emails_by_user_stmt *sql.Stmt
var get_topic_basic_stmt *sql.Stmt
var get_activity_entry_stmt *sql.Stmt
var forum_entry_exists_stmt *sql.Stmt
var group_entry_exists_stmt *sql.Stmt
var get_topic_replies_offset_stmt *sql.Stmt
var get_forum_topics_offset_stmt *sql.Stmt
var get_topic_list_stmt *sql.Stmt
var get_topic_user_stmt *sql.Stmt
var get_topic_by_reply_stmt *sql.Stmt
@ -297,6 +301,30 @@ func gen_mysql() (err error) {
return err
}
log.Print("Preparing forum_entry_exists statement.")
forum_entry_exists_stmt, err = db.Prepare("SELECT `fid` FROM `forums` WHERE `name` = '' ORDER BY fid ASC LIMIT 0,1")
if err != nil {
return err
}
log.Print("Preparing group_entry_exists statement.")
group_entry_exists_stmt, err = db.Prepare("SELECT `gid` FROM `users_groups` WHERE `name` = '' ORDER BY gid ASC LIMIT 0,1")
if err != nil {
return err
}
log.Print("Preparing get_topic_replies_offset statement.")
get_topic_replies_offset_stmt, err = db.Prepare("SELECT `replies`.`rid`,`replies`.`content`,`replies`.`createdBy`,`replies`.`createdAt`,`replies`.`lastEdit`,`replies`.`lastEditBy`,`users`.`avatar`,`users`.`name`,`users`.`group`,`users`.`url_prefix`,`users`.`url_name`,`users`.`level`,`replies`.`ipaddress`,`replies`.`likeCount`,`replies`.`actionType` FROM `replies` LEFT JOIN `users` ON `replies`.`createdBy` = `users`.`uid` WHERE `tid` = ? LIMIT ?,?")
if err != nil {
return err
}
log.Print("Preparing get_forum_topics_offset statement.")
get_forum_topics_offset_stmt, err = db.Prepare("SELECT `topics`.`tid`,`topics`.`title`,`topics`.`content`,`topics`.`createdBy`,`topics`.`is_closed`,`topics`.`sticky`,`topics`.`createdAt`,`topics`.`lastReplyAt`,`topics`.`parentID`,`topics`.`postCount`,`topics`.`likeCount`,`users`.`name`,`users`.`avatar` FROM `topics` LEFT JOIN `users` ON `topics`.`createdBy` = `users`.`uid` WHERE `topics`.`parentID` = ? ORDER BY topics.sticky DESC,topics.lastReplyAt DESC,topics.createdBy DESC LIMIT ?,?")
if err != nil {
return err
}
log.Print("Preparing get_topic_list statement.")
get_topic_list_stmt, err = db.Prepare("SELECT `topics`.`tid`,`topics`.`title`,`topics`.`content`,`topics`.`createdBy`,`topics`.`is_closed`,`topics`.`sticky`,`topics`.`createdAt`,`topics`.`parentID`,`users`.`name`,`users`.`avatar` FROM `topics` LEFT JOIN `users` ON `topics`.`createdBy` = `users`.`uid` ORDER BY topics.sticky DESC,topics.lastReplyAt DESC,topics.createdBy DESC")
if err != nil {

View File

@ -55,8 +55,8 @@ func gloinit() {
}
if cache_topicuser == CACHE_STATIC {
users = NewStaticUserStore(user_cache_capacity)
topics = NewStaticTopicStore(topic_cache_capacity)
users = NewMemoryUserStore(user_cache_capacity)
topics = NewMemoryTopicStore(topic_cache_capacity)
} else {
users = NewSqlUserStore()
topics = NewSqlTopicStore()

View File

@ -31,6 +31,7 @@ type Group struct
CanSee []int // The IDs of the forums this group can see
}
var group_create_mutex sync.Mutex
func create_group(group_name string, tag string, is_admin bool, is_mod bool, is_banned bool) (int, error) {
var gid int
err := group_entry_exists_stmt.QueryRow().Scan(&gid)
@ -47,23 +48,24 @@ func create_group(group_name string, tag string, is_admin bool, is_mod bool, is_
if err != nil {
return gid, err
}
groups[gid].Name = group_name
groups[gid].Tag = tag
groups[gid].Is_Banned = is_banned
groups[gid].Is_Mod = is_mod
groups[gid].Is_Admin = is_admin
group_update_mutex.Unlock()
return gid, nil
}
group_create_mutex.Lock()
var permstr string = "{}"
res, err := create_group_stmt.Exec(group_name, tag, is_admin, is_mod, is_banned, permstr)
if err != nil {
return 0, err
}
gid64, err := res.LastInsertId()
if err != nil {
return 0, err
@ -73,7 +75,8 @@ func create_group(group_name string, tag string, is_admin bool, is_mod bool, is_
var blankForums []ForumPerms
var blankIntList []int
groups = append(groups, Group{gid,group_name,is_mod,is_admin,is_banned,tag,perms,[]byte(permstr),blankForums,blankIntList})
group_create_mutex.Unlock()
// Generate the forum permissions based on the presets...
fdata := forums
permupdate_mutex.Lock()
@ -88,7 +91,7 @@ func create_group(group_name string, tag string, is_admin bool, is_mod bool, is_
} else {
thePreset = "members"
}
permmap := preset_to_permmap(forum.Preset)
permitem := permmap[thePreset]
permitem.Overrides = true
@ -101,7 +104,7 @@ func create_group(group_name string, tag string, is_admin bool, is_mod bool, is_
if err != nil {
return gid, err
}
err = rebuild_forum_permissions(forum.ID)
if err != nil {
return gid, err

View File

@ -43,6 +43,7 @@ var external_sites map[string]string = make(map[string]string)
var groups []Group
var forums []Forum // The IDs for a forum tend to be low and sequential for the most part, so we can get more performance out of using a slice instead of a map AND it has better concurrency
var forum_perms map[int]map[int]ForumPerms // [gid][fid]Perms
var fstore ForumStore // :soon:
var groupCapCount, forumCapCount int
var static_files map[string]SFile = make(map[string]SFile)
@ -185,8 +186,8 @@ func main(){
}
if cache_topicuser == CACHE_STATIC {
users = NewStaticUserStore(user_cache_capacity)
topics = NewStaticTopicStore(topic_cache_capacity)
users = NewMemoryUserStore(user_cache_capacity)
topics = NewMemoryTopicStore(topic_cache_capacity)
} else {
users = NewSqlUserStore()
topics = NewSqlTopicStore()

View File

@ -3,23 +3,14 @@
package main
import "log"
import "strconv"
import "strings"
import "database/sql"
import _ "github.com/go-sql-driver/mysql"
import "./query_gen/lib"
var db *sql.DB
var db_version string
var db_collation string = "utf8mb4_general_ci"
var get_topic_replies_offset_stmt *sql.Stmt // I'll need to rewrite this one to stop it hard-coding the per page setting before moving it to the query generator
var get_forum_topics_offset_stmt *sql.Stmt
var notify_watchers_stmt *sql.Stmt
var get_activity_feed_by_watcher_stmt *sql.Stmt
var get_activity_count_by_watcher_stmt *sql.Stmt
var forum_entry_exists_stmt *sql.Stmt
var group_entry_exists_stmt *sql.Stmt
var add_forum_perms_to_forum_admins_stmt *sql.Stmt
var add_forum_perms_to_forum_staff_stmt *sql.Stmt
var add_forum_perms_to_forum_members_stmt *sql.Stmt
@ -65,18 +56,6 @@ func _init_database() (err error) {
return err
}
log.Print("Preparing get_topic_replies_offset statement.")
get_topic_replies_offset_stmt, err = db.Prepare("select replies.rid, replies.content, replies.createdBy, replies.createdAt, replies.lastEdit, replies.lastEditBy, users.avatar, users.name, users.group, users.url_prefix, users.url_name, users.level, replies.ipaddress, replies.likeCount, replies.actionType from replies left join users on replies.createdBy = users.uid where tid = ? limit ?, " + strconv.Itoa(items_per_page))
if err != nil {
return err
}
log.Print("Preparing get_forum_topics_offset statement.")
get_forum_topics_offset_stmt, err = db.Prepare("select topics.tid, topics.title, topics.content, topics.createdBy, topics.is_closed, topics.sticky, topics.createdAt, topics.lastReplyAt, topics.parentID, topics.postCount, topics.likeCount, users.name, users.avatar from topics left join users ON topics.createdBy = users.uid WHERE topics.parentID = ? order by topics.sticky DESC, topics.lastReplyAt DESC, topics.createdBy DESC limit ?, " + strconv.Itoa(items_per_page))
if err != nil {
return err
}
log.Print("Preparing notify_watchers statement.")
notify_watchers_stmt, err = db.Prepare("INSERT INTO activity_stream_matches(watcher, asid) SELECT activity_subscriptions.user, activity_stream.asid FROM activity_stream INNER JOIN activity_subscriptions ON activity_subscriptions.targetType = activity_stream.elementType and activity_subscriptions.targetID = activity_stream.elementID and activity_subscriptions.user != activity_stream.actor where asid = ?")
if err != nil {
@ -95,18 +74,6 @@ func _init_database() (err error) {
return err
}
log.Print("Preparing forum_entry_exists statement.")
forum_entry_exists_stmt, err = db.Prepare("SELECT `fid` FROM `forums` WHERE `name` = '' order by fid asc limit 1")
if err != nil {
return err
}
log.Print("Preparing group_entry_exists statement.")
group_entry_exists_stmt, err = db.Prepare("SELECT `gid` FROM `users_groups` WHERE `name` = '' order by gid asc limit 1")
if err != nil {
return err
}
log.Print("Preparing add_forum_perms_to_forum_admins statement.")
add_forum_perms_to_forum_admins_stmt, err = db.Prepare("INSERT INTO forums_permissions(gid,fid,preset,permissions) SELECT `gid`,? AS fid,? AS preset,? AS permissions FROM users_groups WHERE is_admin = 1")
if err != nil {
@ -151,3 +118,8 @@ func _init_database() (err error) {
return nil
}
// Temporary hack so that we can move all the raw queries out of the other files and into here
func topic_list_query(visible_fids []string) string {
return "select topics.tid, topics.title, topics.content, topics.createdBy, topics.is_closed, topics.sticky, topics.createdAt, topics.lastReplyAt, topics.parentID, topics.postCount, topics.likeCount, users.name, users.avatar from topics left join users ON topics.createdBy = users.uid where parentID in("+strings.Join(visible_fids,",")+") order by topics.sticky DESC, topics.lastReplyAt DESC, topics.createdBy DESC"
}

View File

@ -28,8 +28,8 @@ func (build *builder) SetAdapter(name string) error {
return nil
}
func (build *builder) SimpleSelect(table string, columns string, where string, orderby string/*, offset int, maxCount int*/) (stmt *sql.Stmt, err error) {
res, err := build.adapter.SimpleSelect("_builder", table, columns, where, orderby /*, offset, maxCount*/)
func (build *builder) SimpleSelect(table string, columns string, where string, orderby string, limit string) (stmt *sql.Stmt, err error) {
res, err := build.adapter.SimpleSelect("_builder", table, columns, where, orderby, limit)
if err != nil {
return stmt, err
}

View File

@ -11,8 +11,6 @@ func init() {
)
}
type Mysql_Adapter struct
{
Name string
@ -210,7 +208,7 @@ func (adapter *Mysql_Adapter) Purge(name string, table string) (string, error) {
return "DELETE FROM `" + table + "`", nil
}
func (adapter *Mysql_Adapter) SimpleSelect(name string, table string, columns string, where string, orderby string/*, offset int, maxCount int*/) (string, error) {
func (adapter *Mysql_Adapter) SimpleSelect(name string, table string, columns string, where string, orderby string, limit string) (string, error) {
if name == "" {
return "", errors.New("You need a name for this statement")
}
@ -264,12 +262,16 @@ func (adapter *Mysql_Adapter) SimpleSelect(name string, table string, columns st
querystr = querystr[0:len(querystr) - 1]
}
if limit != "" {
querystr += " LIMIT " + limit
}
querystr = strings.TrimSpace(querystr)
adapter.push_statement(name,querystr)
return querystr, nil
}
func (adapter *Mysql_Adapter) SimpleLeftJoin(name string, table1 string, table2 string, columns string, joiners string, where string, orderby string/*, offset int, maxCount int*/) (string, error) {
func (adapter *Mysql_Adapter) SimpleLeftJoin(name string, table1 string, table2 string, columns string, joiners string, where string, orderby string, limit string) (string, error) {
if name == "" {
return "", errors.New("You need a name for this statement")
}
@ -350,12 +352,16 @@ func (adapter *Mysql_Adapter) SimpleLeftJoin(name string, table1 string, table2
querystr = querystr[0:len(querystr) - 1]
}
if limit != "" {
querystr += " LIMIT " + limit
}
querystr = strings.TrimSpace(querystr)
adapter.push_statement(name,querystr)
return querystr, nil
}
func (adapter *Mysql_Adapter) SimpleInnerJoin(name string, table1 string, table2 string, columns string, joiners string, where string, orderby string/*, offset int, maxCount int*/) (string, error) {
func (adapter *Mysql_Adapter) SimpleInnerJoin(name string, table1 string, table2 string, columns string, joiners string, where string, orderby string, limit string) (string, error) {
if name == "" {
return "", errors.New("You need a name for this statement")
}
@ -436,12 +442,16 @@ func (adapter *Mysql_Adapter) SimpleInnerJoin(name string, table1 string, table2
querystr = querystr[0:len(querystr) - 1]
}
if limit != "" {
querystr += " LIMIT " + limit
}
querystr = strings.TrimSpace(querystr)
adapter.push_statement(name,querystr)
return querystr, nil
}
func (adapter *Mysql_Adapter) SimpleCount(name string, table string, where string/*, offset int, maxCount int*/) (string, error) {
func (adapter *Mysql_Adapter) SimpleCount(name string, table string, where string, limit string) (string, error) {
if name == "" {
return "", errors.New("You need a name for this statement")
}
@ -472,6 +482,10 @@ func (adapter *Mysql_Adapter) SimpleCount(name string, table string, where strin
querystr = querystr[0:len(querystr) - 4]
}
if limit != "" {
querystr += " LIMIT " + limit
}
querystr = strings.TrimSpace(querystr)
adapter.push_statement(name,querystr)
return querystr, nil

View File

@ -56,6 +56,11 @@ type DB_Setter struct {
Expr []DB_Token // Simple expressions, the innards of functions are opaque for now.
}
type DB_Limit struct {
Offset string // ? or int
MaxCount string // ? or int
}
type DB_Adapter interface {
GetName() string
SimpleInsert(string,string,string,string) (string, error)
@ -63,10 +68,10 @@ type DB_Adapter interface {
SimpleUpdate(string,string,string,string) (string, error)
SimpleDelete(string,string,string) (string, error)
Purge(string,string) (string, error)
SimpleSelect(string,string,string,string,string/*,int,int*/) (string, error)
SimpleLeftJoin(string,string,string,string,string,string,string/*,int,int*/) (string, error)
SimpleInnerJoin(string,string,string,string,string,string,string/*,int,int*/) (string, error)
SimpleCount(string,string,string/*,int,int*/) (string, error)
SimpleSelect(string,string,string,string,string,string) (string, error)
SimpleLeftJoin(string,string,string,string,string,string,string,string) (string, error)
SimpleInnerJoin(string,string,string,string,string,string,string,string) (string, error)
SimpleCount(string,string,string,string) (string, error)
Write() error
// TO-DO: Add a simple query builder

View File

@ -243,6 +243,17 @@ func _process_set(setstr string) (setter []DB_Setter) {
return setter
}
func _process_limit(limitstr string) (limiter DB_Limit) {
halves := strings.Split(limitstr,",")
if len(halves) == 2 {
limiter.Offset = halves[0]
limiter.MaxCount = halves[1]
} else {
limiter.MaxCount = halves[0]
}
return limiter
}
func _is_op_byte(char byte) bool {
return char == '<' || char == '>' || char == '=' || char == '!' || char == '*' || char == '%' || char == '+' || char == '-' || char == '/'
}

View File

@ -51,92 +51,100 @@ func write_statements(adapter qgen.DB_Adapter) error {
func write_selects(adapter qgen.DB_Adapter) error {
// url_prefix and url_name will be removed from this query in a later commit
adapter.SimpleSelect("get_user","users","name, group, is_super_admin, avatar, message, url_prefix, url_name, level","uid = ?","")
adapter.SimpleSelect("get_user","users","name, group, is_super_admin, avatar, message, url_prefix, url_name, level","uid = ?","","")
// Looking for get_topic? Your statement is in another castle
adapter.SimpleSelect("get_reply","replies","tid, content, createdBy, createdAt, lastEdit, lastEditBy, ipaddress, likeCount","rid = ?","")
adapter.SimpleSelect("get_reply","replies","tid, content, createdBy, createdAt, lastEdit, lastEditBy, ipaddress, likeCount","rid = ?","","")
adapter.SimpleSelect("get_user_reply","users_replies","uid, content, createdBy, createdAt, lastEdit, lastEditBy, ipaddress","rid = ?","")
adapter.SimpleSelect("get_user_reply","users_replies","uid, content, createdBy, createdAt, lastEdit, lastEditBy, ipaddress","rid = ?","","")
adapter.SimpleSelect("login","users","uid, name, password, salt","name = ?","")
adapter.SimpleSelect("login","users","uid, name, password, salt","name = ?","","")
adapter.SimpleSelect("get_password","users","password,salt","uid = ?","")
adapter.SimpleSelect("get_password","users","password,salt","uid = ?","","")
adapter.SimpleSelect("username_exists","users","name","name = ?","")
adapter.SimpleSelect("username_exists","users","name","name = ?","","")
adapter.SimpleSelect("get_settings","settings","name, content, type","","")
adapter.SimpleSelect("get_settings","settings","name, content, type","","","")
adapter.SimpleSelect("get_setting","settings","content, type","name = ?","")
adapter.SimpleSelect("get_setting","settings","content, type","name = ?","","")
adapter.SimpleSelect("get_full_setting","settings","name, type, constraints","name = ?","")
adapter.SimpleSelect("get_full_setting","settings","name, type, constraints","name = ?","","")
adapter.SimpleSelect("get_full_settings","settings","name, content, type, constraints","","")
adapter.SimpleSelect("get_full_settings","settings","name, content, type, constraints","","","")
adapter.SimpleSelect("get_groups","users_groups","gid, name, permissions, is_mod, is_admin, is_banned, tag","","")
adapter.SimpleSelect("get_groups","users_groups","gid, name, permissions, is_mod, is_admin, is_banned, tag","","","")
adapter.SimpleSelect("get_forums","forums","fid, name, desc, active, preset, topicCount, lastTopic, lastTopicID, lastReplyer, lastReplyerID, lastTopicTime","","fid ASC")
adapter.SimpleSelect("get_forums","forums","fid, name, desc, active, preset, topicCount, lastTopic, lastTopicID, lastReplyer, lastReplyerID, lastTopicTime","","fid ASC","")
adapter.SimpleSelect("get_forums_permissions","forums_permissions","gid, fid, permissions","","gid ASC, fid ASC")
adapter.SimpleSelect("get_forums_permissions","forums_permissions","gid, fid, permissions","","gid ASC, fid ASC","")
adapter.SimpleSelect("get_plugins","plugins","uname, active","","")
adapter.SimpleSelect("get_plugins","plugins","uname, active","","","")
adapter.SimpleSelect("get_themes","themes","uname, default","","")
adapter.SimpleSelect("get_themes","themes","uname, default","","","")
adapter.SimpleSelect("is_plugin_active","plugins","active","uname = ?","")
adapter.SimpleSelect("is_plugin_active","plugins","active","uname = ?","","")
adapter.SimpleSelect("get_users","users","uid, name, group, active, is_super_admin, avatar","","")
adapter.SimpleSelect("get_users","users","uid, name, group, active, is_super_admin, avatar","","","")
adapter.SimpleSelect("is_theme_default","themes","default","uname = ?","")
adapter.SimpleSelect("is_theme_default","themes","default","uname = ?","","")
adapter.SimpleSelect("get_modlogs","moderation_logs","action, elementID, elementType, ipaddress, actorID, doneAt","","")
adapter.SimpleSelect("get_modlogs","moderation_logs","action, elementID, elementType, ipaddress, actorID, doneAt","","","")
adapter.SimpleSelect("get_reply_tid","replies","tid","rid = ?","")
adapter.SimpleSelect("get_reply_tid","replies","tid","rid = ?","","")
adapter.SimpleSelect("get_topic_fid","topics","parentID","tid = ?","")
adapter.SimpleSelect("get_topic_fid","topics","parentID","tid = ?","","")
adapter.SimpleSelect("get_user_reply_uid","users_replies","uid","rid = ?","")
adapter.SimpleSelect("get_user_reply_uid","users_replies","uid","rid = ?","","")
adapter.SimpleSelect("has_liked_topic","likes","targetItem","sentBy = ? and targetItem = ? and targetType = 'topics'","")
adapter.SimpleSelect("has_liked_topic","likes","targetItem","sentBy = ? and targetItem = ? and targetType = 'topics'","","")
adapter.SimpleSelect("has_liked_reply","likes","targetItem","sentBy = ? and targetItem = ? and targetType = 'replies'","")
adapter.SimpleSelect("has_liked_reply","likes","targetItem","sentBy = ? and targetItem = ? and targetType = 'replies'","","")
adapter.SimpleSelect("get_user_name","users","name","uid = ?","")
adapter.SimpleSelect("get_user_name","users","name","uid = ?","","")
adapter.SimpleSelect("get_user_rank","users","group, is_super_admin","uid = ?","")
adapter.SimpleSelect("get_user_rank","users","group, is_super_admin","uid = ?","","")
adapter.SimpleSelect("get_user_active","users","active","uid = ?","")
adapter.SimpleSelect("get_user_active","users","active","uid = ?","","")
adapter.SimpleSelect("get_user_group","users","group","uid = ?","")
adapter.SimpleSelect("get_user_group","users","group","uid = ?","","")
adapter.SimpleSelect("get_emails_by_user","emails","email, validated, token","uid = ?","")
adapter.SimpleSelect("get_emails_by_user","emails","email, validated, token","uid = ?","","")
adapter.SimpleSelect("get_topic_basic","topics","title, content","tid = ?","")
adapter.SimpleSelect("get_topic_basic","topics","title, content","tid = ?","","")
adapter.SimpleSelect("get_activity_entry","activity_stream","actor, targetUser, event, elementType, elementID","asid = ?","")
adapter.SimpleSelect("get_activity_entry","activity_stream","actor, targetUser, event, elementType, elementID","asid = ?","","")
adapter.SimpleSelect("forum_entry_exists","forums","fid","name = ''","fid ASC","0,1") // Is '' empty?
adapter.SimpleSelect("group_entry_exists","users_groups","gid","name = ''","gid ASC","0,1") // Is '' empty?
return nil
}
func write_left_joins(adapter qgen.DB_Adapter) error {
adapter.SimpleLeftJoin("get_topic_list","topics","users","topics.tid, topics.title, topics.content, topics.createdBy, topics.is_closed, topics.sticky, topics.createdAt, topics.parentID, users.name, users.avatar","topics.createdBy = users.uid","","topics.sticky DESC, topics.lastReplyAt DESC, topics.createdBy DESC")
adapter.SimpleLeftJoin("get_topic_replies_offset","replies","users","replies.rid, replies.content, replies.createdBy, replies.createdAt, replies.lastEdit, replies.lastEditBy, users.avatar, users.name, users.group, users.url_prefix, users.url_name, users.level, replies.ipaddress, replies.likeCount, replies.actionType","replies.createdBy = users.uid","tid = ?","","?,?")
adapter.SimpleLeftJoin("get_topic_user","topics","users","topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.postCount, topics.likeCount, users.name, users.avatar, users.group, users.url_prefix, users.url_name, users.level","topics.createdBy = users.uid","tid = ?","")
adapter.SimpleLeftJoin("get_forum_topics_offset","topics","users","topics.tid, topics.title, topics.content, topics.createdBy, topics.is_closed, topics.sticky, topics.createdAt, topics.lastReplyAt, topics.parentID, topics.postCount, topics.likeCount, users.name, users.avatar","topics.createdBy = users.uid","topics.parentID = ?","topics.sticky DESC, topics.lastReplyAt DESC, topics.createdBy DESC","?,?")
adapter.SimpleLeftJoin("get_topic_by_reply","replies","topics","topics.tid, topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.postCount, topics.likeCount, topics.data","replies.tid = topics.tid","rid = ?","")
adapter.SimpleLeftJoin("get_topic_list","topics","users","topics.tid, topics.title, topics.content, topics.createdBy, topics.is_closed, topics.sticky, topics.createdAt, topics.parentID, users.name, users.avatar","topics.createdBy = users.uid","","topics.sticky DESC, topics.lastReplyAt DESC, topics.createdBy DESC","")
adapter.SimpleLeftJoin("get_topic_replies","replies","users","replies.rid, replies.content, replies.createdBy, replies.createdAt, replies.lastEdit, replies.lastEditBy, users.avatar, users.name, users.group, users.url_prefix, users.url_name, users.level, replies.ipaddress","replies.createdBy = users.uid","tid = ?","")
adapter.SimpleLeftJoin("get_topic_user","topics","users","topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.postCount, topics.likeCount, users.name, users.avatar, users.group, users.url_prefix, users.url_name, users.level","topics.createdBy = users.uid","tid = ?","","")
adapter.SimpleLeftJoin("get_forum_topics","topics","users","topics.tid, topics.title, topics.content, topics.createdBy, topics.is_closed, topics.sticky, topics.createdAt, topics.lastReplyAt, topics.parentID, users.name, users.avatar","topics.createdBy = users.uid","topics.parentID = ?","topics.sticky DESC, topics.lastReplyAt DESC, topics.createdBy desc")
adapter.SimpleLeftJoin("get_topic_by_reply","replies","topics","topics.tid, topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.postCount, topics.likeCount, topics.data","replies.tid = topics.tid","rid = ?","","")
adapter.SimpleLeftJoin("get_profile_replies","users_replies","users","users_replies.rid, users_replies.content, users_replies.createdBy, users_replies.createdAt, users_replies.lastEdit, users_replies.lastEditBy, users.avatar, users.name, users.group","users_replies.createdBy = users.uid","users_replies.uid = ?","")
adapter.SimpleLeftJoin("get_topic_replies","replies","users","replies.rid, replies.content, replies.createdBy, replies.createdAt, replies.lastEdit, replies.lastEditBy, users.avatar, users.name, users.group, users.url_prefix, users.url_name, users.level, replies.ipaddress","replies.createdBy = users.uid","tid = ?","","")
adapter.SimpleLeftJoin("get_forum_topics","topics","users","topics.tid, topics.title, topics.content, topics.createdBy, topics.is_closed, topics.sticky, topics.createdAt, topics.lastReplyAt, topics.parentID, users.name, users.avatar","topics.createdBy = users.uid","topics.parentID = ?","topics.sticky DESC, topics.lastReplyAt DESC, topics.createdBy desc","")
adapter.SimpleLeftJoin("get_profile_replies","users_replies","users","users_replies.rid, users_replies.content, users_replies.createdBy, users_replies.createdAt, users_replies.lastEdit, users_replies.lastEditBy, users.avatar, users.name, users.group","users_replies.createdBy = users.uid","users_replies.uid = ?","","")
return nil
}
func write_inner_joins(adapter qgen.DB_Adapter) error {
adapter.SimpleInnerJoin("get_watchers","activity_stream","activity_subscriptions","activity_subscriptions.user","activity_subscriptions.targetType = activity_stream.elementType AND activity_subscriptions.targetID = activity_stream.elementID AND activity_subscriptions.user != activity_stream.actor","asid = ?","")
adapter.SimpleInnerJoin("get_watchers","activity_stream","activity_subscriptions","activity_subscriptions.user","activity_subscriptions.targetType = activity_stream.elementType AND activity_subscriptions.targetID = activity_stream.elementID AND activity_subscriptions.user != activity_stream.actor","asid = ?","","")
return nil
}
@ -283,7 +291,7 @@ func write_deletes(adapter qgen.DB_Adapter) error {
}
func write_simple_counts(adapter qgen.DB_Adapter) error {
adapter.SimpleCount("report_exists","topics","data = ? and data != '' and parentID = 1")
adapter.SimpleCount("report_exists","topics","data = ? and data != '' and parentID = 1","")
return nil
}

View File

@ -111,8 +111,7 @@ func route_topics(w http.ResponseWriter, r *http.Request){
}
var topicList []TopicsRow
rows, err := db.Query("select topics.tid, topics.title, topics.content, topics.createdBy, topics.is_closed, topics.sticky, topics.createdAt, topics.lastReplyAt, topics.parentID, topics.postCount, topics.likeCount, users.name, users.avatar from topics left join users ON topics.createdBy = users.uid where parentID in("+strings.Join(fidList,",")+") order by topics.sticky DESC, topics.lastReplyAt DESC, topics.createdBy DESC")
//rows, err := get_topic_list_stmt.Query()
rows, err := db.Query(topic_list_query(fidList))
if err != nil {
InternalError(err,w,r)
return
@ -201,7 +200,7 @@ func route_forum(w http.ResponseWriter, r *http.Request, sfid string){
} else {
page = 1
}
rows, err := get_forum_topics_offset_stmt.Query(fid,offset)
rows, err := get_forum_topics_offset_stmt.Query(fid,offset,items_per_page)
if err != nil {
InternalError(err,w,r)
return
@ -364,7 +363,7 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
}
// Get the replies..
rows, err := get_topic_replies_offset_stmt.Query(topic.ID, offset)
rows, err := get_topic_replies_offset_stmt.Query(topic.ID, offset, items_per_page)
if err == sql.ErrNoRows {
LocalError("Bad Page. Some of the posts may have been deleted or you got here by directly typing in the page number.",w,r,user)
return

View File

@ -23,7 +23,7 @@ type TopicStore interface {
GetCapacity() int
}
type StaticTopicStore struct {
type MemoryTopicStore struct {
items map[int]*Topic
length int
capacity int
@ -31,19 +31,19 @@ type StaticTopicStore struct {
sync.RWMutex
}
func NewStaticTopicStore(capacity int) *StaticTopicStore {
stmt, err := qgen.Builder.SimpleSelect("topics","title, content, createdBy, createdAt, is_closed, sticky, parentID, ipaddress, postCount, likeCount, data","tid = ?","")
func NewMemoryTopicStore(capacity int) *MemoryTopicStore {
stmt, err := qgen.Builder.SimpleSelect("topics","title, content, createdBy, createdAt, is_closed, sticky, parentID, ipaddress, postCount, likeCount, data","tid = ?","","")
if err != nil {
log.Fatal(err)
}
return &StaticTopicStore{
return &MemoryTopicStore{
items:make(map[int]*Topic),
capacity:capacity,
get:stmt,
}
}
func (sts *StaticTopicStore) Get(id int) (*Topic, error) {
func (sts *MemoryTopicStore) Get(id int) (*Topic, error) {
sts.RLock()
item, ok := sts.items[id]
sts.RUnlock()
@ -53,7 +53,7 @@ func (sts *StaticTopicStore) Get(id int) (*Topic, error) {
return item, sql.ErrNoRows
}
func (sts *StaticTopicStore) GetUnsafe(id int) (*Topic, error) {
func (sts *MemoryTopicStore) GetUnsafe(id int) (*Topic, error) {
item, ok := sts.items[id]
if ok {
return item, nil
@ -61,7 +61,7 @@ func (sts *StaticTopicStore) GetUnsafe(id int) (*Topic, error) {
return item, sql.ErrNoRows
}
func (sts *StaticTopicStore) CascadeGet(id int) (*Topic, error) {
func (sts *MemoryTopicStore) CascadeGet(id int) (*Topic, error) {
sts.RLock()
topic, ok := sts.items[id]
sts.RUnlock()
@ -77,13 +77,13 @@ func (sts *StaticTopicStore) CascadeGet(id int) (*Topic, error) {
return topic, err
}
func (sts *StaticTopicStore) BypassGet(id int) (*Topic, error) {
func (sts *MemoryTopicStore) BypassGet(id int) (*Topic, error) {
topic := &Topic{ID:id}
err := sts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.IpAddress, &topic.PostCount, &topic.LikeCount, &topic.Data)
return topic, err
}
func (sts *StaticTopicStore) Load(id int) error {
func (sts *MemoryTopicStore) Load(id int) error {
topic := &Topic{ID:id}
err := sts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.IpAddress, &topic.PostCount, &topic.LikeCount, &topic.Data)
if err == nil {
@ -94,7 +94,7 @@ func (sts *StaticTopicStore) Load(id int) error {
return err
}
func (sts *StaticTopicStore) Set(item *Topic) error {
func (sts *MemoryTopicStore) Set(item *Topic) error {
sts.Lock()
_, ok := sts.items[item.ID]
if ok {
@ -110,7 +110,7 @@ func (sts *StaticTopicStore) Set(item *Topic) error {
return nil
}
func (sts *StaticTopicStore) Add(item *Topic) error {
func (sts *MemoryTopicStore) Add(item *Topic) error {
if sts.length >= sts.capacity {
return ErrStoreCapacityOverflow
}
@ -121,7 +121,7 @@ func (sts *StaticTopicStore) Add(item *Topic) error {
return nil
}
func (sts *StaticTopicStore) AddUnsafe(item *Topic) error {
func (sts *MemoryTopicStore) AddUnsafe(item *Topic) error {
if sts.length >= sts.capacity {
return ErrStoreCapacityOverflow
}
@ -130,7 +130,7 @@ func (sts *StaticTopicStore) AddUnsafe(item *Topic) error {
return nil
}
func (sts *StaticTopicStore) Remove(id int) error {
func (sts *MemoryTopicStore) Remove(id int) error {
sts.Lock()
delete(sts.items,id)
sts.Unlock()
@ -138,40 +138,35 @@ func (sts *StaticTopicStore) Remove(id int) error {
return nil
}
func (sts *StaticTopicStore) RemoveUnsafe(id int) error {
func (sts *MemoryTopicStore) RemoveUnsafe(id int) error {
delete(sts.items,id)
sts.length--
return nil
}
func (sts *StaticTopicStore) AddLastTopic(item *Topic, fid int) error {
func (sts *MemoryTopicStore) AddLastTopic(item *Topic, fid int) error {
// Coming Soon...
return nil
}
func (sts *StaticTopicStore) GetLength() int {
func (sts *MemoryTopicStore) GetLength() int {
return sts.length
}
func (sts *StaticTopicStore) SetCapacity(capacity int) {
func (sts *MemoryTopicStore) SetCapacity(capacity int) {
sts.capacity = capacity
}
func (sts *StaticTopicStore) GetCapacity() int {
func (sts *MemoryTopicStore) GetCapacity() int {
return sts.capacity
}
//type DynamicTopicStore struct {
// items_expiries list.List
// items map[int]*Topic
//}
type SqlTopicStore struct {
get *sql.Stmt
}
func NewSqlTopicStore() *SqlTopicStore {
stmt, err := qgen.Builder.SimpleSelect("topics","title, content, createdBy, createdAt, is_closed, sticky, parentID, ipaddress, postCount, likeCount, data","tid = ?","")
stmt, err := qgen.Builder.SimpleSelect("topics","title, content, createdBy, createdAt, is_closed, sticky, parentID, ipaddress, postCount, likeCount, data","tid = ?","","")
if err != nil {
log.Fatal(err)
}

View File

@ -11,6 +11,7 @@ import (
)
var guest_user User = User{ID:0,Group:6,Perms:GuestPerms}
var SimpleSessionCheck func(http.ResponseWriter, *http.Request) (User,bool) = _simple_session_check
type User struct
{
@ -145,7 +146,7 @@ func SessionCheck(w http.ResponseWriter, r *http.Request) (user User, noticeList
return user, noticeList, success
}
func SimpleSessionCheck(w http.ResponseWriter, r *http.Request) (User,bool) {
func _simple_session_check(w http.ResponseWriter, r *http.Request) (User,bool) {
// Are there any session cookies..?
cookie, err := r.Cookie("uid")
if err != nil {

View File

@ -26,7 +26,7 @@ type UserStore interface {
GetCapacity() int
}
type StaticUserStore struct {
type MemoryUserStore struct {
items map[int]*User
length int
capacity int
@ -34,19 +34,19 @@ type StaticUserStore struct {
sync.RWMutex
}
func NewStaticUserStore(capacity int) *StaticUserStore {
stmt, err := qgen.Builder.SimpleSelect("users","name, group, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, last_ip","uid = ?","")
func NewMemoryUserStore(capacity int) *MemoryUserStore {
stmt, err := qgen.Builder.SimpleSelect("users","name, group, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, last_ip","uid = ?","","")
if err != nil {
log.Fatal(err)
}
return &StaticUserStore{
return &MemoryUserStore{
items:make(map[int]*User),
capacity:capacity,
get:stmt,
}
}
func (sus *StaticUserStore) Get(id int) (*User, error) {
func (sus *MemoryUserStore) Get(id int) (*User, error) {
sus.RLock()
item, ok := sus.items[id]
sus.RUnlock()
@ -56,7 +56,7 @@ func (sus *StaticUserStore) Get(id int) (*User, error) {
return item, sql.ErrNoRows
}
func (sus *StaticUserStore) GetUnsafe(id int) (*User, error) {
func (sus *MemoryUserStore) GetUnsafe(id int) (*User, error) {
item, ok := sus.items[id]
if ok {
return item, nil
@ -64,7 +64,7 @@ func (sus *StaticUserStore) GetUnsafe(id int) (*User, error) {
return item, sql.ErrNoRows
}
func (sus *StaticUserStore) CascadeGet(id int) (*User, error) {
func (sus *MemoryUserStore) CascadeGet(id int) (*User, error) {
sus.RLock()
user, ok := sus.items[id]
sus.RUnlock()
@ -90,7 +90,7 @@ func (sus *StaticUserStore) CascadeGet(id int) (*User, error) {
return user, err
}
func (sus *StaticUserStore) BypassGet(id int) (*User, error) {
func (sus *MemoryUserStore) BypassGet(id int) (*User, error) {
user := &User{ID:id,Loggedin:true}
err := sus.get.QueryRow(id).Scan(&user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Last_IP)
@ -106,7 +106,7 @@ func (sus *StaticUserStore) BypassGet(id int) (*User, error) {
return user, err
}
func (sus *StaticUserStore) Load(id int) error {
func (sus *MemoryUserStore) Load(id int) error {
user := &User{ID:id,Loggedin:true}
err := sus.get.QueryRow(id).Scan(&user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.Last_IP)
if err != nil {
@ -127,7 +127,7 @@ func (sus *StaticUserStore) Load(id int) error {
return nil
}
func (sus *StaticUserStore) Set(item *User) error {
func (sus *MemoryUserStore) Set(item *User) error {
sus.Lock()
user, ok := sus.items[item.ID]
if ok {
@ -144,7 +144,7 @@ func (sus *StaticUserStore) Set(item *User) error {
return nil
}
func (sus *StaticUserStore) Add(item *User) error {
func (sus *MemoryUserStore) Add(item *User) error {
if sus.length >= sus.capacity {
return ErrStoreCapacityOverflow
}
@ -155,7 +155,7 @@ func (sus *StaticUserStore) Add(item *User) error {
return nil
}
func (sus *StaticUserStore) AddUnsafe(item *User) error {
func (sus *MemoryUserStore) AddUnsafe(item *User) error {
if sus.length >= sus.capacity {
return ErrStoreCapacityOverflow
}
@ -164,7 +164,7 @@ func (sus *StaticUserStore) AddUnsafe(item *User) error {
return nil
}
func (sus *StaticUserStore) Remove(id int) error {
func (sus *MemoryUserStore) Remove(id int) error {
sus.Lock()
delete(sus.items,id)
sus.Unlock()
@ -172,35 +172,30 @@ func (sus *StaticUserStore) Remove(id int) error {
return nil
}
func (sus *StaticUserStore) RemoveUnsafe(id int) error {
func (sus *MemoryUserStore) RemoveUnsafe(id int) error {
delete(sus.items,id)
sus.length--
return nil
}
func (sus *StaticUserStore) GetLength() int {
func (sus *MemoryUserStore) GetLength() int {
return sus.length
}
func (sus *StaticUserStore) SetCapacity(capacity int) {
func (sus *MemoryUserStore) SetCapacity(capacity int) {
sus.capacity = capacity
}
func (sus *StaticUserStore) GetCapacity() int {
func (sus *MemoryUserStore) GetCapacity() int {
return sus.capacity
}
//type DynamicUserStore struct {
// items_expiries list.List
// items map[int]*User
//}
type SqlUserStore struct {
get *sql.Stmt
}
func NewSqlUserStore() *SqlUserStore {
stmt, err := qgen.Builder.SimpleSelect("users","name, group, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, last_ip","uid = ?","")
stmt, err := qgen.Builder.SimpleSelect("users","name, group, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, last_ip","uid = ?","","")
if err != nil {
log.Fatal(err)
}