Added Live Alerts for replies to posts.
Added relative times to posts. Added push_alerts to the WebSockets Hub. Added simple_delete, purge, and simple_inner_join to the query generator. Query generator joiners now take not equals into account. Other query generator stuff and query refactoring. Fixed a weird padding bug on Tempra Conflux. Fixed a couple of megapost_min_chars and bigpost_min_chars which I missed. Fixed a security exploit in the login system.
This commit is contained in:
parent
81af085c7a
commit
29d9d07cde
37
alerts.go
37
alerts.go
|
@ -1,8 +1,10 @@
|
|||
package main
|
||||
|
||||
import "log"
|
||||
import "strings"
|
||||
import "strconv"
|
||||
import "errors"
|
||||
import "database/sql"
|
||||
|
||||
/*
|
||||
"You received a friend invite from {user}"
|
||||
|
@ -111,3 +113,38 @@ func build_alert(event string, elementType string, actor_id int, targetUser_id i
|
|||
|
||||
return `{"msg":"{0} ` + start_frag + act + post_act + ` {1}` + end_frag + `","sub":["` + actor.Name + `","` + area + `"],"path":"` + url + `","avatar":"` + actor.Avatar + `"}`, nil
|
||||
}
|
||||
|
||||
func notify_watchers(asid int64) {
|
||||
rows, err := get_watchers_stmt.Query(asid)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
log.Fatal(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
var uid int
|
||||
var uids []int
|
||||
for rows.Next() {
|
||||
err := rows.Scan(&uid)
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
return
|
||||
}
|
||||
uids = append(uids,uid)
|
||||
}
|
||||
err = rows.Err()
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
return
|
||||
}
|
||||
rows.Close()
|
||||
|
||||
var actor_id, targetUser_id, elementID int
|
||||
var event, elementType string
|
||||
err = get_activity_entry_stmt.QueryRow(asid).Scan(&actor_id, &targetUser_id, &event, &elementType, &elementID)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
log.Fatal(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
_ = ws_hub.push_alerts(uids, event, elementType, actor_id, targetUser_id, elementID)
|
||||
}
|
||||
|
|
81
gen_mysql.go
81
gen_mysql.go
|
@ -26,14 +26,19 @@ var get_user_reply_uid_stmt *sql.Stmt
|
|||
var has_liked_topic_stmt *sql.Stmt
|
||||
var has_liked_reply_stmt *sql.Stmt
|
||||
var get_user_name_stmt *sql.Stmt
|
||||
var get_user_rank_stmt *sql.Stmt
|
||||
var get_user_active_stmt *sql.Stmt
|
||||
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 get_topic_list_stmt *sql.Stmt
|
||||
var get_topic_user_stmt *sql.Stmt
|
||||
var get_topic_by_reply_stmt *sql.Stmt
|
||||
var get_topic_replies_stmt *sql.Stmt
|
||||
var get_forum_topics_stmt *sql.Stmt
|
||||
var get_profile_replies_stmt *sql.Stmt
|
||||
var get_watchers_stmt *sql.Stmt
|
||||
var create_topic_stmt *sql.Stmt
|
||||
var create_report_stmt *sql.Stmt
|
||||
var create_reply_stmt *sql.Stmt
|
||||
|
@ -42,7 +47,9 @@ var create_like_stmt *sql.Stmt
|
|||
var add_activity_stmt *sql.Stmt
|
||||
var notify_one_stmt *sql.Stmt
|
||||
var register_stmt *sql.Stmt
|
||||
var add_email_stmt *sql.Stmt
|
||||
var create_profile_reply_stmt *sql.Stmt
|
||||
var add_subscription_stmt *sql.Stmt
|
||||
var create_forum_stmt *sql.Stmt
|
||||
var add_forum_perms_to_forum_stmt *sql.Stmt
|
||||
var add_plugin_stmt *sql.Stmt
|
||||
|
@ -86,6 +93,10 @@ var update_user_stmt *sql.Stmt
|
|||
var update_group_perms_stmt *sql.Stmt
|
||||
var update_group_rank_stmt *sql.Stmt
|
||||
var update_group_stmt *sql.Stmt
|
||||
var delete_reply_stmt *sql.Stmt
|
||||
var delete_topic_stmt *sql.Stmt
|
||||
var delete_profile_reply_stmt *sql.Stmt
|
||||
var delete_forum_perms_by_forum_stmt *sql.Stmt
|
||||
|
||||
func gen_mysql() (err error) {
|
||||
if debug {
|
||||
|
@ -105,7 +116,7 @@ func gen_mysql() (err error) {
|
|||
}
|
||||
|
||||
log.Print("Preparing get_topic statement.")
|
||||
get_topic_stmt, err = db.Prepare("SELECT `title`,`content`,`createdBy`,`createdAt`,`is_closed`,`sticky`,`parentID`,`ipaddress`,`postCount`,`likeCount` FROM `topics` WHERE `tid` = ?")
|
||||
get_topic_stmt, err = db.Prepare("SELECT `title`,`content`,`createdBy`,`createdAt`,`is_closed`,`sticky`,`parentID`,`ipaddress`,`postCount`,`likeCount`,`data` FROM `topics` WHERE `tid` = ?")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -212,6 +223,24 @@ func gen_mysql() (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing get_user_rank statement.")
|
||||
get_user_rank_stmt, err = db.Prepare("SELECT `group`,`is_super_admin` FROM `users` WHERE `uid` = ?")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing get_user_active statement.")
|
||||
get_user_active_stmt, err = db.Prepare("SELECT `active` FROM `users` WHERE `uid` = ?")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing get_user_group statement.")
|
||||
get_user_group_stmt, err = db.Prepare("SELECT `group` FROM `users` WHERE `uid` = ?")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing get_emails_by_user statement.")
|
||||
get_emails_by_user_stmt, err = db.Prepare("SELECT `email`,`validated` FROM `emails` WHERE `uid` = ?")
|
||||
if err != nil {
|
||||
|
@ -224,6 +253,12 @@ func gen_mysql() (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing get_activity_entry statement.")
|
||||
get_activity_entry_stmt, err = db.Prepare("SELECT `actor`,`targetUser`,`event`,`elementType`,`elementID` FROM `activity_stream` WHERE `asid` = ?")
|
||||
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 {
|
||||
|
@ -237,7 +272,7 @@ func gen_mysql() (err error) {
|
|||
}
|
||||
|
||||
log.Print("Preparing get_topic_by_reply statement.")
|
||||
get_topic_by_reply_stmt, err = db.Prepare("SELECT `topics`.`tid`,`topics`.`title`,`topics`.`content`,`topics`.`createdBy`,`topics`.`createdAt`,`topics`.`is_closed`,`topics`.`sticky`,`topics`.`parentID`,`topics`.`ipaddress`,`topics`.`postCount`,`topics`.`likeCount` FROM `replies` LEFT JOIN `topics` ON `replies`.`tid`=`topics`.`tid` WHERE `rid` = ?")
|
||||
get_topic_by_reply_stmt, err = db.Prepare("SELECT `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` FROM `replies` LEFT JOIN `topics` ON `replies`.`tid` = `topics`.`tid` WHERE `rid` = ?")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -260,6 +295,12 @@ func gen_mysql() (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing get_watchers statement.")
|
||||
get_watchers_stmt, err = db.Prepare("SELECT `activity_subscriptions`.`user` 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 {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing create_topic statement.")
|
||||
create_topic_stmt, err = db.Prepare("INSERT INTO `topics`(`parentID`,`title`,`content`,`parsed_content`,`createdAt`,`lastReplyAt`,`ipaddress`,`words`,`createdBy`) VALUES (?,?,?,?,NOW(),NOW(),?,?,?)")
|
||||
if err != nil {
|
||||
|
@ -308,12 +349,24 @@ func gen_mysql() (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing add_email statement.")
|
||||
add_email_stmt, err = db.Prepare("INSERT INTO `emails`(`email`,`uid`,`validated`,`token`) VALUES (?,?,?,?)")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing create_profile_reply statement.")
|
||||
create_profile_reply_stmt, err = db.Prepare("INSERT INTO `users_replies`(`uid`,`content`,`parsed_content`,`createdAt`,`createdBy`) VALUES (?,?,?,NOW(),?)")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing add_subscription statement.")
|
||||
add_subscription_stmt, err = db.Prepare("INSERT INTO `activity_subscriptions`(`user`,`targetID`,`targetType`,`level`) VALUES (?,?,?,2)")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing create_forum statement.")
|
||||
create_forum_stmt, err = db.Prepare("INSERT INTO `forums`(`name`,`desc`,`active`,`preset`) VALUES (?,?,?,?)")
|
||||
if err != nil {
|
||||
|
@ -572,5 +625,29 @@ func gen_mysql() (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing delete_reply statement.")
|
||||
delete_reply_stmt, err = db.Prepare("DELETE FROM `replies` WHERE `rid` = ?")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing delete_topic statement.")
|
||||
delete_topic_stmt, err = db.Prepare("DELETE FROM `topics` WHERE `tid` = ?")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing delete_profile_reply statement.")
|
||||
delete_profile_reply_stmt, err = db.Prepare("DELETE FROM `users_replies` WHERE `rid` = ?")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing delete_forum_perms_by_forum statement.")
|
||||
delete_forum_perms_by_forum_stmt, err = db.Prepare("DELETE FROM `forums_permissions` WHERE `fid` = ?")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
4
main.go
4
main.go
|
@ -61,7 +61,7 @@ func compile_templates() {
|
|||
|
||||
log.Print("Compiling the templates")
|
||||
|
||||
topic := TopicUser{1,"Blah","Hey there!",0,false,false,"Date","Date",0,"","127.0.0.1",0,1,"classname","",default_group,"",no_css_tmpl,0,"","","","",58,false}
|
||||
topic := TopicUser{1,"Blah","Hey there!",0,false,false,"Date","Date",0,"","127.0.0.1",0,1,"classname","","",default_group,"",no_css_tmpl,0,"","","","",58,false}
|
||||
var replyList []Reply
|
||||
replyList = append(replyList, Reply{0,0,"","Yo!",0,"",default_group,"",0,0,"",no_css_tmpl,0,"","","","",0,"127.0.0.1",false,1,"",""})
|
||||
|
||||
|
@ -90,7 +90,7 @@ func compile_templates() {
|
|||
topics_tmpl := c.compile_template("topics.html","templates/","TopicsPage", topics_page, varList)
|
||||
|
||||
var topicList []TopicUser
|
||||
topicList = append(topicList,TopicUser{1,"Topic Title","The topic content.",1,false,false,"Date","Date",1,"","127.0.0.1",0,1,"classname","Admin",default_group,"","",0,"","","","",58,false})
|
||||
topicList = append(topicList,TopicUser{1,"Topic Title","The topic content.",1,false,false,"Date","Date",1,"","127.0.0.1",0,1,"classname","","Admin",default_group,"","",0,"","","","",58,false})
|
||||
forum_item := Forum{1,"General Forum","Where the general stuff happens",true,"all",0,"",0,"",0,""}
|
||||
forum_page := ForumPage{"General Forum",user,noticeList,topicList,forum_item,1,1,nil}
|
||||
forum_tmpl := c.compile_template("forum.html","templates/","ForumPage", forum_page, varList)
|
||||
|
|
|
@ -22,15 +22,14 @@ func route_edit_topic(w http.ResponseWriter, r *http.Request) {
|
|||
is_js = "0"
|
||||
}
|
||||
|
||||
var tid, fid int
|
||||
var tid int
|
||||
tid, err = strconv.Atoi(r.URL.Path[len("/topic/edit/submit/"):])
|
||||
if err != nil {
|
||||
PreErrorJSQ("The provided TopicID is not a valid number.",w,r,is_js)
|
||||
return
|
||||
}
|
||||
|
||||
var old_is_closed bool
|
||||
err = db.QueryRow("select parentID, is_closed from topics where tid = ?", tid).Scan(&fid,&old_is_closed)
|
||||
old_topic, err := topics.CascadeGet(tid)
|
||||
if err == sql.ErrNoRows {
|
||||
PreErrorJSQ("The topic you tried to edit doesn't exist.",w,r,is_js)
|
||||
return
|
||||
|
@ -39,7 +38,7 @@ func route_edit_topic(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
user, ok := SimpleForumSessionCheck(w,r,fid)
|
||||
user, ok := SimpleForumSessionCheck(w,r,old_topic.ParentID)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -65,7 +64,7 @@ func route_edit_topic(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
if old_is_closed != is_closed {
|
||||
if old_topic.Is_Closed != is_closed {
|
||||
var action string
|
||||
if is_closed {
|
||||
action = "lock"
|
||||
|
@ -97,9 +96,12 @@ func route_edit_topic(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
err = topics.Load(tid)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
LocalErrorJSQ("This topic no longer exists!",w,r,user,is_js)
|
||||
return
|
||||
} else if err != nil {
|
||||
InternalErrorJSQ(err,w,r,is_js)
|
||||
return
|
||||
}
|
||||
|
||||
if is_js == "0" {
|
||||
|
@ -116,9 +118,7 @@ func route_delete_topic(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
var content string
|
||||
var createdBy, fid int
|
||||
err = db.QueryRow("select content, createdBy, parentID from topics where tid = ?", tid).Scan(&content, &createdBy, &fid)
|
||||
topic, err := topics.CascadeGet(tid)
|
||||
if err == sql.ErrNoRows {
|
||||
PreError("The topic you tried to delete doesn't exist.",w,r)
|
||||
return
|
||||
|
@ -127,7 +127,7 @@ func route_delete_topic(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
user, ok := SimpleForumSessionCheck(w,r,fid)
|
||||
user, ok := SimpleForumSessionCheck(w,r,topic.ParentID)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -163,20 +163,20 @@ func route_delete_topic(w http.ResponseWriter, r *http.Request) {
|
|||
//log.Print("Topic #" + strconv.Itoa(tid) + " was deleted by User #" + strconv.Itoa(user.ID))
|
||||
http.Redirect(w,r,"/",http.StatusSeeOther)
|
||||
|
||||
wcount := word_count(content)
|
||||
err = decrease_post_user_stats(wcount,createdBy,true,user)
|
||||
wcount := word_count(topic.Content)
|
||||
err = decrease_post_user_stats(wcount,topic.CreatedBy,true,user)
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = remove_topics_from_forum_stmt.Exec(1, fid)
|
||||
_, err = remove_topics_from_forum_stmt.Exec(1, topic.ParentID)
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
return
|
||||
}
|
||||
|
||||
forums[fid].TopicCount -= 1
|
||||
forums[topic.ParentID].TopicCount -= 1
|
||||
topics.Remove(tid)
|
||||
}
|
||||
|
||||
|
@ -553,7 +553,7 @@ func route_ban(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
var uname string
|
||||
err = db.QueryRow("select name from users where uid = ?", uid).Scan(&uname)
|
||||
err = get_user_name_stmt.QueryRow(uid).Scan(&uname)
|
||||
if err == sql.ErrNoRows {
|
||||
LocalError("The user you're trying to ban no longer exists.",w,r,user)
|
||||
return
|
||||
|
@ -588,14 +588,14 @@ func route_ban_submit(w http.ResponseWriter, r *http.Request) {
|
|||
LocalError("The provided User ID is not a valid number.",w,r,user)
|
||||
return
|
||||
}
|
||||
if uid == -2 {
|
||||
/*if uid == -2 {
|
||||
LocalError("Sigh, are you really trying to ban me? Do you despise so much? Despite all of our adventures over at /arcane-tower/...?",w,r,user)
|
||||
return
|
||||
}
|
||||
}*/
|
||||
|
||||
var group int
|
||||
var is_super_admin bool
|
||||
err = db.QueryRow("select `group`,`is_super_admin` from `users` where `uid` = ?", uid).Scan(&group, &is_super_admin)
|
||||
err = get_user_rank_stmt.QueryRow(uid).Scan(&group, &is_super_admin)
|
||||
if err == sql.ErrNoRows {
|
||||
LocalError("The user you're trying to ban no longer exists.",w,r,user)
|
||||
return
|
||||
|
@ -663,9 +663,8 @@ func route_unban(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
var uname string
|
||||
var group int
|
||||
err = db.QueryRow("select `name`, `group` from users where `uid` = ?", uid).Scan(&uname, &group)
|
||||
err = get_user_group_stmt.QueryRow(uid).Scan(&group)
|
||||
if err == sql.ErrNoRows {
|
||||
LocalError("The user you're trying to unban no longer exists.",w,r,user)
|
||||
return
|
||||
|
@ -697,10 +696,14 @@ func route_unban(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
err = users.Load(uid)
|
||||
if err != nil {
|
||||
if err != nil && err == sql.ErrNoRows {
|
||||
LocalError("This user no longer exists!",w,r,user)
|
||||
return
|
||||
} else if err != nil {
|
||||
InternalError(err,w,r)
|
||||
return
|
||||
}
|
||||
|
||||
http.Redirect(w,r,"/user/" + strconv.Itoa(uid),http.StatusSeeOther)
|
||||
}
|
||||
|
||||
|
@ -724,9 +727,8 @@ func route_activate(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
var uname string
|
||||
var active bool
|
||||
err = db.QueryRow("select `name`,`active` from users where `uid` = ?", uid).Scan(&uname, &active)
|
||||
err = get_user_active_stmt.QueryRow(uid).Scan(&active)
|
||||
if err == sql.ErrNoRows {
|
||||
LocalError("The account you're trying to activate no longer exists.",w,r,user)
|
||||
return
|
||||
|
|
45
mysql.go
45
mysql.go
|
@ -16,19 +16,12 @@ 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 add_subscription_stmt *sql.Stmt
|
||||
var delete_reply_stmt *sql.Stmt
|
||||
var delete_topic_stmt *sql.Stmt
|
||||
var get_activity_feed_by_watcher_stmt *sql.Stmt
|
||||
var get_activity_count_by_watcher_stmt *sql.Stmt
|
||||
var add_email_stmt *sql.Stmt
|
||||
var update_email_stmt *sql.Stmt
|
||||
var verify_email_stmt *sql.Stmt
|
||||
var delete_profile_reply_stmt *sql.Stmt
|
||||
var update_email_stmt, verify_email_stmt *sql.Stmt
|
||||
|
||||
var forum_entry_exists_stmt *sql.Stmt
|
||||
var group_entry_exists_stmt *sql.Stmt
|
||||
var delete_forum_perms_by_forum_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
|
||||
|
@ -86,24 +79,6 @@ func init_database() (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing add_subscription statement.")
|
||||
add_subscription_stmt, err = db.Prepare("INSERT INTO activity_subscriptions(user,targetID,targetType,level) VALUES(?,?,?,2)")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing delete_reply statement.")
|
||||
delete_reply_stmt, err = db.Prepare("DELETE FROM replies WHERE rid = ?")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing delete_topic statement.")
|
||||
delete_topic_stmt, err = db.Prepare("DELETE FROM topics WHERE tid = ?")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing get_activity_feed_by_watcher statement.")
|
||||
get_activity_feed_by_watcher_stmt, err = db.Prepare("SELECT activity_stream_matches.asid, activity_stream.actor, activity_stream.targetUser, activity_stream.event, activity_stream.elementType, activity_stream.elementID FROM `activity_stream_matches` INNER JOIN `activity_stream` ON activity_stream_matches.asid = activity_stream.asid AND activity_stream_matches.watcher != activity_stream.actor WHERE `watcher` = ? ORDER BY activity_stream.asid ASC LIMIT 8")
|
||||
if err != nil {
|
||||
|
@ -116,12 +91,6 @@ func init_database() (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing add_email statement.")
|
||||
add_email_stmt, err = db.Prepare("INSERT INTO emails(`email`,`uid`,`validated`,`token`) VALUES(?,?,?,?)")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing update_email statement.")
|
||||
update_email_stmt, err = db.Prepare("UPDATE emails SET email = ?, uid = ?, validated = ?, token = ? WHERE email = ?")
|
||||
if err != nil {
|
||||
|
@ -134,12 +103,6 @@ func init_database() (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing delete_profile_reply statement.")
|
||||
delete_profile_reply_stmt, err = db.Prepare("DELETE FROM users_replies WHERE rid = ?")
|
||||
if err != nil {
|
||||
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 {
|
||||
|
@ -152,12 +115,6 @@ func init_database() (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing delete_forum_perms_by_forum statement.")
|
||||
delete_forum_perms_by_forum_stmt, err = db.Prepare("DELETE FROM forums_permissions WHERE fid = ?")
|
||||
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 {
|
||||
|
|
|
@ -32,5 +32,9 @@ func(hub *WS_Hub) push_alert(_ int, _ string, _ string, _ int, _ int, _ int) err
|
|||
return ws_nouser
|
||||
}
|
||||
|
||||
func(hub *WS_Hub) push_alerts(_ []int, _ string, _ string, _ int, _ int, _ int) error {
|
||||
return ws_nouser
|
||||
}
|
||||
|
||||
func route_websockets(_ http.ResponseWriter, _ *http.Request) {
|
||||
}
|
||||
|
|
|
@ -1030,7 +1030,6 @@ func route_panel_groups(w http.ResponseWriter, r *http.Request){
|
|||
}
|
||||
|
||||
can_edit = user.Perms.EditGroup && (!group.Is_Admin || user.Perms.EditGroupAdmin) && (!group.Is_Mod || user.Perms.EditGroupSuperMod)
|
||||
|
||||
groupList = append(groupList, GroupAdmin{group.ID,group.Name,rank,rank_class,can_edit,can_delete})
|
||||
}
|
||||
//fmt.Printf("%+v\n", groupList)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
var form_vars = {};
|
||||
var alertList = [];
|
||||
var alertCount = 0;
|
||||
var conn;
|
||||
|
||||
function post_link(event)
|
||||
{
|
||||
|
@ -345,7 +346,7 @@ $(document).ready(function(){
|
|||
$(".menu_alerts").click(function(event) {
|
||||
event.stopPropagation();
|
||||
if($(this).hasClass("selectedAlert")) return;
|
||||
load_alerts($(this));
|
||||
if(!conn) load_alerts($(this));
|
||||
this.className += " selectedAlert";
|
||||
document.getElementById("back").className += " alertActive"
|
||||
});
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
/* WIP Under Construction */
|
||||
package main
|
||||
|
||||
//import "fmt"
|
||||
import "strings"
|
||||
import "log"
|
||||
import "os"
|
||||
|
||||
var db_registry []DB_Adapter
|
||||
var blank_order []DB_Order
|
||||
|
@ -40,6 +37,7 @@ type DB_Joiner struct
|
|||
LeftColumn string
|
||||
RightTable string
|
||||
RightColumn string
|
||||
Operator string
|
||||
}
|
||||
|
||||
type DB_Order struct
|
||||
|
@ -63,9 +61,13 @@ type DB_Adapter interface {
|
|||
simple_insert(string,string,string,string) error
|
||||
simple_replace(string,string,string,string) error
|
||||
simple_update(string,string,string,string) error
|
||||
simple_delete(string,string,string) error
|
||||
purge(string,string) error
|
||||
simple_select(string,string,string,string,string/*,int,int*/) error
|
||||
simple_left_join(string,string,string,string,string,string,string/*,int,int*/) error
|
||||
simple_inner_join(string,string,string,string,string,string,string/*,int,int*/) error
|
||||
write() error
|
||||
|
||||
// TO-DO: Add a simple query builder
|
||||
}
|
||||
|
||||
|
@ -83,7 +85,11 @@ func write_statements(adapter DB_Adapter) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = write_joins(adapter)
|
||||
err = write_left_joins(adapter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = write_inner_joins(adapter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -99,6 +105,10 @@ func write_statements(adapter DB_Adapter) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = write_deletes(adapter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -108,7 +118,7 @@ func write_selects(adapter DB_Adapter) error {
|
|||
|
||||
adapter.simple_select("get_full_user","users","name, group, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, last_ip","uid = ?","")
|
||||
|
||||
adapter.simple_select("get_topic","topics","title, content, createdBy, createdAt, is_closed, sticky, parentID, ipaddress, postCount, likeCount","tid = ?","")
|
||||
adapter.simple_select("get_topic","topics","title, content, createdBy, createdAt, is_closed, sticky, parentID, ipaddress, postCount, likeCount, data","tid = ?","")
|
||||
|
||||
adapter.simple_select("get_reply","replies","content, createdBy, createdAt, lastEdit, lastEditBy, ipaddress, likeCount","rid = ?","")
|
||||
|
||||
|
@ -145,24 +155,40 @@ func write_selects(adapter DB_Adapter) error {
|
|||
|
||||
adapter.simple_select("get_user_name","users","name","uid = ?","")
|
||||
|
||||
adapter.simple_select("get_user_rank","users","group, is_super_admin","uid = ?","")
|
||||
|
||||
adapter.simple_select("get_user_active","users","active","uid = ?","")
|
||||
|
||||
adapter.simple_select("get_user_group","users","group","uid = ?","")
|
||||
|
||||
adapter.simple_select("get_emails_by_user","emails","email, validated","uid = ?","")
|
||||
|
||||
adapter.simple_select("get_topic_basic","topics","title, content","tid = ?","")
|
||||
|
||||
adapter.simple_select("get_activity_entry","activity_stream","actor, targetUser, event, elementType, elementID","asid = ?","")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func write_joins(adapter DB_Adapter) error {
|
||||
func write_left_joins(adapter DB_Adapter) error {
|
||||
adapter.simple_left_join("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.simple_left_join("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.simple_left_join("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","replies.tid = topics.tid","rid = ?","")
|
||||
adapter.simple_left_join("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.simple_left_join("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.simple_left_join("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.simple_left_join("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 DB_Adapter) error {
|
||||
adapter.simple_inner_join("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
|
||||
}
|
||||
|
||||
|
@ -185,8 +211,12 @@ func write_inserts(adapter DB_Adapter) error {
|
|||
// create_account_stmt, err = db.Prepare("INSERT INTO
|
||||
adapter.simple_insert("register","users","name, email, password, salt, group, is_super_admin, session, active, message","?,?,?,?,?,0,?,?,''")
|
||||
|
||||
adapter.simple_insert("add_email","emails","email, uid, validated, token","?,?,?,?")
|
||||
|
||||
adapter.simple_insert("create_profile_reply","users_replies","uid,content,parsed_content,createdAt,createdBy","?,?,?,NOW(),?")
|
||||
|
||||
adapter.simple_insert("add_subscription","activity_subscriptions","user,targetID,targetType,level","?,?,?,2")
|
||||
|
||||
adapter.simple_insert("create_forum","forums","name, desc, active, preset","?,?,?,?")
|
||||
|
||||
adapter.simple_insert("add_forum_perms_to_forum","forums_permissions","gid,fid,preset,permissions","?,?,?,?")
|
||||
|
@ -286,335 +316,15 @@ func write_updates(adapter DB_Adapter) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func _process_columns(colstr string) (columns []DB_Column) {
|
||||
if colstr == "" {
|
||||
return columns
|
||||
}
|
||||
colstr = strings.Replace(colstr," as "," AS ",-1)
|
||||
for _, segment := range strings.Split(colstr,",") {
|
||||
var outcol DB_Column
|
||||
dothalves := strings.Split(strings.TrimSpace(segment),".")
|
||||
func write_deletes(adapter DB_Adapter) error {
|
||||
adapter.simple_delete("delete_reply","replies","rid = ?")
|
||||
|
||||
var halves []string
|
||||
if len(dothalves) == 2 {
|
||||
outcol.Table = dothalves[0]
|
||||
halves = strings.Split(dothalves[1]," AS ")
|
||||
} else {
|
||||
halves = strings.Split(dothalves[0]," AS ")
|
||||
}
|
||||
|
||||
halves[0] = strings.TrimSpace(halves[0])
|
||||
if len(halves) == 2 {
|
||||
outcol.Alias = strings.TrimSpace(halves[1])
|
||||
}
|
||||
if halves[0][len(halves[0]) - 1] == ')' {
|
||||
outcol.Type = "function"
|
||||
} else {
|
||||
outcol.Type = "column"
|
||||
}
|
||||
|
||||
outcol.Left = halves[0]
|
||||
columns = append(columns,outcol)
|
||||
}
|
||||
return columns
|
||||
}
|
||||
|
||||
func _process_orderby(orderstr string) (order []DB_Order) {
|
||||
if orderstr == "" {
|
||||
return order
|
||||
}
|
||||
for _, segment := range strings.Split(orderstr,",") {
|
||||
var outorder DB_Order
|
||||
halves := strings.Split(strings.TrimSpace(segment)," ")
|
||||
if len(halves) != 2 {
|
||||
continue
|
||||
}
|
||||
outorder.Column = halves[0]
|
||||
outorder.Order = strings.ToLower(halves[1])
|
||||
order = append(order,outorder)
|
||||
}
|
||||
return order
|
||||
}
|
||||
|
||||
func _process_joiner(joinstr string) (joiner []DB_Joiner) {
|
||||
if joinstr == "" {
|
||||
return joiner
|
||||
}
|
||||
joinstr = strings.Replace(joinstr," on "," ON ",-1)
|
||||
joinstr = strings.Replace(joinstr," and "," AND ",-1)
|
||||
for _, segment := range strings.Split(joinstr," AND ") {
|
||||
var outjoin DB_Joiner
|
||||
halves := strings.Split(segment,"=")
|
||||
if len(halves) != 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
left_column := strings.Split(halves[0],".")
|
||||
right_column := strings.Split(halves[1],".")
|
||||
outjoin.LeftTable = strings.TrimSpace(left_column[0])
|
||||
outjoin.RightTable = strings.TrimSpace(right_column[0])
|
||||
outjoin.LeftColumn = strings.TrimSpace(left_column[1])
|
||||
outjoin.RightColumn = strings.TrimSpace(right_column[1])
|
||||
|
||||
joiner = append(joiner,outjoin)
|
||||
}
|
||||
return joiner
|
||||
}
|
||||
|
||||
// TO-DO: Add support for keywords like BETWEEN. We'll probably need an arbitrary expression parser like with the update setters.
|
||||
func _process_where(wherestr string) (where []DB_Where) {
|
||||
if wherestr == "" {
|
||||
return where
|
||||
}
|
||||
wherestr = strings.Replace(wherestr," and "," AND ",-1)
|
||||
for _, segment := range strings.Split(wherestr," AND ") {
|
||||
// TO-DO: Subparse the contents of a function and spit out a DB_Function struct
|
||||
var outwhere DB_Where
|
||||
var parseOffset int
|
||||
var left, right string
|
||||
adapter.simple_delete("delete_topic","topics","tid = ?")
|
||||
|
||||
|
||||
left, parseOffset = _get_identifier(segment, parseOffset)
|
||||
outwhere.Operator, parseOffset = _get_operator(segment, parseOffset + 1)
|
||||
right, parseOffset = _get_identifier(segment, parseOffset + 1)
|
||||
outwhere.LeftType = _get_identifier_type(left)
|
||||
outwhere.RightType = _get_identifier_type(right)
|
||||
adapter.simple_delete("delete_profile_reply","users_replies","rid = ?")
|
||||
|
||||
left_operand := strings.Split(left,".")
|
||||
right_operand := strings.Split(right,".")
|
||||
adapter.simple_delete("delete_forum_perms_by_forum","forums_permissions","fid = ?")
|
||||
|
||||
if len(left_operand) == 2 {
|
||||
outwhere.LeftTable = strings.TrimSpace(left_operand[0])
|
||||
outwhere.LeftColumn = strings.TrimSpace(left_operand[1])
|
||||
} else {
|
||||
outwhere.LeftColumn = strings.TrimSpace(left_operand[0])
|
||||
}
|
||||
|
||||
if len(right_operand) == 2 {
|
||||
outwhere.RightTable = strings.TrimSpace(right_operand[0])
|
||||
outwhere.RightColumn = strings.TrimSpace(right_operand[1])
|
||||
} else {
|
||||
outwhere.RightColumn = strings.TrimSpace(right_operand[0])
|
||||
}
|
||||
|
||||
where = append(where,outwhere)
|
||||
}
|
||||
return where
|
||||
}
|
||||
|
||||
func _process_set(setstr string) (setter []DB_Setter) {
|
||||
if setstr == "" {
|
||||
return setter
|
||||
}
|
||||
//fmt.Println("setstr",setstr)
|
||||
|
||||
// First pass, splitting the string by commas while ignoring the innards of functions
|
||||
var setset []string
|
||||
var buffer string
|
||||
var last_item int
|
||||
setstr += ","
|
||||
for i := 0; i < len(setstr); i++ {
|
||||
if setstr[i] == '(' {
|
||||
i = _skip_function_call(setstr,i-1)
|
||||
setset = append(setset,setstr[last_item:i+1])
|
||||
buffer = ""
|
||||
last_item = i + 2
|
||||
} else if setstr[i] == ',' && buffer != "" {
|
||||
setset = append(setset,buffer)
|
||||
buffer = ""
|
||||
last_item = i + 1
|
||||
} else if (setstr[i] > 32) && setstr[i] != ',' && setstr[i] != ')' {
|
||||
buffer += string(setstr[i])
|
||||
}
|
||||
}
|
||||
|
||||
// Second pass. Break this setitem into manageable chunks
|
||||
buffer = ""
|
||||
for _, setitem := range setset {
|
||||
var tmp_setter DB_Setter
|
||||
halves := strings.Split(setitem,"=")
|
||||
if len(halves) != 2 {
|
||||
continue
|
||||
}
|
||||
tmp_setter.Column = strings.TrimSpace(halves[0])
|
||||
|
||||
halves[1] += ")"
|
||||
var optype int // 0: None, 1: Number, 2: Column, 3: Function, 4: String, 5: Operator
|
||||
//fmt.Println("halves[1]",halves[1])
|
||||
for i := 0; i < len(halves[1]); i++ {
|
||||
char := halves[1][i]
|
||||
//fmt.Println("optype",optype)
|
||||
switch(optype) {
|
||||
case 0: // unknown
|
||||
if ('0' <= char && char <= '9') {
|
||||
optype = 1
|
||||
buffer = string(char)
|
||||
} else if ('a' <= char && char <= 'z') || ('A' <= char && char <= 'Z') {
|
||||
optype = 2
|
||||
buffer = string(char)
|
||||
} else if char == '\'' {
|
||||
optype = 4
|
||||
} else if _is_op_byte(char) {
|
||||
optype = 5
|
||||
buffer = string(char)
|
||||
} else if char == '?' {
|
||||
//fmt.Println("Expr:","?")
|
||||
tmp_setter.Expr = append(tmp_setter.Expr,DB_Token{"?","substitute"})
|
||||
}
|
||||
case 1: // number
|
||||
if ('0' <= char && char <= '9') {
|
||||
buffer += string(char)
|
||||
} else {
|
||||
optype = 0
|
||||
i--
|
||||
//fmt.Println("Expr:",buffer)
|
||||
tmp_setter.Expr = append(tmp_setter.Expr,DB_Token{buffer,"number"})
|
||||
}
|
||||
case 2: // column
|
||||
if ('a' <= char && char <= 'z') || ('A' <= char && char <= 'Z') {
|
||||
buffer += string(char)
|
||||
} else if char == '(' {
|
||||
optype = 3
|
||||
i--
|
||||
} else {
|
||||
optype = 0
|
||||
i--
|
||||
//fmt.Println("Expr:",buffer)
|
||||
tmp_setter.Expr = append(tmp_setter.Expr,DB_Token{buffer,"column"})
|
||||
}
|
||||
case 3: // function
|
||||
var pre_i int = i
|
||||
//fmt.Println("buffer",buffer)
|
||||
//fmt.Println("len(halves)",len(halves[1]))
|
||||
//fmt.Println("pre_i",string(halves[1][pre_i]))
|
||||
//fmt.Println("msg prior to pre_i",halves[1][0:pre_i])
|
||||
i = _skip_function_call(halves[1],i-1)
|
||||
//fmt.Println("i",i)
|
||||
//fmt.Println("msg prior to i-1",halves[1][0:i-1])
|
||||
//fmt.Println("string(i-1)",string(halves[1][i-1]))
|
||||
//fmt.Println("string(i)",string(halves[1][i]))
|
||||
buffer += halves[1][pre_i:i] + string(halves[1][i])
|
||||
//fmt.Println("Expr:",buffer)
|
||||
tmp_setter.Expr = append(tmp_setter.Expr,DB_Token{buffer,"function"})
|
||||
optype = 0
|
||||
case 4: // string
|
||||
if char != '\'' {
|
||||
buffer += string(char)
|
||||
} else {
|
||||
optype = 0
|
||||
//fmt.Println("Expr:",buffer)
|
||||
tmp_setter.Expr = append(tmp_setter.Expr,DB_Token{buffer,"string"})
|
||||
}
|
||||
case 5: // operator
|
||||
if _is_op_byte(char) {
|
||||
buffer += string(char)
|
||||
} else {
|
||||
optype = 0
|
||||
i--
|
||||
//fmt.Println("Expr:",buffer)
|
||||
tmp_setter.Expr = append(tmp_setter.Expr,DB_Token{buffer,"operator"})
|
||||
}
|
||||
}
|
||||
}
|
||||
setter = append(setter,tmp_setter)
|
||||
}
|
||||
//fmt.Println("setter",setter)
|
||||
return setter
|
||||
}
|
||||
|
||||
func _is_op_byte(char byte) bool {
|
||||
return char == '<' || char == '>' || char == '=' || char == '!' || char == '*' || char == '%' || char == '+' || char == '-' || char == '/'
|
||||
}
|
||||
|
||||
func _process_fields(fieldstr string) (fields []DB_Field) {
|
||||
if fieldstr == "" {
|
||||
return fields
|
||||
}
|
||||
var buffer string
|
||||
var last_item int
|
||||
fieldstr += ","
|
||||
for i := 0; i < len(fieldstr); i++ {
|
||||
if fieldstr[i] == '(' {
|
||||
i = _skip_function_call(fieldstr,i-1)
|
||||
fields = append(fields,DB_Field{Name:fieldstr[last_item:i+1],Type:_get_identifier_type(fieldstr[last_item:i+1])})
|
||||
buffer = ""
|
||||
last_item = i + 2
|
||||
} else if fieldstr[i] == ',' && buffer != "" {
|
||||
fields = append(fields,DB_Field{Name:buffer,Type:_get_identifier_type(buffer)})
|
||||
buffer = ""
|
||||
last_item = i + 1
|
||||
} else if (fieldstr[i] > 32) && fieldstr[i] != ',' && fieldstr[i] != ')' {
|
||||
buffer += string(fieldstr[i])
|
||||
}
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
func _get_identifier_type(identifier string) string {
|
||||
if ('a' <= identifier[0] && identifier[0] <= 'z') || ('A' <= identifier[0] && identifier[0] <= 'Z') {
|
||||
if identifier[len(identifier) - 1] == ')' {
|
||||
return "function"
|
||||
}
|
||||
return "column"
|
||||
}
|
||||
if identifier[0] == '\'' || identifier[0] == '"' {
|
||||
return "string"
|
||||
}
|
||||
return "literal"
|
||||
}
|
||||
|
||||
func _get_identifier(segment string, startOffset int) (out string, i int) {
|
||||
segment = strings.TrimSpace(segment)
|
||||
segment += " " // Avoid overflow bugs with slicing
|
||||
for i = startOffset; i < len(segment); i++ {
|
||||
if segment[i] == '(' {
|
||||
i = _skip_function_call(segment,i)
|
||||
return strings.TrimSpace(segment[startOffset:i]), (i - 1)
|
||||
}
|
||||
if segment[i] == ' ' && i != startOffset {
|
||||
return strings.TrimSpace(segment[startOffset:i]), (i - 1)
|
||||
}
|
||||
}
|
||||
return strings.TrimSpace(segment[startOffset:]), (i - 1)
|
||||
}
|
||||
|
||||
func _get_operator(segment string, startOffset int) (out string, i int) {
|
||||
segment = strings.TrimSpace(segment)
|
||||
segment += " " // Avoid overflow bugs with slicing
|
||||
for i = startOffset; i < len(segment); i++ {
|
||||
if segment[i] == ' ' && i != startOffset {
|
||||
return strings.TrimSpace(segment[startOffset:i]), (i - 1)
|
||||
}
|
||||
}
|
||||
return strings.TrimSpace(segment[startOffset:]), (i - 1)
|
||||
}
|
||||
|
||||
func _skip_function_call(data string, index int) int {
|
||||
var brace_count int
|
||||
for ;index < len(data); index++{
|
||||
char := data[index]
|
||||
if char == '(' {
|
||||
brace_count++
|
||||
} else if char == ')' {
|
||||
brace_count--
|
||||
if brace_count == 0 {
|
||||
return index
|
||||
}
|
||||
}
|
||||
}
|
||||
return index
|
||||
}
|
||||
|
||||
func write_file(name string, content string) (err error) {
|
||||
f, err := os.Create(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = f.WriteString(content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.Sync()
|
||||
f.Close()
|
||||
return
|
||||
return nil
|
||||
}
|
|
@ -152,6 +152,53 @@ func (adapter *Mysql_Adapter) simple_update(name string, table string, set strin
|
|||
return nil
|
||||
}
|
||||
|
||||
func (adapter *Mysql_Adapter) simple_delete(name string, table string, where string) error {
|
||||
if name == "" {
|
||||
return errors.New("You need a name for this statement")
|
||||
}
|
||||
if table == "" {
|
||||
return errors.New("You need a name for this table")
|
||||
}
|
||||
if where == "" {
|
||||
return errors.New("You need to specify what data you want to delete")
|
||||
}
|
||||
|
||||
var querystr string = "DELETE FROM `" + table + "` WHERE"
|
||||
for _, loc := range _process_where(where) {
|
||||
var left, right string
|
||||
|
||||
if loc.LeftType == "column" {
|
||||
left = "`" + loc.LeftColumn + "`"
|
||||
} else {
|
||||
left = loc.LeftColumn
|
||||
}
|
||||
|
||||
if loc.RightType == "column" {
|
||||
right = "`" + loc.RightColumn + "`"
|
||||
} else {
|
||||
right = loc.RightColumn
|
||||
}
|
||||
|
||||
querystr += " " + left + " " + loc.Operator + " " + right + " AND "
|
||||
}
|
||||
querystr = querystr[0:len(querystr) - 4]
|
||||
|
||||
adapter.write_statement(name,strings.TrimSpace(querystr))
|
||||
return nil
|
||||
}
|
||||
|
||||
// We don't want to accidentally wipe tables, so we'll have a seperate method for purging tables instead
|
||||
func (adapter *Mysql_Adapter) purge(name string, table string) error {
|
||||
if name == "" {
|
||||
return errors.New("You need a name for this statement")
|
||||
}
|
||||
if table == "" {
|
||||
return errors.New("You need a name for this table")
|
||||
}
|
||||
adapter.write_statement(name,"DELETE FROM `" + table + "`")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (adapter *Mysql_Adapter) simple_select(name string, table string, columns string, where string, orderby string/*, offset int, maxCount int*/) error {
|
||||
if name == "" {
|
||||
return errors.New("You need a name for this statement")
|
||||
|
@ -253,7 +300,92 @@ func (adapter *Mysql_Adapter) simple_left_join(name string, table1 string, table
|
|||
|
||||
querystr += " FROM `" + table1 + "` LEFT JOIN `" + table2 + "` ON "
|
||||
for _, joiner := range _process_joiner(joiners) {
|
||||
querystr += "`" + joiner.LeftTable + "`.`" + joiner.LeftColumn + "`=`" + joiner.RightTable + "`.`" + joiner.RightColumn + "` AND "
|
||||
querystr += "`" + joiner.LeftTable + "`.`" + joiner.LeftColumn + "` " + joiner.Operator + " `" + joiner.RightTable + "`.`" + joiner.RightColumn + "` AND "
|
||||
}
|
||||
// Remove the trailing AND
|
||||
querystr = querystr[0:len(querystr) - 4]
|
||||
|
||||
if len(where) != 0 {
|
||||
querystr += " WHERE"
|
||||
for _, loc := range _process_where(where) {
|
||||
var left, right string
|
||||
|
||||
if loc.LeftTable != "" {
|
||||
left = "`" + loc.LeftTable + "`.`" + loc.LeftColumn + "`"
|
||||
} else if loc.LeftType == "column" {
|
||||
left = "`" + loc.LeftColumn + "`"
|
||||
} else {
|
||||
left = loc.LeftColumn
|
||||
}
|
||||
|
||||
if loc.RightTable != "" {
|
||||
right = "`" + loc.RightTable + "`.`" + loc.RightColumn + "`"
|
||||
} else if loc.RightType == "column" {
|
||||
right = "`" + loc.RightColumn + "`"
|
||||
} else {
|
||||
right = loc.RightColumn
|
||||
}
|
||||
|
||||
querystr += " " + left + " " + loc.Operator + " " + right + " AND "
|
||||
}
|
||||
querystr = querystr[0:len(querystr) - 4]
|
||||
}
|
||||
|
||||
if len(orderby) != 0 {
|
||||
querystr += " ORDER BY "
|
||||
for _, column := range _process_orderby(orderby) {
|
||||
querystr += column.Column + " " + strings.ToUpper(column.Order) + ","
|
||||
}
|
||||
querystr = querystr[0:len(querystr) - 1]
|
||||
}
|
||||
|
||||
adapter.write_statement(name,strings.TrimSpace(querystr))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (adapter *Mysql_Adapter) simple_inner_join(name string, table1 string, table2 string, columns string, joiners string, where string, orderby string/*, offset int, maxCount int*/) error {
|
||||
if name == "" {
|
||||
return errors.New("You need a name for this statement")
|
||||
}
|
||||
if table1 == "" {
|
||||
return errors.New("You need a name for the left table")
|
||||
}
|
||||
if table2 == "" {
|
||||
return errors.New("You need a name for the right table")
|
||||
}
|
||||
if len(columns) == 0 {
|
||||
return errors.New("No columns found for simple_inner_join")
|
||||
}
|
||||
if len(joiners) == 0 {
|
||||
return errors.New("No joiners found for simple_inner_join")
|
||||
}
|
||||
|
||||
var querystr string = "SELECT "
|
||||
|
||||
for _, column := range _process_columns(columns) {
|
||||
var source, alias string
|
||||
|
||||
// Escape the column names, just in case we've used a reserved keyword
|
||||
if column.Table != "" {
|
||||
source = "`" + column.Table + "`.`" + column.Left + "`"
|
||||
} else if column.Type == "function" {
|
||||
source = column.Left
|
||||
} else {
|
||||
source = "`" + column.Left + "`"
|
||||
}
|
||||
|
||||
if column.Alias != "" {
|
||||
alias = " AS `" + column.Alias + "`"
|
||||
}
|
||||
querystr += source + alias + ","
|
||||
}
|
||||
|
||||
// Remove the trailing comma
|
||||
querystr = querystr[0:len(querystr) - 1]
|
||||
|
||||
querystr += " FROM `" + table1 + "` INNER JOIN `" + table2 + "` ON "
|
||||
for _, joiner := range _process_joiner(joiners) {
|
||||
querystr += "`" + joiner.LeftTable + "`.`" + joiner.LeftColumn + "` " + joiner.Operator + " `" + joiner.RightTable + "`.`" + joiner.RightColumn + "` AND "
|
||||
}
|
||||
// Remove the trailing AND
|
||||
querystr = querystr[0:len(querystr) - 4]
|
||||
|
|
|
@ -0,0 +1,341 @@
|
|||
/* WIP Under Construction */
|
||||
package main
|
||||
|
||||
//import "fmt"
|
||||
import "strings"
|
||||
import "os"
|
||||
|
||||
func _process_columns(colstr string) (columns []DB_Column) {
|
||||
if colstr == "" {
|
||||
return columns
|
||||
}
|
||||
colstr = strings.Replace(colstr," as "," AS ",-1)
|
||||
for _, segment := range strings.Split(colstr,",") {
|
||||
var outcol DB_Column
|
||||
dothalves := strings.Split(strings.TrimSpace(segment),".")
|
||||
|
||||
var halves []string
|
||||
if len(dothalves) == 2 {
|
||||
outcol.Table = dothalves[0]
|
||||
halves = strings.Split(dothalves[1]," AS ")
|
||||
} else {
|
||||
halves = strings.Split(dothalves[0]," AS ")
|
||||
}
|
||||
|
||||
halves[0] = strings.TrimSpace(halves[0])
|
||||
if len(halves) == 2 {
|
||||
outcol.Alias = strings.TrimSpace(halves[1])
|
||||
}
|
||||
if halves[0][len(halves[0]) - 1] == ')' {
|
||||
outcol.Type = "function"
|
||||
} else {
|
||||
outcol.Type = "column"
|
||||
}
|
||||
|
||||
outcol.Left = halves[0]
|
||||
columns = append(columns,outcol)
|
||||
}
|
||||
return columns
|
||||
}
|
||||
|
||||
func _process_orderby(orderstr string) (order []DB_Order) {
|
||||
if orderstr == "" {
|
||||
return order
|
||||
}
|
||||
for _, segment := range strings.Split(orderstr,",") {
|
||||
var outorder DB_Order
|
||||
halves := strings.Split(strings.TrimSpace(segment)," ")
|
||||
if len(halves) != 2 {
|
||||
continue
|
||||
}
|
||||
outorder.Column = halves[0]
|
||||
outorder.Order = strings.ToLower(halves[1])
|
||||
order = append(order,outorder)
|
||||
}
|
||||
return order
|
||||
}
|
||||
|
||||
func _process_joiner(joinstr string) (joiner []DB_Joiner) {
|
||||
if joinstr == "" {
|
||||
return joiner
|
||||
}
|
||||
joinstr = strings.Replace(joinstr," on "," ON ",-1)
|
||||
joinstr = strings.Replace(joinstr," and "," AND ",-1)
|
||||
for _, segment := range strings.Split(joinstr," AND ") {
|
||||
var outjoin DB_Joiner
|
||||
var parseOffset int
|
||||
var left, right string
|
||||
|
||||
left, parseOffset = _get_identifier(segment, parseOffset)
|
||||
outjoin.Operator, parseOffset = _get_operator(segment, parseOffset + 1)
|
||||
right, parseOffset = _get_identifier(segment, parseOffset + 1)
|
||||
|
||||
|
||||
left_column := strings.Split(left,".")
|
||||
right_column := strings.Split(right,".")
|
||||
outjoin.LeftTable = strings.TrimSpace(left_column[0])
|
||||
outjoin.RightTable = strings.TrimSpace(right_column[0])
|
||||
outjoin.LeftColumn = strings.TrimSpace(left_column[1])
|
||||
outjoin.RightColumn = strings.TrimSpace(right_column[1])
|
||||
|
||||
joiner = append(joiner,outjoin)
|
||||
}
|
||||
return joiner
|
||||
}
|
||||
|
||||
// TO-DO: Add support for keywords like BETWEEN. We'll probably need an arbitrary expression parser like with the update setters.
|
||||
func _process_where(wherestr string) (where []DB_Where) {
|
||||
if wherestr == "" {
|
||||
return where
|
||||
}
|
||||
wherestr = strings.Replace(wherestr," and "," AND ",-1)
|
||||
for _, segment := range strings.Split(wherestr," AND ") {
|
||||
// TO-DO: Subparse the contents of a function and spit out a DB_Function struct
|
||||
var outwhere DB_Where
|
||||
var parseOffset int
|
||||
var left, right string
|
||||
|
||||
left, parseOffset = _get_identifier(segment, parseOffset)
|
||||
outwhere.Operator, parseOffset = _get_operator(segment, parseOffset + 1)
|
||||
right, parseOffset = _get_identifier(segment, parseOffset + 1)
|
||||
outwhere.LeftType = _get_identifier_type(left)
|
||||
outwhere.RightType = _get_identifier_type(right)
|
||||
|
||||
left_operand := strings.Split(left,".")
|
||||
right_operand := strings.Split(right,".")
|
||||
|
||||
if len(left_operand) == 2 {
|
||||
outwhere.LeftTable = strings.TrimSpace(left_operand[0])
|
||||
outwhere.LeftColumn = strings.TrimSpace(left_operand[1])
|
||||
} else {
|
||||
outwhere.LeftColumn = strings.TrimSpace(left_operand[0])
|
||||
}
|
||||
|
||||
if len(right_operand) == 2 {
|
||||
outwhere.RightTable = strings.TrimSpace(right_operand[0])
|
||||
outwhere.RightColumn = strings.TrimSpace(right_operand[1])
|
||||
} else {
|
||||
outwhere.RightColumn = strings.TrimSpace(right_operand[0])
|
||||
}
|
||||
|
||||
where = append(where,outwhere)
|
||||
}
|
||||
return where
|
||||
}
|
||||
|
||||
func _process_set(setstr string) (setter []DB_Setter) {
|
||||
if setstr == "" {
|
||||
return setter
|
||||
}
|
||||
//fmt.Println("setstr",setstr)
|
||||
|
||||
// First pass, splitting the string by commas while ignoring the innards of functions
|
||||
var setset []string
|
||||
var buffer string
|
||||
var last_item int
|
||||
setstr += ","
|
||||
for i := 0; i < len(setstr); i++ {
|
||||
if setstr[i] == '(' {
|
||||
i = _skip_function_call(setstr,i-1)
|
||||
setset = append(setset,setstr[last_item:i+1])
|
||||
buffer = ""
|
||||
last_item = i + 2
|
||||
} else if setstr[i] == ',' && buffer != "" {
|
||||
setset = append(setset,buffer)
|
||||
buffer = ""
|
||||
last_item = i + 1
|
||||
} else if (setstr[i] > 32) && setstr[i] != ',' && setstr[i] != ')' {
|
||||
buffer += string(setstr[i])
|
||||
}
|
||||
}
|
||||
|
||||
// Second pass. Break this setitem into manageable chunks
|
||||
buffer = ""
|
||||
for _, setitem := range setset {
|
||||
var tmp_setter DB_Setter
|
||||
halves := strings.Split(setitem,"=")
|
||||
if len(halves) != 2 {
|
||||
continue
|
||||
}
|
||||
tmp_setter.Column = strings.TrimSpace(halves[0])
|
||||
|
||||
halves[1] += ")"
|
||||
var optype int // 0: None, 1: Number, 2: Column, 3: Function, 4: String, 5: Operator
|
||||
//fmt.Println("halves[1]",halves[1])
|
||||
for i := 0; i < len(halves[1]); i++ {
|
||||
char := halves[1][i]
|
||||
//fmt.Println("optype",optype)
|
||||
switch(optype) {
|
||||
case 0: // unknown
|
||||
if ('0' <= char && char <= '9') {
|
||||
optype = 1
|
||||
buffer = string(char)
|
||||
} else if ('a' <= char && char <= 'z') || ('A' <= char && char <= 'Z') {
|
||||
optype = 2
|
||||
buffer = string(char)
|
||||
} else if char == '\'' {
|
||||
optype = 4
|
||||
} else if _is_op_byte(char) {
|
||||
optype = 5
|
||||
buffer = string(char)
|
||||
} else if char == '?' {
|
||||
//fmt.Println("Expr:","?")
|
||||
tmp_setter.Expr = append(tmp_setter.Expr,DB_Token{"?","substitute"})
|
||||
}
|
||||
case 1: // number
|
||||
if ('0' <= char && char <= '9') {
|
||||
buffer += string(char)
|
||||
} else {
|
||||
optype = 0
|
||||
i--
|
||||
//fmt.Println("Expr:",buffer)
|
||||
tmp_setter.Expr = append(tmp_setter.Expr,DB_Token{buffer,"number"})
|
||||
}
|
||||
case 2: // column
|
||||
if ('a' <= char && char <= 'z') || ('A' <= char && char <= 'Z') {
|
||||
buffer += string(char)
|
||||
} else if char == '(' {
|
||||
optype = 3
|
||||
i--
|
||||
} else {
|
||||
optype = 0
|
||||
i--
|
||||
//fmt.Println("Expr:",buffer)
|
||||
tmp_setter.Expr = append(tmp_setter.Expr,DB_Token{buffer,"column"})
|
||||
}
|
||||
case 3: // function
|
||||
var pre_i int = i
|
||||
//fmt.Println("buffer",buffer)
|
||||
//fmt.Println("len(halves)",len(halves[1]))
|
||||
//fmt.Println("pre_i",string(halves[1][pre_i]))
|
||||
//fmt.Println("msg prior to pre_i",halves[1][0:pre_i])
|
||||
i = _skip_function_call(halves[1],i-1)
|
||||
//fmt.Println("i",i)
|
||||
//fmt.Println("msg prior to i-1",halves[1][0:i-1])
|
||||
//fmt.Println("string(i-1)",string(halves[1][i-1]))
|
||||
//fmt.Println("string(i)",string(halves[1][i]))
|
||||
buffer += halves[1][pre_i:i] + string(halves[1][i])
|
||||
//fmt.Println("Expr:",buffer)
|
||||
tmp_setter.Expr = append(tmp_setter.Expr,DB_Token{buffer,"function"})
|
||||
optype = 0
|
||||
case 4: // string
|
||||
if char != '\'' {
|
||||
buffer += string(char)
|
||||
} else {
|
||||
optype = 0
|
||||
//fmt.Println("Expr:",buffer)
|
||||
tmp_setter.Expr = append(tmp_setter.Expr,DB_Token{buffer,"string"})
|
||||
}
|
||||
case 5: // operator
|
||||
if _is_op_byte(char) {
|
||||
buffer += string(char)
|
||||
} else {
|
||||
optype = 0
|
||||
i--
|
||||
//fmt.Println("Expr:",buffer)
|
||||
tmp_setter.Expr = append(tmp_setter.Expr,DB_Token{buffer,"operator"})
|
||||
}
|
||||
}
|
||||
}
|
||||
setter = append(setter,tmp_setter)
|
||||
}
|
||||
//fmt.Println("setter",setter)
|
||||
return setter
|
||||
}
|
||||
|
||||
func _is_op_byte(char byte) bool {
|
||||
return char == '<' || char == '>' || char == '=' || char == '!' || char == '*' || char == '%' || char == '+' || char == '-' || char == '/'
|
||||
}
|
||||
|
||||
func _process_fields(fieldstr string) (fields []DB_Field) {
|
||||
if fieldstr == "" {
|
||||
return fields
|
||||
}
|
||||
var buffer string
|
||||
var last_item int
|
||||
fieldstr += ","
|
||||
for i := 0; i < len(fieldstr); i++ {
|
||||
if fieldstr[i] == '(' {
|
||||
i = _skip_function_call(fieldstr,i-1)
|
||||
fields = append(fields,DB_Field{Name:fieldstr[last_item:i+1],Type:_get_identifier_type(fieldstr[last_item:i+1])})
|
||||
buffer = ""
|
||||
last_item = i + 2
|
||||
} else if fieldstr[i] == ',' && buffer != "" {
|
||||
fields = append(fields,DB_Field{Name:buffer,Type:_get_identifier_type(buffer)})
|
||||
buffer = ""
|
||||
last_item = i + 1
|
||||
} else if (fieldstr[i] > 32) && fieldstr[i] != ',' && fieldstr[i] != ')' {
|
||||
buffer += string(fieldstr[i])
|
||||
}
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
func _get_identifier_type(identifier string) string {
|
||||
if ('a' <= identifier[0] && identifier[0] <= 'z') || ('A' <= identifier[0] && identifier[0] <= 'Z') {
|
||||
if identifier[len(identifier) - 1] == ')' {
|
||||
return "function"
|
||||
}
|
||||
return "column"
|
||||
}
|
||||
if identifier[0] == '\'' || identifier[0] == '"' {
|
||||
return "string"
|
||||
}
|
||||
return "literal"
|
||||
}
|
||||
|
||||
func _get_identifier(segment string, startOffset int) (out string, i int) {
|
||||
segment = strings.TrimSpace(segment)
|
||||
segment += " " // Avoid overflow bugs with slicing
|
||||
for i = startOffset; i < len(segment); i++ {
|
||||
if segment[i] == '(' {
|
||||
i = _skip_function_call(segment,i)
|
||||
return strings.TrimSpace(segment[startOffset:i]), (i - 1)
|
||||
}
|
||||
if (segment[i] == ' ' || _is_op_byte(segment[i])) && i != startOffset {
|
||||
return strings.TrimSpace(segment[startOffset:i]), (i - 1)
|
||||
}
|
||||
}
|
||||
return strings.TrimSpace(segment[startOffset:]), (i - 1)
|
||||
}
|
||||
|
||||
func _get_operator(segment string, startOffset int) (out string, i int) {
|
||||
segment = strings.TrimSpace(segment)
|
||||
segment += " " // Avoid overflow bugs with slicing
|
||||
for i = startOffset; i < len(segment); i++ {
|
||||
if !_is_op_byte(segment[i]) && i != startOffset {
|
||||
return strings.TrimSpace(segment[startOffset:i]), (i - 1)
|
||||
}
|
||||
}
|
||||
return strings.TrimSpace(segment[startOffset:]), (i - 1)
|
||||
}
|
||||
|
||||
func _skip_function_call(data string, index int) int {
|
||||
var brace_count int
|
||||
for ;index < len(data); index++{
|
||||
char := data[index]
|
||||
if char == '(' {
|
||||
brace_count++
|
||||
} else if char == ')' {
|
||||
brace_count--
|
||||
if brace_count == 0 {
|
||||
return index
|
||||
}
|
||||
}
|
||||
}
|
||||
return index
|
||||
}
|
||||
|
||||
func write_file(name string, content string) (err error) {
|
||||
f, err := os.Create(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = f.WriteString(content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.Sync()
|
||||
f.Close()
|
||||
return
|
||||
}
|
89
routes.go
89
routes.go
|
@ -3,7 +3,7 @@ package main
|
|||
|
||||
import (
|
||||
"log"
|
||||
"fmt"
|
||||
//"fmt"
|
||||
"strconv"
|
||||
"bytes"
|
||||
"regexp"
|
||||
|
@ -142,7 +142,7 @@ func route_topics(w http.ResponseWriter, r *http.Request){
|
|||
|
||||
/*topicItem.CreatedAt, err = relative_time(topicItem.CreatedAt)
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
replyItem.CreatedAt = ""
|
||||
}*/
|
||||
topicItem.LastReplyAt, err = relative_time(topicItem.LastReplyAt)
|
||||
if err != nil {
|
||||
|
@ -347,6 +347,11 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
|
|||
}
|
||||
}*/
|
||||
|
||||
topic.CreatedAt, err = relative_time(topic.CreatedAt)
|
||||
if err != nil {
|
||||
topic.CreatedAt = ""
|
||||
}
|
||||
|
||||
// Calculate the offset
|
||||
last_page := int(topic.PostCount / items_per_page) + 1
|
||||
if page > 1 {
|
||||
|
@ -407,6 +412,11 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
|
|||
}
|
||||
}*/
|
||||
|
||||
replyItem.CreatedAt, err = relative_time(replyItem.CreatedAt)
|
||||
if err != nil {
|
||||
replyItem.CreatedAt = ""
|
||||
}
|
||||
|
||||
// We really shouldn't have inline HTML, we should do something about this...
|
||||
if replyItem.ActionType != "" {
|
||||
switch(replyItem.ActionType) {
|
||||
|
@ -671,9 +681,7 @@ func route_create_reply(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
var topic_name string
|
||||
var fid, createdBy int
|
||||
err = db.QueryRow("select title, parentID, createdBy from topics where tid = ?",tid).Scan(&topic_name,&fid,&createdBy)
|
||||
topic, err := topics.CascadeGet(tid)
|
||||
if err == sql.ErrNoRows {
|
||||
PreError("Couldn't find the parent topic",w,r)
|
||||
return
|
||||
|
@ -682,7 +690,7 @@ func route_create_reply(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
user, ok := SimpleForumSessionCheck(w,r,fid)
|
||||
user, ok := SimpleForumSessionCheck(w,r,topic.ParentID)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -710,13 +718,13 @@ func route_create_reply(w http.ResponseWriter, r *http.Request) {
|
|||
InternalError(err,w,r)
|
||||
return
|
||||
}
|
||||
_, err = update_forum_cache_stmt.Exec(topic_name,tid,user.Name,user.ID,1)
|
||||
_, err = update_forum_cache_stmt.Exec(topic.Title,tid,user.Name,user.ID,1)
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
return
|
||||
}
|
||||
|
||||
res, err := add_activity_stmt.Exec(user.ID,createdBy,"reply","topic",tid)
|
||||
res, err := add_activity_stmt.Exec(user.ID,topic.CreatedBy,"reply","topic",tid)
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
return
|
||||
|
@ -733,9 +741,14 @@ func route_create_reply(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
// Alert the subscribers about this post without blocking this post from being posted
|
||||
if enable_websockets {
|
||||
go notify_watchers(lastId)
|
||||
}
|
||||
|
||||
// Reload the topic...
|
||||
err = topics.Load(tid)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
if err != nil && err == sql.ErrNoRows {
|
||||
LocalError("The destination no longer exists",w,r,user)
|
||||
return
|
||||
} else if err != nil {
|
||||
|
@ -764,8 +777,7 @@ func route_like_topic(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
var words, fid, createdBy int
|
||||
err = db.QueryRow("select parentID, words, createdBy from topics where tid = ?", tid).Scan(&fid,&words,&createdBy)
|
||||
topic, err := topics.CascadeGet(tid)
|
||||
if err == sql.ErrNoRows {
|
||||
PreError("The requested topic doesn't exist.",w,r)
|
||||
return
|
||||
|
@ -774,7 +786,7 @@ func route_like_topic(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
user, ok := SimpleForumSessionCheck(w,r,fid)
|
||||
user, ok := SimpleForumSessionCheck(w,r,topic.ParentID)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -783,7 +795,7 @@ func route_like_topic(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
if createdBy == user.ID {
|
||||
if topic.CreatedBy == user.ID {
|
||||
LocalError("You can't like your own topics",w,r,user)
|
||||
return
|
||||
}
|
||||
|
@ -797,7 +809,7 @@ func route_like_topic(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
_, err = users.CascadeGet(createdBy)
|
||||
_, err = users.CascadeGet(topic.CreatedBy)
|
||||
if err != nil && err == sql.ErrNoRows {
|
||||
LocalError("The target user doesn't exist",w,r,user)
|
||||
return
|
||||
|
@ -819,7 +831,7 @@ func route_like_topic(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
res, err := add_activity_stmt.Exec(user.ID,createdBy,"like","topic",tid)
|
||||
res, err := add_activity_stmt.Exec(user.ID,topic.CreatedBy,"like","topic",tid)
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
return
|
||||
|
@ -830,18 +842,18 @@ func route_like_topic(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
_, err = notify_one_stmt.Exec(createdBy,lastId)
|
||||
_, err = notify_one_stmt.Exec(topic.CreatedBy,lastId)
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
return
|
||||
}
|
||||
|
||||
// Live alerts, if the poster is online and WebSockets is enabled
|
||||
_ = ws_hub.push_alert(createdBy,"like","topic",user.ID,createdBy,tid)
|
||||
_ = ws_hub.push_alert(topic.CreatedBy,"like","topic",user.ID,topic.CreatedBy,tid)
|
||||
|
||||
// Reload the topic...
|
||||
err = topics.Load(tid)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
if err != nil && err == sql.ErrNoRows {
|
||||
LocalError("The liked topic no longer exists",w,r,user)
|
||||
return
|
||||
} else if err != nil {
|
||||
|
@ -948,11 +960,7 @@ func route_reply_like_submit(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
// Live alerts, if the poster is online and WebSockets is enabled
|
||||
fmt.Println("Calling push_alert")
|
||||
err = ws_hub.push_alert(createdBy,"like","post",user.ID,createdBy,rid)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
_ = ws_hub.push_alert(createdBy,"like","post",user.ID,createdBy,rid)
|
||||
|
||||
http.Redirect(w,r,"/topic/" + strconv.Itoa(tid),http.StatusSeeOther)
|
||||
}
|
||||
|
@ -1031,7 +1039,7 @@ func route_report_submit(w http.ResponseWriter, r *http.Request, sitem_id string
|
|||
|
||||
var fid int = 1
|
||||
var tid int
|
||||
var title, content, data string
|
||||
var title, content string
|
||||
if item_type == "reply" {
|
||||
err = db.QueryRow("select tid, content from replies where rid = ?", item_id).Scan(&tid, &content)
|
||||
if err == sql.ErrNoRows {
|
||||
|
@ -1042,20 +1050,21 @@ func route_report_submit(w http.ResponseWriter, r *http.Request, sitem_id string
|
|||
return
|
||||
}
|
||||
|
||||
err = db.QueryRow("select title, data from topics where tid = ?",tid).Scan(&title,&data)
|
||||
topic, err := topics.CascadeGet(tid)
|
||||
if err == sql.ErrNoRows {
|
||||
LocalError("We were unable to find the topic which the reported post is supposed to be in",w,r,user)
|
||||
LocalError("We weren't able to find the topic the reported post is supposed to be in",w,r,user)
|
||||
return
|
||||
} else if err != nil {
|
||||
InternalError(err,w,r)
|
||||
return
|
||||
}
|
||||
title = "Reply: " + title
|
||||
|
||||
title = "Reply: " + topic.Title
|
||||
content = content + "\n\nOriginal Post: #rid-" + strconv.Itoa(item_id)
|
||||
} else if item_type == "user-reply" {
|
||||
err = db.QueryRow("select uid, content from users_replies where rid = ?", item_id).Scan(&tid, &content)
|
||||
if err == sql.ErrNoRows {
|
||||
LocalError("We were unable to find the reported post",w,r,user)
|
||||
LocalError("We weren't able to find the reported post",w,r,user)
|
||||
return
|
||||
} else if err != nil {
|
||||
InternalError(err,w,r)
|
||||
|
@ -1064,7 +1073,7 @@ func route_report_submit(w http.ResponseWriter, r *http.Request, sitem_id string
|
|||
|
||||
err = get_user_name_stmt.QueryRow(tid).Scan(&title)
|
||||
if err == sql.ErrNoRows {
|
||||
LocalError("We were unable to find the profile which the reported post is supposed to be on",w,r,user)
|
||||
LocalError("We weren't able to find the profile the reported post is supposed to be on",w,r,user)
|
||||
return
|
||||
} else if err != nil {
|
||||
InternalError(err,w,r)
|
||||
|
@ -1315,8 +1324,8 @@ func route_account_own_edit_avatar_submit(w http.ResponseWriter, r *http.Request
|
|||
LocalError("This user no longer exists!",w,r,user)
|
||||
return
|
||||
}
|
||||
noticeList = append(noticeList, "Your avatar was successfully updated")
|
||||
|
||||
noticeList = append(noticeList, "Your avatar was successfully updated")
|
||||
pi := Page{"Edit Avatar",user,noticeList,tList,nil}
|
||||
templates.ExecuteTemplate(w,"account-own-edit-avatar.html", pi)
|
||||
}
|
||||
|
@ -1558,7 +1567,7 @@ func route_login_submit(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
// Emergency password reset mechanism..
|
||||
// Admin password reset mechanism...
|
||||
if salt == "" {
|
||||
if password != real_password {
|
||||
LocalError("That's not the correct password.",w,r,user)
|
||||
|
@ -1566,15 +1575,26 @@ func route_login_submit(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
// Re-encrypt the password
|
||||
SetPassword(uid, password)
|
||||
} else { // Normal login..
|
||||
SetPassword(uid, real_password)
|
||||
|
||||
// Fe-fetch the user data...
|
||||
err = login_stmt.QueryRow(username).Scan(&uid, &username, &real_password, &salt)
|
||||
if err == sql.ErrNoRows {
|
||||
LocalError("That username doesn't exist anymore.",w,r,user)
|
||||
return
|
||||
} else if err != nil {
|
||||
InternalError(err,w,r)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
password = password + salt
|
||||
if err != nil {
|
||||
InternalError(err,w,r)
|
||||
return
|
||||
}
|
||||
|
||||
err := bcrypt.CompareHashAndPassword([]byte(real_password), []byte(password))
|
||||
err = bcrypt.CompareHashAndPassword([]byte(real_password), []byte(password))
|
||||
if err == bcrypt.ErrMismatchedHashAndPassword {
|
||||
LocalError("That's not the correct password.",w,r,user)
|
||||
return
|
||||
|
@ -1582,7 +1602,6 @@ func route_login_submit(w http.ResponseWriter, r *http.Request) {
|
|||
InternalError(err,w,r)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
session, err = GenerateSafeString(sessionLength)
|
||||
if err != nil {
|
||||
|
|
|
@ -296,75 +296,83 @@ var topic_alt_42 []byte = []byte(`&type=topic" class="action_button report_item"
|
|||
`)
|
||||
var topic_alt_43 []byte = []byte(`<a href="#" title="IP Address" class="action_button action_button_right ip_item hide_on_mobile">`)
|
||||
var topic_alt_44 []byte = []byte(`</a>`)
|
||||
var topic_alt_45 []byte = []byte(`<a class="action_button action_button_right hide_on_micro">`)
|
||||
var topic_alt_46 []byte = []byte(` up</a>`)
|
||||
var topic_alt_47 []byte = []byte(`
|
||||
var topic_alt_45 []byte = []byte(`
|
||||
<a class="action_button action_button_right hide_on_mobile">`)
|
||||
var topic_alt_46 []byte = []byte(`</a>
|
||||
`)
|
||||
var topic_alt_47 []byte = []byte(`<a class="action_button action_button_right hide_on_micro">`)
|
||||
var topic_alt_48 []byte = []byte(` up</a>`)
|
||||
var topic_alt_49 []byte = []byte(`
|
||||
</div>
|
||||
</div><div style="clear:both;"></div>
|
||||
</div>
|
||||
`)
|
||||
var topic_alt_48 []byte = []byte(`
|
||||
var topic_alt_50 []byte = []byte(`
|
||||
<div class="rowitem passive deletable_block editable_parent post_item `)
|
||||
var topic_alt_49 []byte = []byte(`action_item`)
|
||||
var topic_alt_50 []byte = []byte(`">
|
||||
var topic_alt_51 []byte = []byte(`action_item`)
|
||||
var topic_alt_52 []byte = []byte(`">
|
||||
<div class="userinfo">
|
||||
<div class="avatar_item" style="background-image: url(`)
|
||||
var topic_alt_51 []byte = []byte(`), url(/static/white-dot.jpg);background-position: 0px -10px;"> </div>
|
||||
var topic_alt_53 []byte = []byte(`), url(/static/white-dot.jpg);background-position: 0px -10px;"> </div>
|
||||
<a href="/user/`)
|
||||
var topic_alt_52 []byte = []byte(`" class="the_name">`)
|
||||
var topic_alt_53 []byte = []byte(`</a>
|
||||
var topic_alt_54 []byte = []byte(`" class="the_name">`)
|
||||
var topic_alt_55 []byte = []byte(`</a>
|
||||
`)
|
||||
var topic_alt_54 []byte = []byte(`<div class="tag_block"><div class="tag_pre"></div><div class="post_tag">`)
|
||||
var topic_alt_55 []byte = []byte(`</div><div class="tag_post"></div></div>`)
|
||||
var topic_alt_56 []byte = []byte(`<div class="tag_block"><div class="tag_pre"></div><div class="post_tag post_level">Level `)
|
||||
var topic_alt_56 []byte = []byte(`<div class="tag_block"><div class="tag_pre"></div><div class="post_tag">`)
|
||||
var topic_alt_57 []byte = []byte(`</div><div class="tag_post"></div></div>`)
|
||||
var topic_alt_58 []byte = []byte(`
|
||||
var topic_alt_58 []byte = []byte(`<div class="tag_block"><div class="tag_pre"></div><div class="post_tag post_level">Level `)
|
||||
var topic_alt_59 []byte = []byte(`</div><div class="tag_post"></div></div>`)
|
||||
var topic_alt_60 []byte = []byte(`
|
||||
</div>
|
||||
<div class="content_container" `)
|
||||
var topic_alt_59 []byte = []byte(`style="margin-left: 0px;"`)
|
||||
var topic_alt_60 []byte = []byte(`>
|
||||
var topic_alt_61 []byte = []byte(`style="margin-left: 0px;"`)
|
||||
var topic_alt_62 []byte = []byte(`>
|
||||
`)
|
||||
var topic_alt_61 []byte = []byte(`
|
||||
var topic_alt_63 []byte = []byte(`
|
||||
<span class="action_icon" style="font-size: 18px;padding-right: 5px;">`)
|
||||
var topic_alt_62 []byte = []byte(`</span>
|
||||
var topic_alt_64 []byte = []byte(`</span>
|
||||
<span>`)
|
||||
var topic_alt_63 []byte = []byte(`</span>
|
||||
var topic_alt_65 []byte = []byte(`</span>
|
||||
`)
|
||||
var topic_alt_64 []byte = []byte(`
|
||||
var topic_alt_66 []byte = []byte(`
|
||||
<div class="editable_block user_content">`)
|
||||
var topic_alt_65 []byte = []byte(`</div>
|
||||
var topic_alt_67 []byte = []byte(`</div>
|
||||
<div class="button_container">
|
||||
`)
|
||||
var topic_alt_66 []byte = []byte(`<a href="/reply/like/submit/`)
|
||||
var topic_alt_67 []byte = []byte(`" class="action_button">+1</a>`)
|
||||
var topic_alt_68 []byte = []byte(`<a href="/reply/edit/submit/`)
|
||||
var topic_alt_69 []byte = []byte(`" class="action_button edit_item">Edit</a>`)
|
||||
var topic_alt_70 []byte = []byte(`<a href="/reply/delete/submit/`)
|
||||
var topic_alt_71 []byte = []byte(`" class="action_button delete_item">Delete</a>`)
|
||||
var topic_alt_72 []byte = []byte(`
|
||||
var topic_alt_68 []byte = []byte(`<a href="/reply/like/submit/`)
|
||||
var topic_alt_69 []byte = []byte(`" class="action_button">+1</a>`)
|
||||
var topic_alt_70 []byte = []byte(`<a href="/reply/edit/submit/`)
|
||||
var topic_alt_71 []byte = []byte(`" class="action_button edit_item">Edit</a>`)
|
||||
var topic_alt_72 []byte = []byte(`<a href="/reply/delete/submit/`)
|
||||
var topic_alt_73 []byte = []byte(`" class="action_button delete_item">Delete</a>`)
|
||||
var topic_alt_74 []byte = []byte(`
|
||||
<a href="/report/submit/`)
|
||||
var topic_alt_73 []byte = []byte(`?session=`)
|
||||
var topic_alt_74 []byte = []byte(`&type=reply" class="action_button report_item">Report</a>
|
||||
var topic_alt_75 []byte = []byte(`?session=`)
|
||||
var topic_alt_76 []byte = []byte(`&type=reply" class="action_button report_item">Report</a>
|
||||
`)
|
||||
var topic_alt_75 []byte = []byte(`<a href="#" title="IP Address" class="action_button action_button_right ip_item hide_on_mobile">`)
|
||||
var topic_alt_76 []byte = []byte(`</a>`)
|
||||
var topic_alt_77 []byte = []byte(`<a class="action_button action_button_right hide_on_micro">`)
|
||||
var topic_alt_78 []byte = []byte(` up</a>`)
|
||||
var topic_alt_77 []byte = []byte(`<a href="#" title="IP Address" class="action_button action_button_right ip_item hide_on_mobile">`)
|
||||
var topic_alt_78 []byte = []byte(`</a>`)
|
||||
var topic_alt_79 []byte = []byte(`
|
||||
<a class="action_button action_button_right hide_on_mobile">`)
|
||||
var topic_alt_80 []byte = []byte(`</a>
|
||||
`)
|
||||
var topic_alt_81 []byte = []byte(`<a class="action_button action_button_right hide_on_micro">`)
|
||||
var topic_alt_82 []byte = []byte(` up</a>`)
|
||||
var topic_alt_83 []byte = []byte(`
|
||||
</div>
|
||||
`)
|
||||
var topic_alt_80 []byte = []byte(`
|
||||
var topic_alt_84 []byte = []byte(`
|
||||
</div>
|
||||
<div style="clear:both;"></div>
|
||||
</div>
|
||||
`)
|
||||
var topic_alt_81 []byte = []byte(`</div>
|
||||
var topic_alt_85 []byte = []byte(`</div>
|
||||
`)
|
||||
var topic_alt_82 []byte = []byte(`
|
||||
var topic_alt_86 []byte = []byte(`
|
||||
<div class="rowblock" style="border-top: none;">
|
||||
<form action="/reply/create/" method="post">
|
||||
<input name="tid" value='`)
|
||||
var topic_alt_83 []byte = []byte(`' type="hidden" />
|
||||
var topic_alt_87 []byte = []byte(`' type="hidden" />
|
||||
<div class="formrow">
|
||||
<div class="formitem"><textarea name="reply-content" placeholder="Insert reply here"></textarea></div>
|
||||
</div>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
// Code generated by. DO NOT EDIT.
|
||||
/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */
|
||||
package main
|
||||
import "strconv"
|
||||
import "io"
|
||||
import "strconv"
|
||||
|
||||
func init() {
|
||||
template_topic_alt_handle = template_topic_alt
|
||||
|
@ -105,6 +105,7 @@ w.Write([]byte(tmpl_topic_alt_vars.Topic.Content))
|
|||
w.Write(topic_alt_28)
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.Content))
|
||||
w.Write(topic_alt_29)
|
||||
if tmpl_topic_alt_vars.CurrentUser.Loggedin {
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.LikeItem {
|
||||
w.Write(topic_alt_30)
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID)))
|
||||
|
@ -141,89 +142,98 @@ w.Write(topic_alt_43)
|
|||
w.Write([]byte(tmpl_topic_alt_vars.Topic.IpAddress))
|
||||
w.Write(topic_alt_44)
|
||||
}
|
||||
if tmpl_topic_alt_vars.Topic.LikeCount > 0 {
|
||||
w.Write(topic_alt_45)
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.LikeCount)))
|
||||
w.Write(topic_alt_46)
|
||||
}
|
||||
w.Write(topic_alt_45)
|
||||
w.Write([]byte(tmpl_topic_alt_vars.Topic.CreatedAt))
|
||||
w.Write(topic_alt_46)
|
||||
if tmpl_topic_alt_vars.Topic.LikeCount > 0 {
|
||||
w.Write(topic_alt_47)
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.LikeCount)))
|
||||
w.Write(topic_alt_48)
|
||||
}
|
||||
w.Write(topic_alt_49)
|
||||
if len(tmpl_topic_alt_vars.ItemList) != 0 {
|
||||
for _, item := range tmpl_topic_alt_vars.ItemList {
|
||||
w.Write(topic_alt_48)
|
||||
if item.ActionType != "" {
|
||||
w.Write(topic_alt_49)
|
||||
}
|
||||
w.Write(topic_alt_50)
|
||||
w.Write([]byte(item.Avatar))
|
||||
w.Write(topic_alt_51)
|
||||
w.Write([]byte(strconv.Itoa(item.CreatedBy)))
|
||||
w.Write(topic_alt_52)
|
||||
w.Write([]byte(item.CreatedByName))
|
||||
w.Write(topic_alt_53)
|
||||
if item.Tag != "" {
|
||||
w.Write(topic_alt_54)
|
||||
w.Write([]byte(item.Tag))
|
||||
w.Write(topic_alt_55)
|
||||
} else {
|
||||
w.Write(topic_alt_56)
|
||||
w.Write([]byte(strconv.Itoa(item.Level)))
|
||||
w.Write(topic_alt_57)
|
||||
}
|
||||
w.Write(topic_alt_58)
|
||||
if item.ActionType != "" {
|
||||
w.Write(topic_alt_51)
|
||||
}
|
||||
w.Write(topic_alt_52)
|
||||
w.Write([]byte(item.Avatar))
|
||||
w.Write(topic_alt_53)
|
||||
w.Write([]byte(strconv.Itoa(item.CreatedBy)))
|
||||
w.Write(topic_alt_54)
|
||||
w.Write([]byte(item.CreatedByName))
|
||||
w.Write(topic_alt_55)
|
||||
if item.Tag != "" {
|
||||
w.Write(topic_alt_56)
|
||||
w.Write([]byte(item.Tag))
|
||||
w.Write(topic_alt_57)
|
||||
} else {
|
||||
w.Write(topic_alt_58)
|
||||
w.Write([]byte(strconv.Itoa(item.Level)))
|
||||
w.Write(topic_alt_59)
|
||||
}
|
||||
w.Write(topic_alt_60)
|
||||
if item.ActionType != "" {
|
||||
w.Write(topic_alt_61)
|
||||
w.Write([]byte(item.ActionIcon))
|
||||
w.Write(topic_alt_62)
|
||||
w.Write([]byte(item.ActionType))
|
||||
w.Write(topic_alt_63)
|
||||
} else {
|
||||
w.Write(topic_alt_64)
|
||||
w.Write([]byte(item.ContentHtml))
|
||||
w.Write(topic_alt_65)
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.LikeItem {
|
||||
w.Write(topic_alt_66)
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_alt_67)
|
||||
}
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.EditReply {
|
||||
w.Write(topic_alt_62)
|
||||
if item.ActionType != "" {
|
||||
w.Write(topic_alt_63)
|
||||
w.Write([]byte(item.ActionIcon))
|
||||
w.Write(topic_alt_64)
|
||||
w.Write([]byte(item.ActionType))
|
||||
w.Write(topic_alt_65)
|
||||
} else {
|
||||
w.Write(topic_alt_66)
|
||||
w.Write([]byte(item.ContentHtml))
|
||||
w.Write(topic_alt_67)
|
||||
if tmpl_topic_alt_vars.CurrentUser.Loggedin {
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.LikeItem {
|
||||
w.Write(topic_alt_68)
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_alt_69)
|
||||
}
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.DeleteReply {
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.EditReply {
|
||||
w.Write(topic_alt_70)
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_alt_71)
|
||||
}
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.DeleteReply {
|
||||
w.Write(topic_alt_72)
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_alt_73)
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session))
|
||||
w.Write(topic_alt_74)
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.ViewIPs {
|
||||
w.Write(topic_alt_75)
|
||||
w.Write([]byte(item.IpAddress))
|
||||
w.Write(topic_alt_76)
|
||||
}
|
||||
if item.LikeCount > 0 {
|
||||
w.Write(topic_alt_74)
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topic_alt_75)
|
||||
w.Write([]byte(tmpl_topic_alt_vars.CurrentUser.Session))
|
||||
w.Write(topic_alt_76)
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.ViewIPs {
|
||||
w.Write(topic_alt_77)
|
||||
w.Write([]byte(strconv.Itoa(item.LikeCount)))
|
||||
w.Write([]byte(item.IpAddress))
|
||||
w.Write(topic_alt_78)
|
||||
}
|
||||
}
|
||||
w.Write(topic_alt_79)
|
||||
}
|
||||
w.Write([]byte(item.CreatedAt))
|
||||
w.Write(topic_alt_80)
|
||||
}
|
||||
}
|
||||
if item.LikeCount > 0 {
|
||||
w.Write(topic_alt_81)
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.CreateReply {
|
||||
w.Write([]byte(strconv.Itoa(item.LikeCount)))
|
||||
w.Write(topic_alt_82)
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID)))
|
||||
}
|
||||
w.Write(topic_alt_83)
|
||||
}
|
||||
w.Write(topic_alt_84)
|
||||
}
|
||||
}
|
||||
w.Write(topic_alt_85)
|
||||
if tmpl_topic_alt_vars.CurrentUser.Perms.CreateReply {
|
||||
w.Write(topic_alt_86)
|
||||
w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID)))
|
||||
w.Write(topic_alt_87)
|
||||
}
|
||||
w.Write(footer_0)
|
||||
}
|
||||
|
|
|
@ -32,14 +32,16 @@
|
|||
<div class="hide_on_edit topic_content user_content">{{.Topic.Content}}</div>
|
||||
<textarea name="topic_content" class="show_on_edit topic_content_input">{{.Topic.Content}}</textarea>
|
||||
<div class="button_container">
|
||||
{{if .CurrentUser.Loggedin}}
|
||||
{{if .CurrentUser.Perms.LikeItem}}<a href="/topic/like/submit/{{.Topic.ID}}" class="action_button">+1</a>{{end}}
|
||||
{{if .CurrentUser.Perms.EditTopic}}<a href="/topic/edit/{{.Topic.ID}}" class="action_button open_edit">Edit</a>{{end}}
|
||||
{{if .CurrentUser.Perms.DeleteTopic}}<a href="/topic/delete/submit/{{.Topic.ID}}" class="action_button delete_item">Delete</a>{{end}}
|
||||
{{if .CurrentUser.Perms.PinTopic}}
|
||||
{{if .Topic.Sticky}}<a href='/topic/unstick/submit/{{.Topic.ID}}' class="action_button">Unpin</a>{{else}}<a href='/topic/stick/submit/{{.Topic.ID}}' class="action_button">Pin</a>{{end}}{{end}}
|
||||
<a href="/report/submit/{{.Topic.ID}}?session={{.CurrentUser.Session}}&type=topic" class="action_button report_item">Report</a>
|
||||
{{/* Element Queries might help with having to use JS. Who knows when or *if* the W3C will standardise it */}}
|
||||
{{if .CurrentUser.Perms.ViewIPs}}<a href="#" title="IP Address" class="action_button action_button_right ip_item hide_on_mobile">{{.Topic.IpAddress}}</a>{{end}}
|
||||
{{end}}
|
||||
<a class="action_button action_button_right hide_on_mobile">{{.Topic.CreatedAt}}</a>
|
||||
{{if .Topic.LikeCount}}<a class="action_button action_button_right hide_on_micro">{{.Topic.LikeCount}} up</a>{{end}}
|
||||
</div>
|
||||
</div><div style="clear:both;"></div>
|
||||
|
@ -58,11 +60,14 @@
|
|||
{{else}}
|
||||
<div class="editable_block user_content">{{.ContentHtml}}</div>
|
||||
<div class="button_container">
|
||||
{{if $.CurrentUser.Loggedin}}
|
||||
{{if $.CurrentUser.Perms.LikeItem}}<a href="/reply/like/submit/{{.ID}}" class="action_button">+1</a>{{end}}
|
||||
{{if $.CurrentUser.Perms.EditReply}}<a href="/reply/edit/submit/{{.ID}}" class="action_button edit_item">Edit</a>{{end}}
|
||||
{{if $.CurrentUser.Perms.DeleteReply}}<a href="/reply/delete/submit/{{.ID}}" class="action_button delete_item">Delete</a>{{end}}
|
||||
<a href="/report/submit/{{.ID}}?session={{$.CurrentUser.Session}}&type=reply" class="action_button report_item">Report</a>
|
||||
{{if $.CurrentUser.Perms.ViewIPs}}<a href="#" title="IP Address" class="action_button action_button_right ip_item hide_on_mobile">{{.IpAddress}}</a>{{end}}
|
||||
{{end}}
|
||||
<a class="action_button action_button_right hide_on_mobile">{{.CreatedAt}}</a>
|
||||
{{if .LikeCount}}<a class="action_button action_button_right hide_on_micro">{{.LikeCount}} up</a>{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
|
|
|
@ -446,7 +446,6 @@ button.username {
|
|||
padding-right: 4px;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
.post_item:last-child { padding-bottom: 7px; }
|
||||
.post_tag {
|
||||
margin-top: 0px;
|
||||
text-align: center;
|
||||
|
|
22
topic.go
22
topic.go
|
@ -22,6 +22,7 @@ type Topic struct
|
|||
PostCount int
|
||||
LikeCount int
|
||||
ClassName string // CSS Class Name
|
||||
Data string // Used for report metadata
|
||||
}
|
||||
|
||||
type TopicUser struct
|
||||
|
@ -41,6 +42,7 @@ type TopicUser struct
|
|||
PostCount int
|
||||
LikeCount int
|
||||
ClassName string
|
||||
Data string // Used for report metadata
|
||||
|
||||
CreatedByName string
|
||||
Group int
|
||||
|
@ -140,7 +142,7 @@ func (sts *StaticTopicStore) CascadeGet(id int) (*Topic, error) {
|
|||
}
|
||||
|
||||
topic = &Topic{ID:id}
|
||||
err := get_topic_stmt.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.IpAddress, &topic.PostCount, &topic.LikeCount)
|
||||
err := get_topic_stmt.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 {
|
||||
sts.Add(topic)
|
||||
}
|
||||
|
@ -149,13 +151,13 @@ func (sts *StaticTopicStore) CascadeGet(id int) (*Topic, error) {
|
|||
|
||||
func (sts *StaticTopicStore) BypassGet(id int) (*Topic, error) {
|
||||
topic := &Topic{ID:id}
|
||||
err := get_topic_stmt.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.IpAddress, &topic.PostCount, &topic.LikeCount)
|
||||
err := get_topic_stmt.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 {
|
||||
topic := &Topic{ID:id}
|
||||
err := get_topic_stmt.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.IpAddress, &topic.PostCount, &topic.LikeCount)
|
||||
err := get_topic_stmt.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 {
|
||||
sts.Set(topic)
|
||||
} else {
|
||||
|
@ -245,31 +247,31 @@ func NewSqlTopicStore() *SqlTopicStore {
|
|||
|
||||
func (sus *SqlTopicStore) Get(id int) (*Topic, error) {
|
||||
topic := Topic{ID:id}
|
||||
err := get_topic_stmt.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.IpAddress, &topic.PostCount, &topic.LikeCount)
|
||||
err := get_topic_stmt.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 (sus *SqlTopicStore) GetUnsafe(id int) (*Topic, error) {
|
||||
topic := Topic{ID:id}
|
||||
err := get_topic_stmt.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.IpAddress, &topic.PostCount, &topic.LikeCount)
|
||||
err := get_topic_stmt.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 (sus *SqlTopicStore) CascadeGet(id int) (*Topic, error) {
|
||||
topic := Topic{ID:id}
|
||||
err := get_topic_stmt.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.IpAddress, &topic.PostCount, &topic.LikeCount)
|
||||
err := get_topic_stmt.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 *SqlTopicStore) BypassGet(id int) (*Topic, error) {
|
||||
topic := &Topic{ID:id}
|
||||
err := get_topic_stmt.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.IpAddress, &topic.PostCount, &topic.LikeCount)
|
||||
err := get_topic_stmt.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 (sus *SqlTopicStore) Load(id int) error {
|
||||
topic := Topic{ID:id}
|
||||
err := get_topic_stmt.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.IpAddress, &topic.PostCount, &topic.LikeCount)
|
||||
err := get_topic_stmt.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 err
|
||||
}
|
||||
|
||||
|
@ -336,7 +338,6 @@ func get_topicuser(tid int) (TopicUser,error) {
|
|||
//fmt.Printf("%+v\n", the_topic)
|
||||
tu.Tag = groups[tu.Group].Tag
|
||||
topics.Add(&the_topic)
|
||||
//err = errors.Error("Loaded data via query")
|
||||
return tu, err
|
||||
}
|
||||
|
||||
|
@ -360,12 +361,13 @@ func copy_topic_to_topicuser(topic *Topic, user *User) (tu TopicUser) {
|
|||
tu.IpAddress = topic.IpAddress
|
||||
tu.PostCount = topic.PostCount
|
||||
tu.LikeCount = topic.LikeCount
|
||||
tu.Data = topic.Data
|
||||
return tu
|
||||
}
|
||||
|
||||
func get_topic_by_reply(rid int) (*Topic, error) {
|
||||
topic := Topic{ID:0}
|
||||
err := get_topic_by_reply_stmt.QueryRow(rid).Scan(&topic.ID, &topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.IpAddress, &topic.PostCount, &topic.LikeCount)
|
||||
err := get_topic_by_reply_stmt.QueryRow(rid).Scan(&topic.ID, &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
|
||||
}
|
||||
|
||||
|
|
20
user.go
20
user.go
|
@ -195,17 +195,6 @@ func (sts *StaticUserStore) AddUnsafe(item *User) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
/*func (sts *StaticUserStore) SetConn(id int, conn interface{}) *User, error {
|
||||
sts.Lock()
|
||||
user, err := sts.CascadeGet(id)
|
||||
sts.Unlock()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
user.WS_Conn = conn
|
||||
return user, nil
|
||||
}*/
|
||||
|
||||
func (sts *StaticUserStore) Remove(id int) error {
|
||||
sts.Lock()
|
||||
delete(sts.items,id)
|
||||
|
@ -336,8 +325,7 @@ func (sus *SqlUserStore) GetCapacity() int {
|
|||
}
|
||||
|
||||
func (sus *SqlUserStore) GetLength() int {
|
||||
// Return the total number of users registered on the forums
|
||||
return 0
|
||||
return 0 // Return the total number of users registered on the forums?
|
||||
}
|
||||
|
||||
func SetPassword(uid int, password string) (error) {
|
||||
|
@ -364,10 +352,8 @@ func SendValidationEmail(username string, email string, token string) bool {
|
|||
if enable_ssl {
|
||||
schema = "s"
|
||||
}
|
||||
|
||||
subject := "Validate Your Email @ " + site_name
|
||||
msg := "Dear " + username + ", following your registration on our forums, we ask you to validate your email, so that we can confirm that this email actually belongs to you.\n\nClick on the following link to do so. http" + schema + "://" + site_url + "/user/edit/token/" + token + "\n\nIf you haven't created an account here, then please feel free to ignore this email.\nWe're sorry for the inconvenience this may have caused."
|
||||
|
||||
return SendEmail(email, subject, msg)
|
||||
}
|
||||
|
||||
|
@ -542,13 +528,13 @@ func decrease_post_user_stats(wcount int, uid int, topic bool, user User) error
|
|||
base_score = -2
|
||||
}
|
||||
|
||||
if wcount >= settings["megapost_min_chars"].(int) {
|
||||
if wcount >= settings["megapost_min_words"].(int) {
|
||||
_, err := increment_user_megaposts_stmt.Exec(-1,-1,-1,uid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mod = 4
|
||||
} else if wcount >= settings["bigpost_min_chars"].(int) {
|
||||
} else if wcount >= settings["bigpost_min_words"].(int) {
|
||||
_, err := increment_user_bigposts_stmt.Exec(-1,-1,uid)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -108,12 +108,55 @@ func(hub *WS_Hub) push_alert(targetUser int, event string, elementType string, a
|
|||
return err
|
||||
}
|
||||
|
||||
//fmt.Println("Writing to the client")
|
||||
w.Write([]byte(alert))
|
||||
w.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
func(hub *WS_Hub) push_alerts(users []int, event string, elementType string, actor_id int, targetUser_id int, elementID int) error {
|
||||
//fmt.Println("In push_alerts")
|
||||
var ws_users []*WS_User
|
||||
hub.users.RLock()
|
||||
// We don't want to keep a lock on this for too long, so we'll accept some nil pointers
|
||||
for _, uid := range users {
|
||||
ws_users = append(ws_users, hub.online_users[uid])
|
||||
}
|
||||
hub.users.RUnlock()
|
||||
if len(ws_users) == 0 {
|
||||
return ws_nouser
|
||||
}
|
||||
|
||||
var errs []error
|
||||
for _, ws_user := range ws_users {
|
||||
if ws_user == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
//fmt.Println("Building alert")
|
||||
alert, err := build_alert(event, elementType, actor_id, targetUser_id, elementID, *ws_user.User)
|
||||
if err != nil {
|
||||
errs = append(errs,err)
|
||||
}
|
||||
|
||||
//fmt.Println("Getting WS Writer")
|
||||
w, err := ws_user.conn.NextWriter(websocket.TextMessage)
|
||||
if err != nil {
|
||||
errs = append(errs,err)
|
||||
}
|
||||
|
||||
w.Write([]byte(alert))
|
||||
w.Close()
|
||||
}
|
||||
|
||||
// Return the first error
|
||||
if len(errs) != 0 {
|
||||
for _, err := range errs {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func route_websockets(w http.ResponseWriter, r *http.Request) {
|
||||
user, ok := SimpleSessionCheck(w,r)
|
||||
if !ok {
|
||||
|
|
Loading…
Reference in New Issue