Added the Level System.

The .bat files now exit upon encountering an error.
Post, bigpost, megapost, and topic stats are now tracked for each user.
Added the bigpost_min_chars and megapost_min_chars settings. Probably needs to be renamed.
Added the Levels test. Run `go test -run "Levels"`
The installer now validates the inputted server port.
Added a word counter utility function.
The template engine now borks less on variable nodes.
Added the lt, gt, ge, eq and ne to the template engine. I'm fairly sure eq was already in there, but things get handled differently depending on what type of node it is.
Eliminated more "success" variables by converting the errors over into InternalError() and LocalErrors()
This commit is contained in:
Azareal 2017-01-12 02:55:08 +00:00
parent 7f8aaedb0a
commit b7c89fd020
22 changed files with 431 additions and 235 deletions

View File

@ -4,7 +4,7 @@ A super fast forum software written in Go.
The initial code-base was forked from one of my side projects, but has now gone far beyond that. The initial code-base was forked from one of my side projects, but has now gone far beyond that.
Discord Server: https://discord.gg/eyYvtTf Azareal's Discord Chat: https://discord.gg/eyYvtTf
If you like this software, please give it a star and give us some feedback :) If you like this software, please give it a star and give us some feedback :)

View File

@ -1,3 +1,13 @@
@echo off
go build go build
if %errorlevel% neq 0 (
pause
exit /b %errorlevel%
)
go build ./install go build ./install
if %errorlevel% neq 0 (
pause
exit /b %errorlevel%
)
echo Gosora was successfully built
pause pause

View File

@ -2,19 +2,25 @@ CREATE TABLE `users`(
`uid` int not null AUTO_INCREMENT, `uid` int not null AUTO_INCREMENT,
`name` varchar(100) not null, `name` varchar(100) not null,
`password` varchar(100) not null, `password` varchar(100) not null,
`salt` varchar(80) DEFAULT '' not null, `salt` varchar(80) default '' not null,
`group` int not null, `group` int not null,
`active` tinyint DEFAULT 0 not null, `active` tinyint default 0 not null,
`is_super_admin` tinyint(1) not null, `is_super_admin` tinyint(1) not null,
`createdAt` datetime not null, `createdAt` datetime not null,
`lastActiveAt` datetime not null, `lastActiveAt` datetime not null,
`session` varchar(200) DEFAULT '' not null, `session` varchar(200) default '' not null,
`last_ip` varchar(200) DEFAULT '0.0.0.0.0' not null, `last_ip` varchar(200) default '0.0.0.0.0' not null,
`email` varchar(200) DEFAULT '' not null, `email` varchar(200) default '' not null,
`avatar` varchar(20) DEFAULT '' not null, `avatar` varchar(20) default '' not null,
`message` text not null, `message` text not null,
`url_prefix` varchar(20) DEFAULT '' not null, `url_prefix` varchar(20) default '' not null,
`url_name` varchar(100) DEFAULT '' not null, `url_name` varchar(100) default '' not null,
`level` tinyint default 0 not null,
`score` int default 0 not null,
`posts` int default 0 not null,
`bigposts` int default 0 not null,
`megaposts` int default 0 not null,
`topics` int default 0 not null,
primary key(`uid`), primary key(`uid`),
unique(`name`) unique(`name`)
) CHARSET=utf8mb4 COLLATE utf8mb4_general_ci; ) CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;
@ -91,8 +97,8 @@ CREATE TABLE `users_replies`(
) CHARSET=utf8mb4 COLLATE utf8mb4_general_ci; ) CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;
CREATE TABLE `likes`( CREATE TABLE `likes`(
`weight` int DEFAULT 1 not null, `weight` tinyint DEFAULT 1 not null,
`type` int not null, /* Regular Post = 1, Big Post = 2, Mega Post = 3, etc.*/ `type` tinyint not null, /* Regular Post = 1, Big Post = 2, Mega Post = 3, etc.*/
`targetItem` int not null, `targetItem` int not null,
`sentBy` int not null, `sentBy` int not null,
`recalc` tinyint DEFAULT 0 not null `recalc` tinyint DEFAULT 0 not null
@ -120,6 +126,8 @@ CREATE TABLE `themes`(
INSERT INTO settings(`name`,`content`,`type`) VALUES ('url_tags','1','bool'); INSERT INTO settings(`name`,`content`,`type`) VALUES ('url_tags','1','bool');
INSERT INTO settings(`name`,`content`,`type`,`constraints`) VALUES ('activation_type','1','list','1-3'); INSERT INTO settings(`name`,`content`,`type`,`constraints`) VALUES ('activation_type','1','list','1-3');
INSERT INTO settings(`name`,`content`,`type`) VALUES ('bigpost_min_chars','250','int');
INSERT INTO settings(`name`,`content`,`type`) VALUES ('megapost_min_chars','1000','int');
INSERT INTO themes(`uname`,`default`) VALUES ('tempra-simple',1); INSERT INTO themes(`uname`,`default`) VALUES ('tempra-simple',1);
INSERT INTO users(`name`,`password`,`email`,`group`,`is_super_admin`,`createdAt`,`lastActiveAt`,`message`) INSERT INTO users(`name`,`password`,`email`,`group`,`is_super_admin`,`createdAt`,`lastActiveAt`,`message`)

View File

@ -1,6 +1,7 @@
package main package main
import "log" import "log"
import "bytes" import "bytes"
import "strconv"
import "math/rand" import "math/rand"
import "testing" import "testing"
import "net/http" import "net/http"
@ -12,24 +13,24 @@ import "html/template"
func BenchmarkTopicTemplate(b *testing.B) { func BenchmarkTopicTemplate(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
user := User{0,"Bob","bob@localhost",0,false,false,false,false,false,false,GuestPerms,"",false,"","","","",""} user := User{0,"Bob","bob@localhost",0,false,false,false,false,false,false,GuestPerms,"",false,"","","","","",0,0}
admin := User{1,"Admin","admin@localhost",0,true,true,true,true,true,false,AllPerms,"",false,"","","","",""} admin := User{1,"Admin","admin@localhost",0,true,true,true,true,true,false,AllPerms,"",false,"","","","","",-1,58}
var noticeList map[int]string = make(map[int]string) var noticeList map[int]string = make(map[int]string)
noticeList[0] = "test" noticeList[0] = "test"
topic := TopicUser{0,"Lol",template.HTML("Hey everyone!"),0,false,false,"",0,"","","",no_css_tmpl,0,"","","",""} topic := TopicUser{Title: "Lol",Content: template.HTML("Hey everyone!"),CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58}
var replyList []Reply var replyList []Reply
replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""}) replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0})
replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""}) replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0})
replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""}) replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0})
replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""}) replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0})
replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""}) replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0})
replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""}) replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0})
replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""}) replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0})
replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""}) replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0})
replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""}) replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0})
replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""}) replyList = append(replyList, Reply{0,0,"Hey everyone!",template.HTML("Hey everyone!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0})
tpage := TopicPage{"Topic Blah",user,noticeList,replyList,topic,false} tpage := TopicPage{"Topic Blah",user,noticeList,replyList,topic,false}
tpage2 := TopicPage{"Topic Blah",admin,noticeList,replyList,topic,false} tpage2 := TopicPage{"Topic Blah",admin,noticeList,replyList,topic,false}
@ -60,22 +61,22 @@ func BenchmarkTopicTemplate(b *testing.B) {
func BenchmarkTopicsTemplate(b *testing.B) { func BenchmarkTopicsTemplate(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
user := User{0,"Bob","bob@localhost",0,false,false,false,false,false,false,GuestPerms,"",false,"","","","",""} user := User{0,"Bob","bob@localhost",0,false,false,false,false,false,false,GuestPerms,"",false,"","","","","",0,0}
admin := User{1,"Admin","admin@localhost",0,true,true,true,true,true,false,AllPerms,"",false,"","","","",""} admin := User{1,"Admin","admin@localhost",0,true,true,true,true,true,false,AllPerms,"",false,"","","","","",-1,58}
var noticeList map[int]string = make(map[int]string) var noticeList map[int]string = make(map[int]string)
noticeList[0] = "test" noticeList[0] = "test"
var topicList []TopicUser var topicList []TopicUser
topicList = append(topicList, TopicUser{0,"Hey everyone!",template.HTML("Hey everyone!"),0,false,false,"0000-00-00 00:00:00",1,"open","Admin","",no_css_tmpl,0,"Admin","","",""}) topicList = append(topicList, TopicUser{Title: "Hey everyone!",Content: template.HTML("Hey everyone!"),CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58})
topicList = append(topicList, TopicUser{0,"Hey everyone!",template.HTML("Hey everyone!"),0,false,false,"0000-00-00 00:00:00",1,"open","Admin","",no_css_tmpl,0,"Admin","","",""}) topicList = append(topicList, TopicUser{Title: "Hey everyone!",Content: template.HTML("Hey everyone!"),CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58})
topicList = append(topicList, TopicUser{0,"Hey everyone!",template.HTML("Hey everyone!"),0,false,false,"0000-00-00 00:00:00",1,"open","Admin","",no_css_tmpl,0,"Admin","","",""}) topicList = append(topicList, TopicUser{Title: "Hey everyone!",Content: template.HTML("Hey everyone!"),CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58})
topicList = append(topicList, TopicUser{0,"Hey everyone!",template.HTML("Hey everyone!"),0,false,false,"0000-00-00 00:00:00",1,"open","Admin","",no_css_tmpl,0,"Admin","","",""}) topicList = append(topicList, TopicUser{Title: "Hey everyone!",Content: template.HTML("Hey everyone!"),CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58})
topicList = append(topicList, TopicUser{0,"Hey everyone!",template.HTML("Hey everyone!"),0,false,false,"0000-00-00 00:00:00",1,"open","Admin","",no_css_tmpl,0,"Admin","","",""}) topicList = append(topicList, TopicUser{Title: "Hey everyone!",Content: template.HTML("Hey everyone!"),CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58})
topicList = append(topicList, TopicUser{0,"Hey everyone!",template.HTML("Hey everyone!"),0,false,false,"0000-00-00 00:00:00",1,"open","Admin","",no_css_tmpl,0,"Admin","","",""}) topicList = append(topicList, TopicUser{Title: "Hey everyone!",Content: template.HTML("Hey everyone!"),CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58})
topicList = append(topicList, TopicUser{0,"Hey everyone!",template.HTML("Hey everyone!"),0,false,false,"0000-00-00 00:00:00",1,"open","Admin","",no_css_tmpl,0,"Admin","","",""}) topicList = append(topicList, TopicUser{Title: "Hey everyone!",Content: template.HTML("Hey everyone!"),CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58})
topicList = append(topicList, TopicUser{0,"Hey everyone!",template.HTML("Hey everyone!"),0,false,false,"0000-00-00 00:00:00",1,"open","Admin","",no_css_tmpl,0,"Admin","","",""}) topicList = append(topicList, TopicUser{Title: "Hey everyone!",Content: template.HTML("Hey everyone!"),CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58})
topicList = append(topicList, TopicUser{0,"Hey everyone!",template.HTML("Hey everyone!"),0,false,false,"0000-00-00 00:00:00",1,"open","Admin","",no_css_tmpl,0,"Admin","","",""}) topicList = append(topicList, TopicUser{Title: "Hey everyone!",Content: template.HTML("Hey everyone!"),CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58})
topicList = append(topicList, TopicUser{0,"Hey everyone!",template.HTML("Hey everyone!"),0,false,false,"0000-00-00 00:00:00",1,"open","Admin","",no_css_tmpl,0,"Admin","","",""}) topicList = append(topicList, TopicUser{Title: "Hey everyone!",Content: template.HTML("Hey everyone!"),CreatedBy: 1,CreatedAt: "0000-00-00 00:00:00",ParentID: 1,CreatedByName:"Admin",Css: no_css_tmpl,Tag: "Admin", Level: 58})
tpage := TopicsPage{"Topic Blah",user,noticeList,topicList,0} tpage := TopicsPage{"Topic Blah",user,noticeList,topicList,0}
tpage2 := TopicsPage{"Topic Blah",admin,noticeList,topicList,0} tpage2 := TopicsPage{"Topic Blah",admin,noticeList,topicList,0}
@ -895,6 +896,14 @@ func BenchmarkBBCodePluginWithFullParser(b *testing.B) {
}) })
} }
func TestLevels(t *testing.T) {
levels := getLevels(40)
for level, score := range levels {
sscore := strconv.FormatFloat(score, 'f', -1, 64)
log.Print("Level: " + strconv.Itoa(level) + " Score: " + sscore)
}
}
/*func TestRoute(t *testing.T) { /*func TestRoute(t *testing.T) {
}*/ }*/

