2016-12-02 07:38:54 +00:00
package main
2016-12-06 10:26:48 +00:00
import "errors"
2016-12-02 07:38:54 +00:00
import "log"
import "fmt"
import "strconv"
import "bytes"
2016-12-02 15:03:31 +00:00
import "regexp"
import "strings"
2016-12-05 07:21:17 +00:00
import "time"
2016-12-02 15:03:31 +00:00
import "io"
import "os"
2016-12-02 07:38:54 +00:00
import "net/http"
import "html"
2016-12-03 04:50:35 +00:00
import "html/template"
2016-12-02 07:38:54 +00:00
import "database/sql"
import _ "github.com/go-sql-driver/mysql"
import "golang.org/x/crypto/bcrypt"
// A blank list to fill out that parameter in Page for routes which don't use it
var tList map [ int ] interface { }
// GET functions
2016-12-05 07:21:17 +00:00
func route_static ( w http . ResponseWriter , r * http . Request ) {
//name := r.URL.Path[len("/static/"):]
if t , err := time . Parse ( http . TimeFormat , r . Header . Get ( "If-Modified-Since" ) ) ; err == nil && static_files [ r . URL . Path ] . Info . ModTime ( ) . Before ( t . Add ( 1 * time . Second ) ) {
w . WriteHeader ( http . StatusNotModified )
return
}
h := w . Header ( )
h . Set ( "Last-Modified" , static_files [ r . URL . Path ] . FormattedModTime )
h . Set ( "Content-Type" , static_files [ r . URL . Path ] . Mimetype )
h . Set ( "Content-Length" , strconv . FormatInt ( static_files [ r . URL . Path ] . Length , 10 ) )
//http.ServeContent(w,r,r.URL.Path,static_files[r.URL.Path].Info.ModTime(),static_files[r.URL.Path])
//w.Write(static_files[r.URL.Path].Data)
io . Copy ( w , bytes . NewReader ( static_files [ r . URL . Path ] . Data ) )
//io.CopyN(w, bytes.NewReader(static_files[r.URL.Path].Data), static_files[r.URL.Path].Length)
}
func route_fstatic ( w http . ResponseWriter , r * http . Request ) {
http . ServeFile ( w , r , r . URL . Path )
}
2016-12-02 07:38:54 +00:00
func route_overview ( w http . ResponseWriter , r * http . Request ) {
user := SessionCheck ( w , r )
pi := Page { "Overview" , "overview" , user , tList , 0 }
err := templates . ExecuteTemplate ( w , "overview.html" , pi )
if err != nil {
InternalError ( err , w , r , user )
}
}
func route_custom_page ( w http . ResponseWriter , r * http . Request ) {
user := SessionCheck ( w , r )
2016-12-02 09:29:45 +00:00
name := r . URL . Path [ len ( "/pages/" ) : ]
2016-12-02 07:38:54 +00:00
2016-12-08 14:11:18 +00:00
pi := Page { "Page" , "page" , user , tList , 0 }
err := custom_pages . ExecuteTemplate ( w , name , pi )
if err != nil {
2016-12-06 10:26:48 +00:00
NotFound ( w , r , user )
2016-12-02 07:38:54 +00:00
}
}
func route_topics ( w http . ResponseWriter , r * http . Request ) {
user := SessionCheck ( w , r )
var (
topicList map [ int ] interface { }
currentID int
tid int
title string
content string
createdBy int
is_closed bool
sticky bool
createdAt string
parentID int
status string
2016-12-03 08:09:40 +00:00
name string
avatar string
2016-12-02 07:38:54 +00:00
)
topicList = make ( map [ int ] interface { } )
currentID = 0
2016-12-03 10:25:39 +00:00
rows , err := db . Query ( "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" )
2016-12-02 07:38:54 +00:00
if err != nil {
InternalError ( err , w , r , user )
return
}
defer rows . Close ( )
for rows . Next ( ) {
2016-12-03 08:09:40 +00:00
err := rows . Scan ( & tid , & title , & content , & createdBy , & is_closed , & sticky , & createdAt , & parentID , & name , & avatar )
2016-12-02 07:38:54 +00:00
if err != nil {
InternalError ( err , w , r , user )
return
}
if is_closed {
status = "closed"
} else {
status = "open"
}
2016-12-07 09:34:09 +00:00
if avatar != "" {
if avatar [ 0 ] == '.' {
avatar = "/uploads/avatar_" + strconv . Itoa ( createdBy ) + avatar
}
} else {
avatar = strings . Replace ( noavatar , "{id}" , strconv . Itoa ( createdBy ) , 1 )
2016-12-03 08:09:40 +00:00
}
2016-12-07 09:34:09 +00:00
topicList [ currentID ] = TopicUser { tid , title , content , createdBy , is_closed , sticky , createdAt , parentID , status , name , avatar , "" , 0 , "" }
2016-12-02 07:38:54 +00:00
currentID ++
}
err = rows . Err ( )
if err != nil {
InternalError ( err , w , r , user )
return
}
2016-12-07 13:46:14 +00:00
var msg string
if len ( topicList ) == 0 {
msg = "There aren't any topics yet."
} else {
msg = ""
}
pi := Page { "Topic List" , "topics" , user , topicList , msg }
2016-12-03 04:50:35 +00:00
err = templates . ExecuteTemplate ( w , "topics.html" , pi )
if err != nil {
InternalError ( err , w , r , user )
}
2016-12-02 07:38:54 +00:00
}
2016-12-03 13:45:08 +00:00
func route_forum ( w http . ResponseWriter , r * http . Request ) {
user := SessionCheck ( w , r )
var (
topicList map [ int ] interface { }
currentID int
tid int
title string
content string
createdBy int
is_closed bool
sticky bool
createdAt string
parentID int
status string
name string
avatar string
)
topicList = make ( map [ int ] interface { } )
currentID = 0
fid , err := strconv . Atoi ( r . URL . Path [ len ( "/forum/" ) : ] )
if err != nil {
LocalError ( "The provided ForumID is not a valid number." , w , r , user )
return
}
2016-12-06 10:26:48 +00:00
_ , ok := forums [ fid ]
if ! ok {
NotFound ( w , r , user )
2016-12-03 13:45:08 +00:00
return
}
rows , err := db . Query ( "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 WHERE topics.parentID = ? order by topics.sticky DESC, topics.lastReplyAt DESC, topics.createdBy DESC" , fid )
if err != nil {
InternalError ( err , w , r , user )
return
}
defer rows . Close ( )
for rows . Next ( ) {
err := rows . Scan ( & tid , & title , & content , & createdBy , & is_closed , & sticky , & createdAt , & parentID , & name , & avatar )
if err != nil {
InternalError ( err , w , r , user )
return
}
if is_closed {
status = "closed"
} else {
status = "open"
}
2016-12-07 09:34:09 +00:00
if avatar != "" {
if avatar [ 0 ] == '.' {
avatar = "/uploads/avatar_" + strconv . Itoa ( createdBy ) + avatar
}
} else {
avatar = strings . Replace ( noavatar , "{id}" , strconv . Itoa ( createdBy ) , 1 )
2016-12-03 13:45:08 +00:00
}
2016-12-07 09:34:09 +00:00
topicList [ currentID ] = TopicUser { tid , title , content , createdBy , is_closed , sticky , createdAt , parentID , status , name , avatar , "" , 0 , "" }
2016-12-03 13:45:08 +00:00
currentID ++
}
err = rows . Err ( )
if err != nil {
InternalError ( err , w , r , user )
return
}
2016-12-07 13:46:14 +00:00
var msg string
if len ( topicList ) == 0 {
msg = "There aren't any topics in this forum yet."
} else {
msg = ""
}
pi := Page { forums [ fid ] . Name , "forum" , user , topicList , msg }
2016-12-03 13:45:08 +00:00
err = templates . ExecuteTemplate ( w , "forum.html" , pi )
if err != nil {
InternalError ( err , w , r , user )
}
}
func route_forums ( w http . ResponseWriter , r * http . Request ) {
user := SessionCheck ( w , r )
2016-12-06 10:26:48 +00:00
var forumList map [ int ] interface { } = make ( map [ int ] interface { } )
2016-12-03 13:45:08 +00:00
currentID := 0
2016-12-06 10:26:48 +00:00
for _ , forum := range forums {
if forum . Active {
forumList [ currentID ] = forum
currentID ++
2016-12-03 13:45:08 +00:00
}
}
2016-12-06 10:26:48 +00:00
if len ( forums ) == 0 {
InternalError ( errors . New ( "No forums" ) , w , r , user )
2016-12-03 13:45:08 +00:00
return
}
2016-12-06 10:26:48 +00:00
2016-12-03 13:45:08 +00:00
pi := Page { "Forum List" , "forums" , user , forumList , 0 }
2016-12-06 10:26:48 +00:00
err := templates . ExecuteTemplate ( w , "forums.html" , pi )
2016-12-03 13:45:08 +00:00
if err != nil {
InternalError ( err , w , r , user )
}
}
2016-12-02 07:38:54 +00:00
func route_topic_id ( w http . ResponseWriter , r * http . Request ) {
user := SessionCheck ( w , r )
var (
2016-12-03 04:50:35 +00:00
err error
2016-12-02 07:38:54 +00:00
rid int
content string
replyContent string
replyCreatedBy int
replyCreatedByName string
replyCreatedAt string
replyLastEdit int
replyLastEditBy int
2016-12-02 15:03:31 +00:00
replyAvatar string
2016-12-04 06:16:59 +00:00
replyCss template . CSS
2016-12-07 09:34:09 +00:00
replyLines int
replyTag string
2016-12-04 06:16:59 +00:00
is_super_admin bool
group int
2016-12-02 07:38:54 +00:00
currentID int
replyList map [ int ] interface { }
)
replyList = make ( map [ int ] interface { } )
currentID = 0
2016-12-07 09:34:09 +00:00
topic := TopicUser { 0 , "" , "" , 0 , false , false , "" , 0 , "" , "" , "" , no_css_tmpl , 0 , "" }
2016-12-02 07:38:54 +00:00
2016-12-03 04:50:35 +00:00
topic . ID , err = strconv . Atoi ( r . URL . Path [ len ( "/topic/" ) : ] )
2016-12-02 07:38:54 +00:00
if err != nil {
LocalError ( "The provided TopicID is not a valid number." , w , r , user )
return
}
// Get the topic..
//err = db.QueryRow("select title, content, createdBy, status, is_closed from topics where tid = ?", tid).Scan(&title, &content, &createdBy, &status, &is_closed)
2016-12-04 06:16:59 +00:00
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 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 )
2016-12-02 07:38:54 +00:00
if err == sql . ErrNoRows {
2016-12-06 10:26:48 +00:00
NotFound ( w , r , user )
2016-12-02 07:38:54 +00:00
return
} else if err != nil {
InternalError ( err , w , r , user )
return
}
2016-12-04 06:16:59 +00:00
topic . Content = template . HTML ( parse_message ( content ) )
2016-12-07 09:34:09 +00:00
topic . ContentLines = strings . Count ( content , "\n" )
2016-12-03 04:50:35 +00:00
if topic . Is_Closed {
topic . Status = "closed"
2016-12-02 07:38:54 +00:00
} else {
2016-12-03 04:50:35 +00:00
topic . Status = "open"
}
2016-12-07 09:34:09 +00:00
if topic . Avatar != "" {
if topic . Avatar [ 0 ] == '.' {
topic . Avatar = "/uploads/avatar_" + strconv . Itoa ( topic . CreatedBy ) + topic . Avatar
}
} else {
topic . Avatar = strings . Replace ( noavatar , "{id}" , strconv . Itoa ( topic . CreatedBy ) , 1 )
2016-12-02 07:38:54 +00:00
}
2016-12-07 13:46:14 +00:00
if is_super_admin || groups [ group ] . Is_Mod || groups [ group ] . Is_Admin {
2016-12-04 06:16:59 +00:00
topic . Css = staff_css_tmpl
}
2016-12-07 09:34:09 +00:00
if groups [ group ] . Tag != "" {
topic . Tag = groups [ group ] . Tag
} else {
topic . Tag = ""
}
2016-12-02 07:38:54 +00:00
// Get the replies..
//rows, err := db.Query("select rid, content, createdBy, createdAt from replies where tid = ?", tid)
2016-12-04 06:16:59 +00:00
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 from replies left join users ON replies.createdBy = users.uid where tid = ?" , topic . ID )
2016-12-02 07:38:54 +00:00
if err != nil {
InternalError ( err , w , r , user )
return
}
defer rows . Close ( )
for rows . Next ( ) {
2016-12-04 06:16:59 +00:00
err := rows . Scan ( & rid , & replyContent , & replyCreatedBy , & replyCreatedAt , & replyLastEdit , & replyLastEditBy , & replyAvatar , & replyCreatedByName , & is_super_admin , & group )
2016-12-02 07:38:54 +00:00
if err != nil {
InternalError ( err , w , r , user )
return
}
2016-12-02 15:03:31 +00:00
2016-12-07 09:34:09 +00:00
replyLines = strings . Count ( replyContent , "\n" )
2016-12-07 13:46:14 +00:00
if is_super_admin || groups [ group ] . Is_Mod || groups [ group ] . Is_Admin {
2016-12-04 06:16:59 +00:00
replyCss = staff_css_tmpl
} else {
replyCss = no_css_tmpl
}
2016-12-07 09:34:09 +00:00
if replyAvatar != "" {
if replyAvatar [ 0 ] == '.' {
replyAvatar = "/uploads/avatar_" + strconv . Itoa ( replyCreatedBy ) + replyAvatar
}
} else {
replyAvatar = strings . Replace ( noavatar , "{id}" , strconv . Itoa ( replyCreatedBy ) , 1 )
}
if groups [ group ] . Tag != "" {
replyTag = groups [ group ] . Tag
} else {
replyTag = ""
2016-12-02 15:03:31 +00:00
}
2016-12-07 09:34:09 +00:00
replyList [ currentID ] = Reply { rid , topic . ID , replyContent , template . HTML ( parse_message ( replyContent ) ) , replyCreatedBy , replyCreatedByName , replyCreatedAt , replyLastEdit , replyLastEditBy , replyAvatar , replyCss , replyLines , replyTag }
2016-12-02 07:38:54 +00:00
currentID ++
}
err = rows . Err ( )
if err != nil {
InternalError ( err , w , r , user )
return
}
2016-12-03 04:50:35 +00:00
pi := Page { topic . Title , "topic" , user , replyList , topic }
err = templates . ExecuteTemplate ( w , "topic.html" , pi )
if err != nil {
InternalError ( err , w , r , user )
}
2016-12-02 07:38:54 +00:00
}
2016-12-07 09:34:09 +00:00
func route_profile ( w http . ResponseWriter , r * http . Request ) {
user := SessionCheck ( w , r )
var (
err error
rid int
replyContent string
replyCreatedBy int
replyCreatedByName string
replyCreatedAt string
replyLastEdit int
replyLastEditBy int
replyAvatar string
replyCss template . CSS
replyLines int
replyTag string
is_super_admin bool
group int
currentID int
replyList map [ int ] interface { }
)
replyList = make ( map [ int ] interface { } )
currentID = 0
2016-12-07 13:46:14 +00:00
puser := User { 0 , "" , 0 , false , false , false , false , false , "" , false , "" }
2016-12-07 09:34:09 +00:00
puser . ID , err = strconv . Atoi ( r . URL . Path [ len ( "/user/" ) : ] )
if err != nil {
LocalError ( "The provided TopicID is not a valid number." , w , r , user )
return
}
2016-12-07 13:46:14 +00:00
if puser . ID == user . ID {
user . Is_Mod = true
puser = user
} else {
// Fetch the user data
err = db . QueryRow ( "SELECT `name`, `group`, `is_super_admin`, `avatar` FROM `users` WHERE `uid` = ?" , puser . ID ) . Scan ( & puser . Name , & puser . Group , & puser . Is_Super_Admin , & puser . Avatar )
if err == sql . ErrNoRows {
NotFound ( w , r , user )
return
} else if err != nil {
InternalError ( err , w , r , user )
return
}
puser . Is_Admin = puser . Is_Super_Admin || groups [ puser . Group ] . Is_Admin
puser . Is_Super_Mod = puser . Is_Admin || groups [ puser . Group ] . Is_Mod
puser . Is_Mod = puser . Is_Super_Mod
2016-12-08 14:11:18 +00:00
puser . Is_Banned = groups [ puser . Group ] . Is_Banned
if puser . Is_Banned && puser . Is_Super_Mod {
puser . Is_Banned = false
}
2016-12-07 09:34:09 +00:00
}
if puser . Avatar != "" {
if puser . Avatar [ 0 ] == '.' {
puser . Avatar = "/uploads/avatar_" + strconv . Itoa ( puser . ID ) + puser . Avatar
}
} else {
puser . Avatar = strings . Replace ( noavatar , "{id}" , strconv . Itoa ( puser . ID ) , 1 )
}
// Get the replies..
rows , err := db . Query ( "select users_replies.rid, users_replies.content, users_replies.createdBy, users_replies.createdAt, users_replies.lastEdit, users_replies.lastEditBy, users.avatar, users.name, users.is_super_admin, users.group from users_replies left join users ON users_replies.createdBy = users.uid where users_replies.uid = ?" , puser . ID )
if err != nil {
InternalError ( err , w , r , user )
return
}
defer rows . Close ( )
for rows . Next ( ) {
err := rows . Scan ( & rid , & replyContent , & replyCreatedBy , & replyCreatedAt , & replyLastEdit , & replyLastEditBy , & replyAvatar , & replyCreatedByName , & is_super_admin , & group )
if err != nil {
InternalError ( err , w , r , user )
return
}
replyLines = strings . Count ( replyContent , "\n" )
2016-12-07 13:46:14 +00:00
if is_super_admin || groups [ group ] . Is_Mod || groups [ group ] . Is_Admin {
2016-12-07 09:34:09 +00:00
replyCss = staff_css_tmpl
} else {
replyCss = no_css_tmpl
}
if replyAvatar != "" {
if replyAvatar [ 0 ] == '.' {
replyAvatar = "/uploads/avatar_" + strconv . Itoa ( replyCreatedBy ) + replyAvatar
}
} else {
replyAvatar = strings . Replace ( noavatar , "{id}" , strconv . Itoa ( replyCreatedBy ) , 1 )
}
if groups [ group ] . Tag != "" {
replyTag = groups [ group ] . Tag
} else if puser . ID == replyCreatedBy {
replyTag = "Profile Owner"
} else {
replyTag = ""
}
replyList [ currentID ] = Reply { rid , puser . ID , replyContent , template . HTML ( parse_message ( replyContent ) ) , replyCreatedBy , replyCreatedByName , replyCreatedAt , replyLastEdit , replyLastEditBy , replyAvatar , replyCss , replyLines , replyTag }
currentID ++
}
err = rows . Err ( )
if err != nil {
InternalError ( err , w , r , user )
return
}
2016-12-02 07:38:54 +00:00
2016-12-07 09:34:09 +00:00
pi := Page { puser . Name + "'s Profile" , "profile" , user , replyList , puser }
err = templates . ExecuteTemplate ( w , "profile.html" , pi )
if err != nil {
InternalError ( err , w , r , user )
}
}
2016-12-02 07:38:54 +00:00
func route_topic_create ( w http . ResponseWriter , r * http . Request ) {
user := SessionCheck ( w , r )
2016-12-04 10:44:28 +00:00
if user . Is_Banned {
Banned ( w , r , user )
return
}
2016-12-02 07:38:54 +00:00
pi := Page { "Create Topic" , "create-topic" , user , tList , 0 }
templates . ExecuteTemplate ( w , "create-topic.html" , pi )
}
// POST functions. Authorised users only.
func route_create_topic ( w http . ResponseWriter , r * http . Request ) {
user := SessionCheck ( w , r )
if ! user . Loggedin {
LoginRequired ( w , r , user )
return
}
2016-12-04 10:44:28 +00:00
if user . Is_Banned {
Banned ( w , r , user )
return
}
2016-12-02 07:38:54 +00:00
err := r . ParseForm ( )
2016-12-02 11:00:07 +00:00
if err != nil {
LocalError ( "Bad Form" , w , r , user )
2016-12-02 07:38:54 +00:00
return
2016-12-02 11:00:07 +00:00
}
2016-12-02 07:38:54 +00:00
success := 1
2016-12-03 13:45:08 +00:00
topic_name := html . EscapeString ( r . PostFormValue ( "topic-name" ) )
2016-12-02 07:38:54 +00:00
2016-12-08 14:11:18 +00:00
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 )
2016-12-02 07:38:54 +00:00
if err != nil {
log . Print ( err )
success = 0
}
lastId , err := res . LastInsertId ( )
if err != nil {
log . Print ( err )
success = 0
}
2016-12-03 13:45:08 +00:00
_ , err = update_forum_cache_stmt . Exec ( topic_name , lastId , user . Name , user . ID , 1 )
if err != nil {
InternalError ( err , w , r , user )
return
}
2016-12-02 07:38:54 +00:00
if success != 1 {
errmsg := "Unable to create the topic"
pi := Page { "Error" , "error" , user , tList , errmsg }
var b bytes . Buffer
templates . ExecuteTemplate ( & b , "error.html" , pi )
errpage := b . String ( )
2016-12-03 11:06:47 +00:00
w . WriteHeader ( 500 )
fmt . Fprintln ( w , errpage )
2016-12-02 07:38:54 +00:00
} else {
http . Redirect ( w , r , "/topic/" + strconv . FormatInt ( lastId , 10 ) , http . StatusSeeOther )
}
}
func route_create_reply ( w http . ResponseWriter , r * http . Request ) {
user := SessionCheck ( w , r )
if ! user . Loggedin {
LoginRequired ( w , r , user )
return
}
2016-12-04 10:44:28 +00:00
if user . Is_Banned {
Banned ( w , r , user )
return
}
2016-12-02 07:38:54 +00:00
err := r . ParseForm ( )
2016-12-02 11:00:07 +00:00
if err != nil {
LocalError ( "Bad Form" , w , r , user )
2016-12-02 07:38:54 +00:00
return
2016-12-02 11:00:07 +00:00
}
2016-12-02 07:38:54 +00:00
success := 1
2016-12-03 13:45:08 +00:00
tid , err := strconv . Atoi ( r . PostFormValue ( "tid" ) )
2016-12-02 07:38:54 +00:00
if err != nil {
log . Print ( err )
success = 0
errmsg := "Unable to create the reply"
pi := Page { "Error" , "error" , user , tList , errmsg }
var b bytes . Buffer
templates . ExecuteTemplate ( & b , "error.html" , pi )
errpage := b . String ( )
2016-12-03 11:06:47 +00:00
w . WriteHeader ( 500 )
fmt . Fprintln ( w , errpage )
2016-12-02 07:38:54 +00:00
return
}
2016-12-08 14:11:18 +00:00
content := preparse_message ( html . EscapeString ( r . PostFormValue ( "reply-content" ) ) )
log . Print ( content )
_ , err = create_reply_stmt . Exec ( tid , content , parse_message ( content ) , user . ID )
2016-12-02 07:38:54 +00:00
if err != nil {
log . Print ( err )
success = 0
}
2016-12-03 13:45:08 +00:00
var topic_name string
err = db . QueryRow ( "select title from topics where tid = ?" , tid ) . Scan ( & topic_name )
if err == sql . ErrNoRows {
log . Print ( err )
success = 0
} else if err != nil {
InternalError ( err , w , r , user )
return
}
_ , err = update_forum_cache_stmt . Exec ( topic_name , tid , user . Name , user . ID , 1 )
if err != nil {
InternalError ( err , w , r , user )
return
}
2016-12-02 07:38:54 +00:00
if success != 1 {
errmsg := "Unable to create the reply"
pi := Page { "Error" , "error" , user , tList , errmsg }
var b bytes . Buffer
templates . ExecuteTemplate ( & b , "error.html" , pi )
errpage := b . String ( )
2016-12-03 11:06:47 +00:00
w . WriteHeader ( 500 )
fmt . Fprintln ( w , errpage )
2016-12-02 07:38:54 +00:00
} else {
http . Redirect ( w , r , "/topic/" + strconv . Itoa ( tid ) , http . StatusSeeOther )
}
}
2016-12-07 09:34:09 +00:00
func route_profile_reply_create ( w http . ResponseWriter , r * http . Request ) {
2016-12-02 07:38:54 +00:00
user := SessionCheck ( w , r )
2016-12-07 09:34:09 +00:00
if ! user . Loggedin {
LoginRequired ( w , r , user )
2016-12-02 07:38:54 +00:00
return
}
2016-12-04 10:44:28 +00:00
if user . Is_Banned {
2016-12-07 09:34:09 +00:00
Banned ( w , r , user )
2016-12-03 10:25:39 +00:00
return
}
2016-12-02 07:38:54 +00:00
err := r . ParseForm ( )
2016-12-02 11:00:07 +00:00
if err != nil {
LocalError ( "Bad Form" , w , r , user )
2016-12-02 07:38:54 +00:00
return
2016-12-02 11:00:07 +00:00
}
2016-12-02 07:38:54 +00:00
2016-12-07 09:34:09 +00:00
success := 1
uid , err := strconv . Atoi ( r . PostFormValue ( "uid" ) )
2016-12-02 11:00:07 +00:00
if err != nil {
2016-12-07 09:34:09 +00:00
log . Print ( err )
success = 0
errmsg := "Unable to create the reply"
pi := Page { "Error" , "error" , user , tList , errmsg }
var b bytes . Buffer
templates . ExecuteTemplate ( & b , "error.html" , pi )
errpage := b . String ( )
w . WriteHeader ( 500 )
fmt . Fprintln ( w , errpage )
2016-12-02 07:38:54 +00:00
return
}
2016-12-08 14:11:18 +00:00
_ , 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 )
2016-12-02 07:38:54 +00:00
if err != nil {
2016-12-07 09:34:09 +00:00
log . Print ( err )
success = 0
2016-12-02 07:38:54 +00:00
}
2016-12-07 09:34:09 +00:00
var user_name string
err = db . QueryRow ( "select name from users where uid = ?" , uid ) . Scan ( & user_name )
2016-12-02 07:38:54 +00:00
if err == sql . ErrNoRows {
2016-12-07 09:34:09 +00:00
log . Print ( err )
success = 0
2016-12-02 07:38:54 +00:00
} else if err != nil {
2016-12-07 09:34:09 +00:00
InternalError ( err , w , r , user )
2016-12-02 07:38:54 +00:00
return
}
2016-12-07 09:34:09 +00:00
if success != 1 {
errmsg := "Unable to create the reply"
pi := Page { "Error" , "error" , user , tList , errmsg }
var b bytes . Buffer
templates . ExecuteTemplate ( & b , "error.html" , pi )
errpage := b . String ( )
w . WriteHeader ( 500 )
fmt . Fprintln ( w , errpage )
2016-12-02 07:38:54 +00:00
} else {
2016-12-07 09:34:09 +00:00
http . Redirect ( w , r , "/user/" + strconv . Itoa ( uid ) , http . StatusSeeOther )
2016-12-02 07:38:54 +00:00
}
}
func route_account_own_edit_critical ( w http . ResponseWriter , r * http . Request ) {
user := SessionCheck ( w , r )
if ! user . Loggedin {
errmsg := "You need to login to edit your own account."
pi := Page { "Error" , "error" , user , tList , errmsg }
var b bytes . Buffer
templates . ExecuteTemplate ( & b , "error.html" , pi )
errpage := b . String ( )
2016-12-03 11:06:47 +00:00
w . WriteHeader ( 500 )
fmt . Fprintln ( w , errpage )
2016-12-02 07:38:54 +00:00
return
}
pi := Page { "Edit Password" , "account-own-edit" , user , tList , 0 }
templates . ExecuteTemplate ( w , "account-own-edit.html" , pi )
}
func route_account_own_edit_critical_submit ( w http . ResponseWriter , r * http . Request ) {
user := SessionCheck ( w , r )
if ! user . Loggedin {
errmsg := "You need to login to edit your own account."
pi := Page { "Error" , "error" , user , tList , errmsg }
var b bytes . Buffer
templates . ExecuteTemplate ( & b , "error.html" , pi )
errpage := b . String ( )
2016-12-03 11:06:47 +00:00
w . WriteHeader ( 500 )
fmt . Fprintln ( w , errpage )
2016-12-02 07:38:54 +00:00
return
}
err := r . ParseForm ( )
2016-12-02 11:00:07 +00:00
if err != nil {
LocalError ( "Bad Form" , w , r , user )
2016-12-02 07:38:54 +00:00
return
2016-12-02 11:00:07 +00:00
}
2016-12-02 07:38:54 +00:00
2016-12-02 11:00:07 +00:00
var real_password string
var salt string
current_password := r . PostFormValue ( "account-current-password" )
new_password := r . PostFormValue ( "account-new-password" )
confirm_password := r . PostFormValue ( "account-confirm-password" )
2016-12-02 07:38:54 +00:00
2016-12-02 11:00:07 +00:00
err = get_password_stmt . QueryRow ( user . ID ) . Scan ( & real_password , & salt )
if err == sql . ErrNoRows {
pi := Page { "Error" , "error" , user , tList , "Your account doesn't exist." }
var b bytes . Buffer
templates . ExecuteTemplate ( & b , "error.html" , pi )
errpage := b . String ( )
2016-12-03 11:06:47 +00:00
w . WriteHeader ( 500 )
fmt . Fprintln ( w , errpage )
2016-12-02 11:00:07 +00:00
return
} else if err != nil {
InternalError ( err , w , r , user )
return
}
2016-12-02 07:38:54 +00:00
2016-12-02 11:00:07 +00:00
current_password = current_password + salt
err = bcrypt . CompareHashAndPassword ( [ ] byte ( real_password ) , [ ] byte ( current_password ) )
if err == bcrypt . ErrMismatchedHashAndPassword {
pi := Page { "Error" , "error" , user , tList , "That's not the correct password." }
var b bytes . Buffer
templates . ExecuteTemplate ( & b , "error.html" , pi )
errpage := b . String ( )
2016-12-03 11:06:47 +00:00
w . WriteHeader ( 500 )
fmt . Fprintln ( w , errpage )
2016-12-02 11:00:07 +00:00
return
} else if err != nil {
InternalError ( err , w , r , user )
return
}
if new_password != confirm_password {
pi := Page { "Error" , "error" , user , tList , "The two passwords don't match." }
var b bytes . Buffer
templates . ExecuteTemplate ( & b , "error.html" , pi )
errpage := b . String ( )
2016-12-03 11:06:47 +00:00
w . WriteHeader ( 500 )
fmt . Fprintln ( w , errpage )
2016-12-02 11:00:07 +00:00
return
}
SetPassword ( user . ID , new_password )
2016-12-02 07:38:54 +00:00
2016-12-02 11:00:07 +00:00
// Log the user out as a safety precaution
_ , err = logout_stmt . Exec ( user . ID )
if err != nil {
InternalError ( err , w , r , user )
return
}
pi := Page { "Edit Password" , "account-own-edit-success" , user , tList , 0 }
templates . ExecuteTemplate ( w , "account-own-edit-success.html" , pi )
2016-12-02 07:38:54 +00:00
}
2016-12-02 15:03:31 +00:00
func route_account_own_edit_avatar ( w http . ResponseWriter , r * http . Request ) {
user := SessionCheck ( w , r )
if ! user . Loggedin {
errmsg := "You need to login to edit your own account."
pi := Page { "Error" , "error" , user , tList , errmsg }
var b bytes . Buffer
templates . ExecuteTemplate ( & b , "error.html" , pi )
errpage := b . String ( )
2016-12-03 11:06:47 +00:00
w . WriteHeader ( 500 )
fmt . Fprintln ( w , errpage )
2016-12-02 15:03:31 +00:00
return
}
pi := Page { "Edit Avatar" , "account-own-edit-avatar" , user , tList , 0 }
templates . ExecuteTemplate ( w , "account-own-edit-avatar.html" , pi )
}
func route_account_own_edit_avatar_submit ( w http . ResponseWriter , r * http . Request ) {
if r . ContentLength > int64 ( max_request_size ) {
http . Error ( w , "request too large" , http . StatusExpectationFailed )
return
}
r . Body = http . MaxBytesReader ( w , r . Body , int64 ( max_request_size ) )
user := SessionCheck ( w , r )
if ! user . Loggedin {
errmsg := "You need to login to edit your own account."
pi := Page { "Error" , "error" , user , tList , errmsg }
var b bytes . Buffer
templates . ExecuteTemplate ( & b , "error.html" , pi )
errpage := b . String ( )
2016-12-03 11:06:47 +00:00
w . WriteHeader ( 500 )
fmt . Fprintln ( w , errpage )
2016-12-02 15:03:31 +00:00
return
}
2016-12-02 07:38:54 +00:00
2016-12-02 15:03:31 +00:00
err := r . ParseMultipartForm ( int64 ( max_request_size ) )
if err != nil {
LocalError ( "Upload failed" , w , r , user )
return
}
var filename string = ""
var ext string
for _ , fheaders := range r . MultipartForm . File {
for _ , hdr := range fheaders {
infile , err := hdr . Open ( ) ;
if err != nil {
LocalError ( "Upload failed" , w , r , user )
return
}
defer infile . Close ( )
// We don't want multiple files
if filename != "" {
if filename != hdr . Filename {
os . Remove ( "./uploads/avatar_" + strconv . Itoa ( user . ID ) + "." + ext )
LocalError ( "You may only upload one avatar" , w , r , user )
return
}
} else {
filename = hdr . Filename
}
if ext == "" {
extarr := strings . Split ( hdr . Filename , "." )
if len ( extarr ) < 2 {
LocalError ( "Bad file" , w , r , user )
return
}
ext = extarr [ len ( extarr ) - 1 ]
reg , err := regexp . Compile ( "[^A-Za-z0-9]+" )
if err != nil {
LocalError ( "Bad file extension" , w , r , user )
return
}
ext = reg . ReplaceAllString ( ext , "" )
ext = strings . ToLower ( ext )
}
outfile , err := os . Create ( "./uploads/avatar_" + strconv . Itoa ( user . ID ) + "." + ext ) ;
if err != nil {
LocalError ( "Upload failed [File Creation Failed]" , w , r , user )
return
}
defer outfile . Close ( )
_ , err = io . Copy ( outfile , infile ) ;
if err != nil {
LocalError ( "Upload failed [Copy Failed]" , w , r , user )
return
}
}
}
_ , err = set_avatar_stmt . Exec ( "." + ext , strconv . Itoa ( user . ID ) )
if err != nil {
InternalError ( err , w , r , user )
return
}
user . Avatar = "/uploads/avatar_" + strconv . Itoa ( user . ID ) + "." + ext
pi := Page { "Edit Avatar" , "account-own-edit-avatar-success" , user , tList , 0 }
templates . ExecuteTemplate ( w , "account-own-edit-avatar-success.html" , pi )
}
2016-12-03 08:09:40 +00:00
func route_account_own_edit_username ( w http . ResponseWriter , r * http . Request ) {
user := SessionCheck ( w , r )
if ! user . Loggedin {
errmsg := "You need to login to edit your own account."
pi := Page { "Error" , "error" , user , tList , errmsg }
var b bytes . Buffer
templates . ExecuteTemplate ( & b , "error.html" , pi )
errpage := b . String ( )
2016-12-03 11:06:47 +00:00
w . WriteHeader ( 500 )
fmt . Fprintln ( w , errpage )
2016-12-03 08:09:40 +00:00
return
}
pi := Page { "Edit Username" , "account-own-edit-username" , user , tList , user . Name }
templates . ExecuteTemplate ( w , "account-own-edit-username.html" , pi )
}
func route_account_own_edit_username_submit ( w http . ResponseWriter , r * http . Request ) {
user := SessionCheck ( w , r )
if ! user . Loggedin {
errmsg := "You need to login to edit your own account."
pi := Page { "Error" , "error" , user , tList , errmsg }
var b bytes . Buffer
templates . ExecuteTemplate ( & b , "error.html" , pi )
errpage := b . String ( )
2016-12-03 11:06:47 +00:00
w . WriteHeader ( 500 )
fmt . Fprintln ( w , errpage )
2016-12-03 08:09:40 +00:00
return
}
err := r . ParseForm ( )
if err != nil {
LocalError ( "Bad Form" , w , r , user )
return
}
new_username := html . EscapeString ( r . PostFormValue ( "account-new-username" ) )
_ , err = set_username_stmt . Exec ( new_username , strconv . Itoa ( user . ID ) )
if err != nil {
InternalError ( err , w , r , user )
return
}
user . Name = new_username
pi := Page { "Edit Username" , "account-own-edit-username" , user , tList , user . Name }
templates . ExecuteTemplate ( w , "account-own-edit-username.html" , pi )
}
2016-12-02 07:38:54 +00:00
func route_logout ( w http . ResponseWriter , r * http . Request ) {
user := SessionCheck ( w , r )
if ! user . Loggedin {
errmsg := "You can't logout without logging in first."
pi := Page { "Error" , "error" , user , tList , errmsg }
var b bytes . Buffer
templates . ExecuteTemplate ( & b , "error.html" , pi )
errpage := b . String ( )
2016-12-03 11:06:47 +00:00
w . WriteHeader ( 500 )
fmt . Fprintln ( w , errpage )
2016-12-02 07:38:54 +00:00
return
}
_ , err := logout_stmt . Exec ( user . ID )
if err != nil {
InternalError ( err , w , r , user )
return
}
http . Redirect ( w , r , "/" , http . StatusSeeOther )
}
func route_login ( w http . ResponseWriter , r * http . Request ) {
user := SessionCheck ( w , r )
if user . Loggedin {
errmsg := "You're already logged in."
pi := Page { "Error" , "error" , user , tList , errmsg }
var b bytes . Buffer
templates . ExecuteTemplate ( & b , "error.html" , pi )
errpage := b . String ( )
2016-12-03 11:06:47 +00:00
w . WriteHeader ( 500 )
fmt . Fprintln ( w , errpage )
2016-12-02 07:38:54 +00:00
return
}
pi := Page { "Login" , "login" , user , tList , 0 }
templates . ExecuteTemplate ( w , "login.html" , pi )
}
func route_login_submit ( w http . ResponseWriter , r * http . Request ) {
user := SessionCheck ( w , r )
if user . Loggedin {
errmsg := "You're already logged in."
pi := Page { "Error" , "error" , user , tList , errmsg }
var b bytes . Buffer
templates . ExecuteTemplate ( & b , "error.html" , pi )
errpage := b . String ( )
2016-12-03 11:06:47 +00:00
w . WriteHeader ( 500 )
fmt . Fprintln ( w , errpage )
2016-12-02 07:38:54 +00:00
return
}
err := r . ParseForm ( )
2016-12-02 11:00:07 +00:00
if err != nil {
LocalError ( "Bad Form" , w , r , user )
2016-12-02 07:38:54 +00:00
return
2016-12-02 11:00:07 +00:00
}
2016-12-02 07:38:54 +00:00
var uid int
var real_password string
var salt string
var session string
username := html . EscapeString ( r . PostFormValue ( "username" ) )
password := r . PostFormValue ( "password" )
err = login_stmt . QueryRow ( username ) . Scan ( & uid , & username , & real_password , & salt )
if err == sql . ErrNoRows {
errmsg := "That username doesn't exist."
pi := Page { "Error" , "error" , user , tList , errmsg }
var b bytes . Buffer
templates . ExecuteTemplate ( & b , "error.html" , pi )
errpage := b . String ( )
2016-12-03 11:06:47 +00:00
w . WriteHeader ( 500 )
fmt . Fprintln ( w , errpage )
2016-12-02 07:38:54 +00:00
return
} else if err != nil {
InternalError ( err , w , r , user )
return
}
// Emergency password reset mechanism..
if salt == "" {
if password != real_password {
errmsg := "That's not the correct password."
pi := Page { "Error" , "error" , user , tList , errmsg }
var b bytes . Buffer
templates . ExecuteTemplate ( & b , "error.html" , pi )
errpage := b . String ( )
2016-12-03 11:06:47 +00:00
w . WriteHeader ( 500 )
fmt . Fprintln ( w , errpage )
2016-12-02 07:38:54 +00:00
return
}
// Re-encrypt the password
SetPassword ( uid , password )
} else { // Normal login..
password = password + salt
if err != nil {
InternalError ( err , w , r , user )
return
}
err := bcrypt . CompareHashAndPassword ( [ ] byte ( real_password ) , [ ] byte ( password ) )
if err == bcrypt . ErrMismatchedHashAndPassword {
errmsg := "That's not the correct password."
pi := Page { "Error" , "error" , user , tList , errmsg }
var b bytes . Buffer
templates . ExecuteTemplate ( & b , "error.html" , pi )
errpage := b . String ( )
2016-12-03 11:06:47 +00:00
w . WriteHeader ( 500 )
fmt . Fprintln ( w , errpage )
2016-12-02 07:38:54 +00:00
return
} else if err != nil {
InternalError ( err , w , r , user )
return
}
}
session , err = GenerateSafeString ( sessionLength )
if err != nil {
InternalError ( err , w , r , user )
return
}
2016-12-02 09:29:45 +00:00
_ , err = update_session_stmt . Exec ( session , uid )
2016-12-02 07:38:54 +00:00
if err != nil {
InternalError ( err , w , r , user )
return
}
2016-12-02 09:29:45 +00:00
cookie := http . Cookie { Name : "uid" , Value : strconv . Itoa ( uid ) , Path : "/" , MaxAge : year }
2016-12-02 07:38:54 +00:00
http . SetCookie ( w , & cookie )
2016-12-02 09:29:45 +00:00
cookie = http . Cookie { Name : "session" , Value : session , Path : "/" , MaxAge : year }
2016-12-02 07:38:54 +00:00
http . SetCookie ( w , & cookie )
http . Redirect ( w , r , "/" , http . StatusSeeOther )
}
func route_register ( w http . ResponseWriter , r * http . Request ) {
user := SessionCheck ( w , r )
if user . Loggedin {
errmsg := "You're already logged in."
pi := Page { "Error" , "error" , user , tList , errmsg }
var b bytes . Buffer
templates . ExecuteTemplate ( & b , "error.html" , pi )
errpage := b . String ( )
2016-12-03 11:06:47 +00:00
w . WriteHeader ( 500 )
fmt . Fprintln ( w , errpage )
2016-12-02 07:38:54 +00:00
return
}
pi := Page { "Registration" , "register" , user , tList , 0 }
templates . ExecuteTemplate ( w , "register.html" , pi )
}
func route_register_submit ( w http . ResponseWriter , r * http . Request ) {
user := SessionCheck ( w , r )
err := r . ParseForm ( )
2016-12-02 11:00:07 +00:00
if err != nil {
LocalError ( "Bad Form" , w , r , user )
2016-12-02 07:38:54 +00:00
return
2016-12-02 11:00:07 +00:00
}
2016-12-02 07:38:54 +00:00
username := html . EscapeString ( r . PostFormValue ( "username" ) )
password := r . PostFormValue ( "password" )
confirm_password := r . PostFormValue ( "confirm_password" )
log . Print ( "Registration Attempt! Username: " + username )
// Do the two inputted passwords match..?
if password != confirm_password {
errmsg := "The two passwords don't match."
pi := Page { "Password Mismatch" , "error" , user , tList , errmsg }
var b bytes . Buffer
templates . ExecuteTemplate ( & b , "error.html" , pi )
errpage := b . String ( )
2016-12-03 11:06:47 +00:00
w . WriteHeader ( 500 )
fmt . Fprintln ( w , errpage )
2016-12-02 07:38:54 +00:00
return
}
// Is this username already taken..?
err = username_exists_stmt . QueryRow ( username ) . Scan ( & username )
if err != nil && err != sql . ErrNoRows {
InternalError ( err , w , r , user )
return
} else if err != sql . ErrNoRows {
errmsg := "This username isn't available. Try another."
pi := Page { "Username Taken" , "error" , user , tList , errmsg }
var b bytes . Buffer
templates . ExecuteTemplate ( & b , "error.html" , pi )
errpage := b . String ( )
2016-12-03 11:06:47 +00:00
w . WriteHeader ( 500 )
fmt . Fprintln ( w , errpage )
2016-12-02 07:38:54 +00:00
return
}
salt , err := GenerateSafeString ( saltLength )
if err != nil {
InternalError ( err , w , r , user )
return
}
session , err := GenerateSafeString ( sessionLength )
if err != nil {
InternalError ( err , w , r , user )
return
}
password = password + salt
hashed_password , err := bcrypt . GenerateFromPassword ( [ ] byte ( password ) , bcrypt . DefaultCost )
if err != nil {
InternalError ( err , w , r , user )
return
}
res , err := register_stmt . Exec ( username , string ( hashed_password ) , salt , session )
if err != nil {
InternalError ( err , w , r , user )
return
}
lastId , err := res . LastInsertId ( )
if err != nil {
InternalError ( err , w , r , user )
return
}
2016-12-02 09:29:45 +00:00
cookie := http . Cookie { Name : "uid" , Value : strconv . FormatInt ( lastId , 10 ) , Path : "/" , MaxAge : year }
2016-12-02 07:38:54 +00:00
http . SetCookie ( w , & cookie )
2016-12-02 09:29:45 +00:00
cookie = http . Cookie { Name : "session" , Value : session , Path : "/" , MaxAge : year }
2016-12-02 07:38:54 +00:00
http . SetCookie ( w , & cookie )
http . Redirect ( w , r , "/" , http . StatusSeeOther )
}