BIN
images/level_algorithm.PNG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

BIN
images/levels.PNG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 334 KiB

View File

@ -1,5 +1,25 @@
@echo off
echo Installing the dependencies
go get -u github.com/go-sql-driver/mysql go get -u github.com/go-sql-driver/mysql
if %errorlevel% neq 0 (
pause
exit /b %errorlevel%
)
go get -u golang.org/x/crypto/bcrypt go get -u golang.org/x/crypto/bcrypt
if %errorlevel% neq 0 (
pause
exit /b %errorlevel%
)
echo Preparing the installer
go build go build
if %errorlevel% neq 0 (
pause
exit /b %errorlevel%
)
go build ./install go build ./install
if %errorlevel% neq 0 (
pause
exit /b %errorlevel%
)
install.exe install.exe

View File

@ -273,6 +273,11 @@ func get_site_details() bool {
if server_port == "" { if server_port == "" {
server_port = default_server_port server_port = default_server_port
} }
_, err := strconv.Atoi(server_port)
if err != nil {
fmt.Println("That's not a valid number!")
return false
}
fmt.Println("Set the server port to " + server_port) fmt.Println("Set the server port to " + server_port)
return true return true
} }

View File

@ -41,15 +41,15 @@ var template_profile_handle func(ProfilePage,io.Writer) = nil
func compile_templates() { func compile_templates() {
var c CTemplateSet var c CTemplateSet
user := User{62,"","compiler@localhost",0,false,false,false,false,false,false,GuestPerms,"",false,"","","","",""} user := User{62,"","compiler@localhost",0,false,false,false,false,false,false,GuestPerms,"",false,"","","","","",0,0}
var noticeList map[int]string = make(map[int]string) var noticeList map[int]string = make(map[int]string)
noticeList[0] = "test" noticeList[0] = "test"
log.Print("Compiling the templates") log.Print("Compiling the templates")
topic := TopicUser{1,"Blah",template.HTML("Hey there!"),0,false,false,"",0,"","","",no_css_tmpl,0,"","","",""} topic := TopicUser{1,"Blah",template.HTML("Hey there!"),0,false,false,"",0,"","","",no_css_tmpl,0,"","","","",58}
var replyList []Reply var replyList []Reply
replyList = append(replyList, Reply{0,0,"",template.HTML("Yo!"),0,"","",0,0,"",no_css_tmpl,0,"","","",""}) replyList = append(replyList, Reply{0,0,"",template.HTML("Yo!"),0,"","",0,0,"",no_css_tmpl,0,"","","","",0})
var varList map[string]VarItem = make(map[string]VarItem) var varList map[string]VarItem = make(map[string]VarItem)
tpage := TopicPage{"Title",user,noticeList,replyList,topic,false} tpage := TopicPage{"Title",user,noticeList,replyList,topic,false}
@ -71,7 +71,7 @@ func compile_templates() {
forums_tmpl := c.compile_template("forums.html","templates/","ForumsPage", forums_page, varList) forums_tmpl := c.compile_template("forums.html","templates/","ForumsPage", forums_page, varList)
var topicList []TopicUser var topicList []TopicUser
topicList = append(topicList, TopicUser{1,"Topic Title","The topic content.",1,false,false,"",1,"open","Admin","","",0,"","","",""}) topicList = append(topicList, TopicUser{1,"Topic Title","The topic content.",1,false,false,"",1,"open","Admin","","",0,"","","","",58})
topics_page := TopicsPage{"Topic List",user,noticeList,topicList,""} topics_page := TopicsPage{"Topic List",user,noticeList,topicList,""}
topics_tmpl := c.compile_template("topics.html","templates/","TopicsPage", topics_page, varList) topics_tmpl := c.compile_template("topics.html","templates/","TopicsPage", topics_page, varList)

View File

@ -38,11 +38,7 @@ func route_edit_topic(w http.ResponseWriter, r *http.Request) {
topic_name := r.PostFormValue("topic_name") topic_name := r.PostFormValue("topic_name")
topic_status := r.PostFormValue("topic_status") topic_status := r.PostFormValue("topic_status")
is_closed := (topic_status == "closed")
var is_closed bool
if topic_status == "closed" {
is_closed = true
}
topic_content := html.EscapeString(r.PostFormValue("topic_content")) topic_content := html.EscapeString(r.PostFormValue("topic_content"))
_, err = edit_topic_stmt.Exec(topic_name, preparse_message(topic_content), parse_message(html.EscapeString(preparse_message(topic_content))), is_closed, tid) _, err = edit_topic_stmt.Exec(topic_name, preparse_message(topic_content), parse_message(html.EscapeString(preparse_message(topic_content))), is_closed, tid)
@ -74,7 +70,9 @@ func route_delete_topic(w http.ResponseWriter, r *http.Request) {
return return
} }
err = db.QueryRow("SELECT tid from topics where tid = ?", tid).Scan(&tid) var content string
var createdBy int
err = db.QueryRow("select tid, content, createdBy from topics where tid = ?", tid).Scan(&tid, &content, &createdBy)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
LocalError("The topic you tried to delete doesn't exist.",w,r,user) LocalError("The topic you tried to delete doesn't exist.",w,r,user)
return return
@ -88,9 +86,15 @@ func route_delete_topic(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r,user) InternalError(err,w,r,user)
return return
} }
log.Print("The topic '" + strconv.Itoa(tid) + "' was deleted by User ID #" + strconv.Itoa(user.ID) + ".") log.Print("The topic '" + strconv.Itoa(tid) + "' was deleted by User ID #" + strconv.Itoa(user.ID) + ".")
http.Redirect(w, r, "/", http.StatusSeeOther) http.Redirect(w,r,"/",http.StatusSeeOther)
wcount := word_count(content)
err = decrease_post_user_stats(wcount, createdBy, true, user)
if err != nil {
InternalError(err,w,r,user)
return
}
} }
func route_stick_topic(w http.ResponseWriter, r *http.Request) { func route_stick_topic(w http.ResponseWriter, r *http.Request) {
@ -152,7 +156,6 @@ func route_reply_edit_submit(w http.ResponseWriter, r *http.Request) {
LocalError("Bad Form", w, r, user) LocalError("Bad Form", w, r, user)
return return
} }
is_js := r.PostFormValue("js") is_js := r.PostFormValue("js")
if is_js == "" { if is_js == "" {
is_js = "0" is_js = "0"
@ -218,7 +221,9 @@ func route_reply_delete_submit(w http.ResponseWriter, r *http.Request) {
} }
var tid int var tid int
err = db.QueryRow("SELECT tid from replies where rid = ?", rid).Scan(&tid) var content string
var createdBy int
err = db.QueryRow("SELECT tid, content, createdBy from replies where rid = ?", rid).Scan(&tid, &content, &createdBy)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
LocalErrorJSQ("The reply you tried to delete doesn't exist.",w,r,user,is_js) LocalErrorJSQ("The reply you tried to delete doesn't exist.",w,r,user,is_js)
return return
@ -233,12 +238,18 @@ func route_reply_delete_submit(w http.ResponseWriter, r *http.Request) {
return return
} }
log.Print("The reply '" + strconv.Itoa(rid) + "' was deleted by User ID #" + strconv.Itoa(user.ID) + ".") log.Print("The reply '" + strconv.Itoa(rid) + "' was deleted by User ID #" + strconv.Itoa(user.ID) + ".")
if is_js == "0" { if is_js == "0" {
//http.Redirect(w,r, "/topic/" + strconv.Itoa(tid), http.StatusSeeOther) //http.Redirect(w,r, "/topic/" + strconv.Itoa(tid), http.StatusSeeOther)
} else { } else {
fmt.Fprintf(w,"{'success': '1'}") fmt.Fprintf(w,"{'success': '1'}")
} }
wcount := word_count(content)
err = decrease_post_user_stats(wcount, createdBy, false, user)
if err != nil {
InternalError(err,w,r,user)
return
}
} }
func route_profile_reply_edit_submit(w http.ResponseWriter, r *http.Request) { func route_profile_reply_edit_submit(w http.ResponseWriter, r *http.Request) {

View File

@ -34,6 +34,12 @@ var register_stmt *sql.Stmt
var username_exists_stmt *sql.Stmt var username_exists_stmt *sql.Stmt
var change_group_stmt *sql.Stmt var change_group_stmt *sql.Stmt
var activate_user_stmt *sql.Stmt var activate_user_stmt *sql.Stmt
var update_user_level_stmt *sql.Stmt
var increment_user_score_stmt *sql.Stmt
var increment_user_posts_stmt *sql.Stmt
var increment_user_bigposts_stmt *sql.Stmt
var increment_user_megaposts_stmt *sql.Stmt
var increment_user_topics_stmt *sql.Stmt
var create_profile_reply_stmt *sql.Stmt var create_profile_reply_stmt *sql.Stmt
var edit_profile_reply_stmt *sql.Stmt var edit_profile_reply_stmt *sql.Stmt
var delete_profile_reply_stmt *sql.Stmt var delete_profile_reply_stmt *sql.Stmt
@ -64,7 +70,7 @@ func init_database(err error) {
} }
log.Print("Preparing get_session statement.") log.Print("Preparing get_session statement.")
get_session_stmt, err = db.Prepare("select `uid`, `name`, `group`, `is_super_admin`, `session`, `email`, `avatar`, `message`, `url_prefix`, `url_name` FROM `users` WHERE `uid` = ? AND `session` = ? AND `session` <> ''") get_session_stmt, err = db.Prepare("select `uid`, `name`, `group`, `is_super_admin`, `session`, `email`, `avatar`, `message`, `url_prefix`, `url_name`, `level`, `score` FROM `users` where `uid` = ? AND `session` = ? AND `session` <> ''")
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
@ -222,6 +228,42 @@ func init_database(err error) {
log.Fatal(err) log.Fatal(err)
} }
log.Print("Preparing update_user_level statement.")
update_user_level_stmt, err = db.Prepare("UPDATE users SET level = ? WHERE uid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing increment_user_score statement.")
increment_user_score_stmt, err = db.Prepare("UPDATE users SET score = score + ? WHERE uid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing increment_user_posts statement.")
increment_user_posts_stmt, err = db.Prepare("UPDATE users SET posts = posts + ? WHERE uid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing increment_user_bigposts statement.")
increment_user_bigposts_stmt, err = db.Prepare("UPDATE users SET posts = posts + ?, bigposts = bigposts + ? WHERE uid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing increment_user_megaposts statement.")
increment_user_megaposts_stmt, err = db.Prepare("UPDATE users SET posts = posts + ?, bigposts = bigposts + ?, megaposts = megaposts + ? WHERE uid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing increment_user_topics statement.")
increment_user_topics_stmt, err = db.Prepare("UPDATE users SET topics = topics + ? WHERE uid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing create_profile_reply statement.") 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(),?)") create_profile_reply_stmt, err = db.Prepare("INSERT INTO users_replies(uid,content,parsed_content,createdAt,createdBy) VALUES(?,?,?,NOW(),?)")
if err != nil { if err != nil {

View File

@ -20,4 +20,5 @@ type Reply struct
URL string URL string
URLPrefix string URLPrefix string
URLName string URLName string
Level int
} }

230
routes.go
View File

@ -236,7 +236,6 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
if !ok { if !ok {
return return
} }
var( var(
err error err error
rid int rid int
@ -254,13 +253,14 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
replyURL string replyURL string
replyURLPrefix string replyURLPrefix string
replyURLName string replyURLName string
replyLevel int
is_super_admin bool is_super_admin bool
group int group int
replyList []Reply replyList []Reply
) )
topic := TopicUser{0,"","",0,false,false,"",0,"","","",no_css_tmpl,0,"","","",""} topic := TopicUser{Css: no_css_tmpl}
topic.ID, err = strconv.Atoi(r.URL.Path[len("/topic/"):]) topic.ID, err = strconv.Atoi(r.URL.Path[len("/topic/"):])
if err != nil { if err != nil {
LocalError("The provided TopicID is not a valid number.",w,r,user) LocalError("The provided TopicID is not a valid number.",w,r,user)
@ -274,7 +274,7 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
} }
// Get the topic.. // Get the topic..
err = db.QueryRow("select topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, users.name, users.avatar, users.is_super_admin, users.group, users.url_prefix, users.url_name from topics left join users ON topics.createdBy = users.uid where tid = ?", topic.ID).Scan(&topic.Title, &content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.CreatedByName, &topic.Avatar, &is_super_admin, &group, &topic.URLPrefix, &topic.URLName) err = db.QueryRow("select topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, users.name, users.avatar, users.is_super_admin, users.group, users.url_prefix, users.url_name, users.level from topics left join users ON topics.createdBy = users.uid where tid = ?", topic.ID).Scan(&topic.Title, &content, &topic.CreatedBy, &topic.CreatedAt, &topic.Is_Closed, &topic.Sticky, &topic.ParentID, &topic.CreatedByName, &topic.Avatar, &is_super_admin, &group, &topic.URLPrefix, &topic.URLName, &topic.Level)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
NotFound(w,r,user) NotFound(w,r,user)
return return
@ -300,12 +300,13 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
} }
if is_super_admin || groups[group].Is_Mod || groups[group].Is_Admin { if is_super_admin || groups[group].Is_Mod || groups[group].Is_Admin {
topic.Css = staff_css_tmpl topic.Css = staff_css_tmpl
topic.Level = -1
} }
if groups[group].Tag != "" { //if groups[group].Tag != "" {
topic.Tag = groups[group].Tag topic.Tag = groups[group].Tag
} else { //} else {
topic.Tag = "" // topic.Tag = ""
} //}
if settings["url_tags"] == false { if settings["url_tags"] == false {
topic.URLName = "" topic.URLName = ""
} else { } else {
@ -318,7 +319,7 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
} }
// Get the replies.. // Get the replies..
rows, err := db.Query("select replies.rid, replies.content, replies.createdBy, replies.createdAt, replies.lastEdit, replies.lastEditBy, users.avatar, users.name, users.is_super_admin, users.group, users.url_prefix, users.url_name from replies left join users ON replies.createdBy = users.uid where tid = ?", topic.ID) rows, err := db.Query("select replies.rid, replies.content, replies.createdBy, replies.createdAt, replies.lastEdit, replies.lastEditBy, users.avatar, users.name, users.is_super_admin, users.group, users.url_prefix, users.url_name, users.level from replies left join users ON replies.createdBy = users.uid where tid = ?", topic.ID)
if err != nil { if err != nil {
InternalError(err,w,r,user) InternalError(err,w,r,user)
return return
@ -326,7 +327,7 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
defer rows.Close() defer rows.Close()
for rows.Next() { for rows.Next() {
err := rows.Scan(&rid, &replyContent, &replyCreatedBy, &replyCreatedAt, &replyLastEdit, &replyLastEditBy, &replyAvatar, &replyCreatedByName, &is_super_admin, &group, &replyURLPrefix, &replyURLName) err := rows.Scan(&rid, &replyContent, &replyCreatedBy, &replyCreatedAt, &replyLastEdit, &replyLastEditBy, &replyAvatar, &replyCreatedByName, &is_super_admin, &group, &replyURLPrefix, &replyURLName, &replyLevel)
if err != nil { if err != nil {
InternalError(err,w,r,user) InternalError(err,w,r,user)
return return
@ -335,6 +336,7 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
replyLines = strings.Count(replyContent,"\n") replyLines = strings.Count(replyContent,"\n")
if is_super_admin || groups[group].Is_Mod || groups[group].Is_Admin { if is_super_admin || groups[group].Is_Mod || groups[group].Is_Admin {
replyCss = staff_css_tmpl replyCss = staff_css_tmpl
replyLevel = -1
} else { } else {
replyCss = no_css_tmpl replyCss = no_css_tmpl
} }
@ -345,11 +347,11 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
} else { } else {
replyAvatar = strings.Replace(noavatar,"{id}",strconv.Itoa(replyCreatedBy),1) replyAvatar = strings.Replace(noavatar,"{id}",strconv.Itoa(replyCreatedBy),1)
} }
if groups[group].Tag != "" { //if groups[group].Tag != "" {
replyTag = groups[group].Tag replyTag = groups[group].Tag
} else { //} else {
replyTag = "" // replyTag = ""
} //}
if settings["url_tags"] == false { if settings["url_tags"] == false {
replyURLName = "" replyURLName = ""
} else { } else {
@ -361,7 +363,7 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
} }
} }
replyItem := Reply{rid,topic.ID,replyContent,template.HTML(parse_message(replyContent)),replyCreatedBy,replyCreatedByName,replyCreatedAt,replyLastEdit,replyLastEditBy,replyAvatar,replyCss,replyLines,replyTag,replyURL,replyURLPrefix,replyURLName} replyItem := Reply{rid,topic.ID,replyContent,template.HTML(parse_message(replyContent)),replyCreatedBy,replyCreatedByName,replyCreatedAt,replyLastEdit,replyLastEditBy,replyAvatar,replyCss,replyLines,replyTag,replyURL,replyURLPrefix,replyURLName,replyLevel}
if hooks["rrow_assign"] != nil { if hooks["rrow_assign"] != nil {
replyItem = run_hook("rrow_assign", replyItem).(Reply) replyItem = run_hook("rrow_assign", replyItem).(Reply)
@ -422,7 +424,7 @@ func route_profile(w http.ResponseWriter, r *http.Request){
puser = user puser = user
} else { } else {
// Fetch the user data // Fetch the user data
err = db.QueryRow("SELECT `name`, `group`, `is_super_admin`, `avatar`, `message`, `url_prefix`, `url_name` FROM `users` WHERE `uid` = ?", puser.ID).Scan(&puser.Name, &puser.Group, &puser.Is_Super_Admin, &puser.Avatar, &puser.Message, &puser.URLPrefix, &puser.URLName) err = db.QueryRow("SELECT `name`, `group`, `is_super_admin`, `avatar`, `message`, `url_prefix`, `url_name`, `level` FROM `users` WHERE `uid` = ?", puser.ID).Scan(&puser.Name, &puser.Group, &puser.Is_Super_Admin, &puser.Avatar, &puser.Message, &puser.URLPrefix, &puser.URLName, &puser.Level)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
NotFound(w,r,user) NotFound(w,r,user)
return return
@ -440,11 +442,11 @@ func route_profile(w http.ResponseWriter, r *http.Request){
} }
} }
if groups[puser.Group].Tag != "" { //if groups[puser.Group].Tag != "" {
puser.Tag = groups[puser.Group].Tag puser.Tag = groups[puser.Group].Tag
} else { //} else {
puser.Tag = "" // puser.Tag = ""
} //}
if puser.Avatar != "" { if puser.Avatar != "" {
if puser.Avatar[0] == '.' { if puser.Avatar[0] == '.' {
@ -490,7 +492,7 @@ func route_profile(w http.ResponseWriter, r *http.Request){
replyTag = "" replyTag = ""
} }
replyList = append(replyList, Reply{rid,puser.ID,replyContent,template.HTML(parse_message(replyContent)),replyCreatedBy,replyCreatedByName,replyCreatedAt,replyLastEdit,replyLastEditBy,replyAvatar,replyCss,replyLines,replyTag,"","",""}) replyList = append(replyList, Reply{rid,puser.ID,replyContent,template.HTML(parse_message(replyContent)),replyCreatedBy,replyCreatedByName,replyCreatedAt,replyLastEdit,replyLastEditBy,replyAvatar,replyCss,replyLines,replyTag,"","","",0})
} }
err = rows.Err() err = rows.Err()
if err != nil { if err != nil {
@ -518,7 +520,6 @@ func route_topic_create(w http.ResponseWriter, r *http.Request){
NoPermissions(w,r,user) NoPermissions(w,r,user)
return return
} }
pi := Page{"Create Topic","create-topic",user,noticeList,tList,0} pi := Page{"Create Topic","create-topic",user,noticeList,tList,0}
templates.ExecuteTemplate(w,"create-topic.html", pi) templates.ExecuteTemplate(w,"create-topic.html", pi)
} }
@ -539,38 +540,32 @@ func route_create_topic(w http.ResponseWriter, r *http.Request) {
LocalError("Bad Form", w, r, user) LocalError("Bad Form", w, r, user)
return return
} }
success := 1
topic_name := html.EscapeString(r.PostFormValue("topic-name")) topic_name := html.EscapeString(r.PostFormValue("topic-name"))
content := html.EscapeString(preparse_message(r.PostFormValue("topic-content")))
res, err := create_topic_stmt.Exec(topic_name,html.EscapeString(preparse_message(r.PostFormValue("topic-content"))),parse_message(html.EscapeString(preparse_message(r.PostFormValue("topic-content")))),user.ID) res, err := create_topic_stmt.Exec(topic_name,content,parse_message(content),user.ID)
if err != nil { if err != nil {
log.Print(err) InternalError(err,w,r,user)
success = 0 return
} }
lastId, err := res.LastInsertId() lastId, err := res.LastInsertId()
if err != nil { if err != nil {
log.Print(err) InternalError(err,w,r,user)
success = 0 return
} }
_, err = update_forum_cache_stmt.Exec(topic_name, lastId, user.Name, user.ID, 1) _, err = update_forum_cache_stmt.Exec(topic_name, lastId, user.Name, user.ID, 1)
if err != nil { if err != nil {
InternalError(err,w,r,user) InternalError(err,w,r,user)
return return
} }
if success != 1 { http.Redirect(w, r, "/topic/" + strconv.FormatInt(lastId,10), http.StatusSeeOther)
errmsg := "Unable to create the topic" wcount := word_count(content)
pi := Page{"Error","error",user,nList,tList,errmsg} err = increase_post_user_stats(wcount, user.ID, true, user)
if err != nil {
var b bytes.Buffer InternalError(err,w,r,user)
templates.ExecuteTemplate(&b,"error.html", pi) return
errpage := b.String()
w.WriteHeader(500)
fmt.Fprintln(w,errpage)
} else {
http.Redirect(w, r, "/topic/" + strconv.FormatInt(lastId, 10), http.StatusSeeOther)
} }
} }
@ -589,7 +584,6 @@ func route_create_reply(w http.ResponseWriter, r *http.Request) {
LocalError("Bad Form", w, r, user) LocalError("Bad Form", w, r, user)
return return
} }
tid, err := strconv.Atoi(r.PostFormValue("tid")) tid, err := strconv.Atoi(r.PostFormValue("tid"))
if err != nil { if err != nil {
LocalError("Failed to convert the TopicID", w, r, user) LocalError("Failed to convert the TopicID", w, r, user)
@ -597,7 +591,7 @@ func route_create_reply(w http.ResponseWriter, r *http.Request) {
} }
content := preparse_message(html.EscapeString(r.PostFormValue("reply-content"))) content := preparse_message(html.EscapeString(r.PostFormValue("reply-content")))
log.Print(content) //log.Print(content)
_, err = create_reply_stmt.Exec(tid,content,parse_message(content),user.ID) _, err = create_reply_stmt.Exec(tid,content,parse_message(content),user.ID)
if err != nil { if err != nil {
InternalError(err,w,r,user) InternalError(err,w,r,user)
@ -621,6 +615,12 @@ func route_create_reply(w http.ResponseWriter, r *http.Request) {
} }
http.Redirect(w, r, "/topic/" + strconv.Itoa(tid), http.StatusSeeOther) http.Redirect(w, r, "/topic/" + strconv.Itoa(tid), http.StatusSeeOther)
wcount := word_count(content)
err = increase_post_user_stats(wcount, user.ID, false, user)
if err != nil {
InternalError(err,w,r,user)
return
}
} }
func route_profile_reply_create(w http.ResponseWriter, r *http.Request) { func route_profile_reply_create(w http.ResponseWriter, r *http.Request) {
@ -638,52 +638,29 @@ func route_profile_reply_create(w http.ResponseWriter, r *http.Request) {
LocalError("Bad Form", w, r, user) LocalError("Bad Form", w, r, user)
return return
} }
success := 1
uid, err := strconv.Atoi(r.PostFormValue("uid")) uid, err := strconv.Atoi(r.PostFormValue("uid"))
if err != nil { if err != nil {
log.Print(err) LocalError("Invalid UID",w,r,user)
success = 0
errmsg := "Unable to create the reply"
pi := Page{"Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
errpage := b.String()
w.WriteHeader(500)
fmt.Fprintln(w,errpage)
return return
} }
_, err = create_profile_reply_stmt.Exec(uid,html.EscapeString(preparse_message(r.PostFormValue("reply-content"))),parse_message(html.EscapeString(preparse_message(r.PostFormValue("reply-content")))),user.ID) _, err = create_profile_reply_stmt.Exec(uid,html.EscapeString(preparse_message(r.PostFormValue("reply-content"))),parse_message(html.EscapeString(preparse_message(r.PostFormValue("reply-content")))),user.ID)
if err != nil { if err != nil {
log.Print(err) InternalError(err,w,r,user)
success = 0 return
} }
var user_name string var user_name string
err = db.QueryRow("select name from users where uid = ?", uid).Scan(&user_name) err = db.QueryRow("select name from users where uid = ?", uid).Scan(&user_name)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
log.Print(err) LocalError("The profile you're trying to post on doesn't exist.",w,r,user)
success = 0 return
} else if err != nil { } else if err != nil {
InternalError(err,w,r,user) InternalError(err,w,r,user)
return return
} }
if success != 1 { http.Redirect(w, r, "/user/" + strconv.Itoa(uid), http.StatusSeeOther)
errmsg := "Unable to create the reply"
pi := Page{"Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
errpage := b.String()
w.WriteHeader(500)
fmt.Fprintln(w,errpage)
} else {
http.Redirect(w, r, "/user/" + strconv.Itoa(uid), http.StatusSeeOther)
}
} }
func route_report_submit(w http.ResponseWriter, r *http.Request) { func route_report_submit(w http.ResponseWriter, r *http.Request) {
@ -691,7 +668,6 @@ func route_report_submit(w http.ResponseWriter, r *http.Request) {
if !ok { if !ok {
return return
} }
if !user.Loggedin { if !user.Loggedin {
LoginRequired(w,r,user) LoginRequired(w,r,user)
return return
@ -872,13 +848,7 @@ func route_account_own_edit_critical_submit(w http.ResponseWriter, r *http.Reque
err = get_password_stmt.QueryRow(user.ID).Scan(&real_password, &salt) err = get_password_stmt.QueryRow(user.ID).Scan(&real_password, &salt)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
pi := Page{"Error","error",user,nList,tList,"Your account doesn't exist."} LocalError("Your account no longer exists.",w,r,user)
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
errpage := b.String()
w.WriteHeader(500)
fmt.Fprintln(w,errpage)
return return
} else if err != nil { } else if err != nil {
InternalError(err,w,r,user) InternalError(err,w,r,user)
@ -888,26 +858,14 @@ func route_account_own_edit_critical_submit(w http.ResponseWriter, r *http.Reque
current_password = current_password + salt current_password = current_password + salt
err = bcrypt.CompareHashAndPassword([]byte(real_password), []byte(current_password)) err = bcrypt.CompareHashAndPassword([]byte(real_password), []byte(current_password))
if err == bcrypt.ErrMismatchedHashAndPassword { if err == bcrypt.ErrMismatchedHashAndPassword {
pi := Page{"Error","error",user,nList,tList,"That's not the correct password."} LocalError("That's not the correct password.",w,r,user)
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
errpage := b.String()
w.WriteHeader(500)
fmt.Fprintln(w,errpage)
return return
} else if err != nil { } else if err != nil {
InternalError(err,w,r,user) InternalError(err,w,r,user)
return return
} }
if new_password != confirm_password { if new_password != confirm_password {
pi := Page{"Error","error",user,nList,tList,"The two passwords don't match."} LocalError("The two passwords don't match.",w,r,user)
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
errpage := b.String()
w.WriteHeader(500)
fmt.Fprintln(w,errpage)
return return
} }
SetPassword(user.ID, new_password) SetPassword(user.ID, new_password)
@ -1192,16 +1150,8 @@ func route_logout(w http.ResponseWriter, r *http.Request) {
if !ok { if !ok {
return return
} }
if !user.Loggedin { if !user.Loggedin {
errmsg := "You can't logout without logging in first." LocalError("You can't logout without logging in first.",w,r,user)
pi := Page{"Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
errpage := b.String()
w.WriteHeader(500)
fmt.Fprintln(w,errpage)
return return
} }
@ -1218,19 +1168,10 @@ func route_login(w http.ResponseWriter, r *http.Request) {
if !ok { if !ok {
return return
} }
if user.Loggedin { if user.Loggedin {
errmsg := "You're already logged in." LocalError("You're already logged in.",w,r,user)
pi := Page{"Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
errpage := b.String()
w.WriteHeader(500)
fmt.Fprintln(w,errpage)
return return
} }
pi := Page{"Login","login",user,noticeList,tList,0} pi := Page{"Login","login",user,noticeList,tList,0}
templates.ExecuteTemplate(w,"login.html", pi) templates.ExecuteTemplate(w,"login.html", pi)
} }
@ -1240,16 +1181,8 @@ func route_login_submit(w http.ResponseWriter, r *http.Request) {
if !ok { if !ok {
return return
} }
if user.Loggedin { if user.Loggedin {
errmsg := "You're already logged in." LocalError("You're already logged in.",w,r,user)
pi := Page{"Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
errpage := b.String()
w.WriteHeader(500)
fmt.Fprintln(w,errpage)
return return
} }
@ -1268,14 +1201,7 @@ func route_login_submit(w http.ResponseWriter, r *http.Request) {
err = login_stmt.QueryRow(username).Scan(&uid, &username, &real_password, &salt) err = login_stmt.QueryRow(username).Scan(&uid, &username, &real_password, &salt)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
errmsg := "That username doesn't exist." LocalError("That username doesn't exist.",w,r,user)
pi := Page{"Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
errpage := b.String()
w.WriteHeader(500)
fmt.Fprintln(w,errpage)
return return
} else if err != nil { } else if err != nil {
InternalError(err,w,r,user) InternalError(err,w,r,user)
@ -1285,14 +1211,7 @@ func route_login_submit(w http.ResponseWriter, r *http.Request) {
// Emergency password reset mechanism.. // Emergency password reset mechanism..
if salt == "" { if salt == "" {
if password != real_password { if password != real_password {
errmsg := "That's not the correct password." LocalError("That's not the correct password.",w,r,user)
pi := Page{"Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
errpage := b.String()
w.WriteHeader(500)
fmt.Fprintln(w,errpage)
return return
} }
@ -1307,14 +1226,7 @@ func route_login_submit(w http.ResponseWriter, r *http.Request) {
err := bcrypt.CompareHashAndPassword([]byte(real_password), []byte(password)) err := bcrypt.CompareHashAndPassword([]byte(real_password), []byte(password))
if err == bcrypt.ErrMismatchedHashAndPassword { if err == bcrypt.ErrMismatchedHashAndPassword {
errmsg := "That's not the correct password." LocalError("That's not the correct password.",w,r,user)
pi := Page{"Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
errpage := b.String()
w.WriteHeader(500)
fmt.Fprintln(w,errpage)
return return
} else if err != nil { } else if err != nil {
InternalError(err,w,r,user) InternalError(err,w,r,user)
@ -1347,17 +1259,9 @@ func route_register(w http.ResponseWriter, r *http.Request) {
return return
} }
if user.Loggedin { if user.Loggedin {
errmsg := "You're already logged in." LocalError("You're already logged in.",w,r,user)
pi := Page{"Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
errpage := b.String()
w.WriteHeader(500)
fmt.Fprintln(w,errpage)
return return
} }
pi := Page{"Registration","register",user,noticeList,tList,0} pi := Page{"Registration","register",user,noticeList,tList,0}
templates.ExecuteTemplate(w,"register.html", pi) templates.ExecuteTemplate(w,"register.html", pi)
} }
@ -1367,7 +1271,6 @@ func route_register_submit(w http.ResponseWriter, r *http.Request) {
if !ok { if !ok {
return return
} }
err := r.ParseForm() err := r.ParseForm()
if err != nil { if err != nil {
LocalError("Bad Form", w, r, user) LocalError("Bad Form", w, r, user)
@ -1400,14 +1303,7 @@ func route_register_submit(w http.ResponseWriter, r *http.Request) {
// Do the two inputted passwords match..? // Do the two inputted passwords match..?
if password != confirm_password { if password != confirm_password {
errmsg := "The two passwords don't match." LocalError("The two passwords don't match.",w,r,user)
pi := Page{"Password Mismatch","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
errpage := b.String()
w.WriteHeader(500)
fmt.Fprintln(w,errpage)
return return
} }
@ -1417,14 +1313,7 @@ func route_register_submit(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r,user) InternalError(err,w,r,user)
return return
} else if err != sql.ErrNoRows { } else if err != sql.ErrNoRows {
errmsg := "This username isn't available. Try another." LocalError("This username isn't available. Try another.",w,r,user)
pi := Page{"Username Taken","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
errpage := b.String()
w.WriteHeader(500)
fmt.Fprintln(w,errpage)
return return
} }
@ -1433,7 +1322,6 @@ func route_register_submit(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r,user) InternalError(err,w,r,user)
return return
} }
session, err := GenerateSafeString(sessionLength) session, err := GenerateSafeString(sessionLength)
if err != nil { if err != nil {
InternalError(err,w,r,user) InternalError(err,w,r,user)

View File

@ -1,3 +1,8 @@
@echo off
go build go build
if %errorlevel% neq 0 (
pause
exit /b %errorlevel%
)
gosora.exe gosora.exe
pause pause

View File

@ -1,7 +1,7 @@
/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */ /* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */
package main package main
import "io"
import "strconv" import "strconv"
import "io"
func init() { func init() {
template_profile_handle = template_profile template_profile_handle = template_profile

View File

@ -120,10 +120,14 @@ w.Write([]byte(`0px;background-repeat: no-repeat, repeat-y;background-size: 128p
} }
w.Write([]byte(`"> w.Write([]byte(`">
<p class="hide_on_edit topic_content user_content" style="margin: 0;padding: 0;">` + string(tmpl_topic_vars.Topic.Content.(template.HTML)) + `</p> <p class="hide_on_edit topic_content user_content" style="margin: 0;padding: 0;">` + string(tmpl_topic_vars.Topic.Content.(template.HTML)) + `</p>
<textarea name="topic_content" class="show_on_edit topic_content_input">` + string(tmpl_topic_vars.Topic.Content.(template.HTML)) + `</textarea> <textarea name="topic_content" class="show_on_edit topic_content_input">` + string(tmpl_topic_vars.Topic.Content.(template.HTML)) + `</textarea><br /><br />
<br /><br />
<a href="/user/` + strconv.Itoa(tmpl_topic_vars.Topic.CreatedBy) + `" class="username real_username">` + tmpl_topic_vars.Topic.CreatedByName + `</a> <a href="/user/` + strconv.Itoa(tmpl_topic_vars.Topic.CreatedBy) + `" class="username real_username">` + tmpl_topic_vars.Topic.CreatedByName + `</a>
`)) `))
if tmpl_topic_vars.Topic.Level != -1 {
w.Write([]byte(`<a class="username level hide_on_mobile" title="Level ` + strconv.Itoa(tmpl_topic_vars.Topic.Level) + `">L` + strconv.Itoa(tmpl_topic_vars.Topic.Level) + `</a>`))
}
w.Write([]byte(`
`))
if tmpl_topic_vars.Topic.Tag != "" { if tmpl_topic_vars.Topic.Tag != "" {
w.Write([]byte(`<a class="username hide_on_micro" style="float: right;">` + tmpl_topic_vars.Topic.Tag + `</a>`)) w.Write([]byte(`<a class="username hide_on_micro" style="float: right;">` + tmpl_topic_vars.Topic.Tag + `</a>`))
} else { } else {
@ -151,6 +155,11 @@ w.Write([]byte(`">
<p class="editable_block user_content" style="margin: 0;padding: 0;">` + string(item.ContentHtml) + `</p><br /><br /> <p class="editable_block user_content" style="margin: 0;padding: 0;">` + string(item.ContentHtml) + `</p><br /><br />
<a href="/user/` + strconv.Itoa(item.CreatedBy) + `" class="username real_username">` + item.CreatedByName + `</a> <a href="/user/` + strconv.Itoa(item.CreatedBy) + `" class="username real_username">` + item.CreatedByName + `</a>
`)) `))
if item.Level != -1 {
w.Write([]byte(`<a class="username level hide_on_mobile" title="Level ` + strconv.Itoa(item.Level) + `">L` + strconv.Itoa(item.Level) + `</a>`))
}
w.Write([]byte(`
`))
if tmpl_topic_vars.CurrentUser.Perms.EditReply { if tmpl_topic_vars.CurrentUser.Perms.EditReply {
w.Write([]byte(`<a href="/reply/edit/submit/` + strconv.Itoa(item.ID) + `" class="mod_button"><button class="username edit_item">Edit</button></a>`)) w.Write([]byte(`<a href="/reply/edit/submit/` + strconv.Itoa(item.ID) + `" class="mod_button"><button class="username edit_item">Edit</button></a>`))
} }

View File

@ -304,7 +304,6 @@ func (c *CTemplateSet) compile_subswitch(varholder string, holdreflect reflect.V
} else { } else {
varbit += "." + id varbit += "." + id
} }
if debug { if debug {
fmt.Println("End Cycle") fmt.Println("End Cycle")
} }
@ -331,9 +330,8 @@ func (c *CTemplateSet) compile_subswitch(varholder string, holdreflect reflect.V
fmt.Println(n.String()) fmt.Println(n.String())
fmt.Println(n.Ident) fmt.Println(n.Ident)
} }
varname, reflectVal := c.compile_if_varsub(n.String(), varholder, template_name, holdreflect)
out, _ = c.compile_if_varsub(n.String(), varholder, template_name, holdreflect) return c.compile_varsub(varname, reflectVal)
return "w.Write([]byte(" + out + "))\n"
case *parse.StringNode: case *parse.StringNode:
return n.Quoted return n.Quoted
default: default:
@ -429,6 +427,21 @@ func (c *CTemplateSet) compile_identswitch(varholder string, holdreflect reflect
case "le": case "le":
out += c.compile_if_varsub_n(node.Args[pos + 1].String(), varholder, template_name, holdreflect) + " <= " + c.compile_if_varsub_n(node.Args[pos + 2].String(), varholder, template_name, holdreflect) out += c.compile_if_varsub_n(node.Args[pos + 1].String(), varholder, template_name, holdreflect) + " <= " + c.compile_if_varsub_n(node.Args[pos + 2].String(), varholder, template_name, holdreflect)
break ArgLoop break ArgLoop
case "lt":
out += c.compile_if_varsub_n(node.Args[pos + 1].String(), varholder, template_name, holdreflect) + " < " + c.compile_if_varsub_n(node.Args[pos + 2].String(), varholder, template_name, holdreflect)
break ArgLoop
case "gt":
out += c.compile_if_varsub_n(node.Args[pos + 1].String(), varholder, template_name, holdreflect) + " > " + c.compile_if_varsub_n(node.Args[pos + 2].String(), varholder, template_name, holdreflect)
break ArgLoop
case "ge":
out += c.compile_if_varsub_n(node.Args[pos + 1].String(), varholder, template_name, holdreflect) + " >= " + c.compile_if_varsub_n(node.Args[pos + 2].String(), varholder, template_name, holdreflect)
break ArgLoop
case "eq":
out += c.compile_if_varsub_n(node.Args[pos + 1].String(), varholder, template_name, holdreflect) + " == " + c.compile_if_varsub_n(node.Args[pos + 2].String(), varholder, template_name, holdreflect)
break ArgLoop
case "ne":
out += c.compile_if_varsub_n(node.Args[pos + 1].String(), varholder, template_name, holdreflect) + " != " + c.compile_if_varsub_n(node.Args[pos + 2].String(), varholder, template_name, holdreflect)
break ArgLoop
default: default:
if debug { if debug {
fmt.Println("Variable!") fmt.Println("Variable!")

View File

@ -23,9 +23,9 @@
<div class="rowblock post_container"> <div class="rowblock post_container">
<div class="rowitem passive editable_parent post_item" style="border-bottom: none;{{ if .Topic.Avatar }}background-image: url({{ .Topic.Avatar }}), url(/static/white-dot.jpg);background-position: 0px {{if le .Topic.ContentLines 5}}-1{{end}}0px;background-repeat: no-repeat, repeat-y;background-size: 128px;padding-left: 136px;{{.Topic.Css}}{{end}}"> <div class="rowitem passive editable_parent post_item" style="border-bottom: none;{{ if .Topic.Avatar }}background-image: url({{ .Topic.Avatar }}), url(/static/white-dot.jpg);background-position: 0px {{if le .Topic.ContentLines 5}}-1{{end}}0px;background-repeat: no-repeat, repeat-y;background-size: 128px;padding-left: 136px;{{.Topic.Css}}{{end}}">
<p class="hide_on_edit topic_content user_content" style="margin: 0;padding: 0;">{{.Topic.Content}}</p> <p class="hide_on_edit topic_content user_content" style="margin: 0;padding: 0;">{{.Topic.Content}}</p>
<textarea name="topic_content" class="show_on_edit topic_content_input">{{.Topic.Content}}</textarea> <textarea name="topic_content" class="show_on_edit topic_content_input">{{.Topic.Content}}</textarea><br /><br />
<br /><br />
<a href="/user/{{.Topic.CreatedBy}}" class="username real_username">{{.Topic.CreatedByName}}</a> <a href="/user/{{.Topic.CreatedBy}}" class="username real_username">{{.Topic.CreatedByName}}</a>
{{if ne .Topic.Level -1}}<a class="username level hide_on_mobile" title="Level {{.Topic.Level}}">L{{.Topic.Level}}</a>{{end}}
{{if .Topic.Tag}}<a class="username hide_on_micro" style="float: right;">{{.Topic.Tag}}</a>{{else if .Topic.URLName}}<a href="{{.Topic.URL}}" class="username" style="color: #505050;float: right;">{{.Topic.URLName}}</a> {{if .Topic.Tag}}<a class="username hide_on_micro" style="float: right;">{{.Topic.Tag}}</a>{{else if .Topic.URLName}}<a href="{{.Topic.URL}}" class="username" style="color: #505050;float: right;">{{.Topic.URLName}}</a>
<a class="username" style="color: #505050;float: right;border-right: 0;">{{.Topic.URLPrefix}}</a>{{end}} <a class="username" style="color: #505050;float: right;border-right: 0;">{{.Topic.URLPrefix}}</a>{{end}}
</div> </div>
@ -34,6 +34,7 @@
<div class="rowitem rowhead passive deletable_block editable_parent post_item" style="{{ if .Avatar }}background-image: url({{.Avatar}}), url(/static/white-dot.jpg);background-position: 0px {{if le .ContentLines 5}}-1{{end}}0px;background-repeat: no-repeat, repeat-y;background-size: 128px;padding-left: 136px;{{.Css}}{{end}}"> <div class="rowitem rowhead passive deletable_block editable_parent post_item" style="{{ if .Avatar }}background-image: url({{.Avatar}}), url(/static/white-dot.jpg);background-position: 0px {{if le .ContentLines 5}}-1{{end}}0px;background-repeat: no-repeat, repeat-y;background-size: 128px;padding-left: 136px;{{.Css}}{{end}}">
<p class="editable_block user_content" style="margin: 0;padding: 0;">{{.ContentHtml}}</p><br /><br /> <p class="editable_block user_content" style="margin: 0;padding: 0;">{{.ContentHtml}}</p><br /><br />
<a href="/user/{{.CreatedBy}}" class="username real_username">{{.CreatedByName}}</a> <a href="/user/{{.CreatedBy}}" class="username real_username">{{.CreatedByName}}</a>
{{if ne .Level -1}}<a class="username level hide_on_mobile" title="Level {{.Level}}">L{{.Level}}</a>{{end}}
{{if $.CurrentUser.Perms.EditReply}}<a href="/reply/edit/submit/{{.ID}}" class="mod_button"><button class="username edit_item">Edit</button></a>{{end}} {{if $.CurrentUser.Perms.EditReply}}<a href="/reply/edit/submit/{{.ID}}" class="mod_button"><button class="username edit_item">Edit</button></a>{{end}}
{{if $.CurrentUser.Perms.DeleteReply}}<a href="/reply/delete/submit/{{.ID}}" class="mod_button"><button class="username delete_item">Delete</button></a>{{end}} {{if $.CurrentUser.Perms.DeleteReply}}<a href="/reply/delete/submit/{{.ID}}" class="mod_button"><button class="username delete_item">Delete</button></a>{{end}}
<a href="/report/submit/{{.ID}}?session={{$.CurrentUser.Session}}&type=reply" class="mod_button"><button class="username report_item">Report</button></a> <a href="/report/submit/{{.ID}}?session={{$.CurrentUser.Session}}&type=reply" class="mod_button"><button class="username report_item">Report</button></a>

View File

@ -34,4 +34,5 @@ type TopicUser struct
URL string URL string
URLPrefix string URLPrefix string
URLName string URLName string
Level int
} }

View File

@ -1,3 +1,13 @@
@echo off
go get -u github.com/go-sql-driver/mysql go get -u github.com/go-sql-driver/mysql
if %errorlevel% neq 0 (
pause
exit /b %errorlevel%
)
go get -u golang.org/x/crypto/bcrypt go get -u golang.org/x/crypto/bcrypt
if %errorlevel% neq 0 (
pause
exit /b %errorlevel%
)
echo The dependencies were successfully updated
pause pause

85
user.go
View File

@ -1,4 +1,5 @@
package main package main
import "fmt"
import "strings" import "strings"
import "strconv" import "strconv"
import "net/http" import "net/http"
@ -26,6 +27,8 @@ type User struct
URLPrefix string URLPrefix string
URLName string URLName string
Tag string Tag string
Level int
Score int
} }
type Email struct type Email struct
@ -92,7 +95,7 @@ func SessionCheck(w http.ResponseWriter, r *http.Request) (user User, noticeList
user.Session = cookie.Value user.Session = cookie.Value
// Is this session valid..? // Is this session valid..?
err = get_session_stmt.QueryRow(user.ID,user.Session).Scan(&user.ID, &user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName) err = get_session_stmt.QueryRow(user.ID,user.Session).Scan(&user.ID, &user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
user.ID = 0 user.ID = 0
user.Session = "" user.Session = ""
@ -154,7 +157,7 @@ func SimpleSessionCheck(w http.ResponseWriter, r *http.Request) (user User, succ
user.Session = cookie.Value user.Session = cookie.Value
// Is this session valid..? // Is this session valid..?
err = get_session_stmt.QueryRow(user.ID,user.Session).Scan(&user.ID, &user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName) err = get_session_stmt.QueryRow(user.ID,user.Session).Scan(&user.ID, &user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
user.ID = 0 user.ID = 0
user.Session = "" user.Session = ""
@ -188,4 +191,80 @@ func SimpleSessionCheck(w http.ResponseWriter, r *http.Request) (user User, succ
user.Avatar = strings.Replace(noavatar,"{id}",strconv.Itoa(user.ID),1) user.Avatar = strings.Replace(noavatar,"{id}",strconv.Itoa(user.ID),1)
} }
return user, true return user, true
} }
func increase_post_user_stats(wcount int, uid int, topic bool, user User) error {
var mod int
base_score := 1
if topic {
_, err := increment_user_topics_stmt.Exec(1, uid)
if err != nil {
return err
}
base_score = 2
}
if wcount > settings["megapost_min_chars"].(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) {
_, err := increment_user_bigposts_stmt.Exec(1,1,uid)
if err != nil {
return err
}
mod = 1
} else {
_, err := increment_user_posts_stmt.Exec(1,uid)
if err != nil {
return err
}
}
_, err := increment_user_score_stmt.Exec(base_score + mod, uid)
if err != nil {
return err
}
fmt.Println(user.Score + base_score + mod)
fmt.Println(getLevel(user.Score + base_score + mod))
_, err = update_user_level_stmt.Exec(getLevel(user.Score + base_score + mod), uid)
return err
}
func decrease_post_user_stats(wcount int, uid int, topic bool, user User) error {
var mod int
base_score := -1
if topic {
_, err := increment_user_topics_stmt.Exec(-1, uid)
if err != nil {
return err
}
base_score = -2
}
if wcount > settings["megapost_min_chars"].(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) {
_, err := increment_user_bigposts_stmt.Exec(-1,-1,uid)
if err != nil {
return err
}
mod = 1
} else {
_, err := increment_user_posts_stmt.Exec(-1,uid)
if err != nil {
return err
}
}
_, err := increment_user_score_stmt.Exec(base_score - mod, uid)
if err != nil {
return err
}
_, err = update_user_level_stmt.Exec(getLevel(user.Score - base_score - mod), uid)
return err
}

View File

@ -3,6 +3,9 @@ import "log"
import "fmt" import "fmt"
import "time" import "time"
import "os" import "os"
import "math"
import "strings"
import "unicode"
import "encoding/base64" import "encoding/base64"
import "crypto/rand" import "crypto/rand"
import "net/smtp" import "net/smtp"
@ -103,3 +106,84 @@ func write_file(name string, content string) {
f.Sync() f.Sync()
f.Close() f.Close()
} }
func word_count(input string) int {
input = strings.TrimSpace(input)
count := 0
in_space := false
for _, value := range input {
if unicode.IsSpace(value) {
if !in_space {
in_space = true
}
} else if in_space {
count++
in_space = false
}
}
return count
}
func getLevel(score int) (level int) {
var base float64 = 25
var current float64
var prev float64
exp_factor := 2.8
for i := 1;;i++ {
_, bit := math.Modf(float64(i) / 10)
if bit == 0 {
exp_factor += 0.1
}
current = base + math.Pow(float64(i), exp_factor) + (prev / 3)
prev = current
if float64(score) < current {
break
} else {
level++
}
}
return level
}
func getLevelScore(getLevel int) (score int) {
var base float64 = 25
var current float64
var prev float64
var level int
exp_factor := 2.8
for i := 1;;i++ {
_, bit := math.Modf(float64(i) / 10)
if bit == 0 {
exp_factor += 0.1
}
current = base + math.Pow(float64(i), exp_factor) + (prev / 3)
prev = current
level++
if level <= getLevel {
break
}
}
return int(math.Ceil(current))
}
func getLevels(maxLevel int) []float64 {
var base float64 = 25
var current float64 = 0
var prev float64 = 0
exp_factor := 2.8
var out []float64
out = append(out, 0)
for i := 1;i <= maxLevel;i++ {
_, bit := math.Modf(float64(i) / 10)
if bit == 0 {
exp_factor += 0.1
}
current = base + math.Pow(float64(i), exp_factor) + (prev / 3)
prev = current
out = append(out, current)
}
return out
}