Added URL tags & the settings system.

Moved the database logic out of main.go and into mysql.go
Tweaked the CSS.
Banned users can no longer log out.
This commit is contained in:
Azareal 2016-12-09 13:46:29 +00:00
parent 5296cc0b14
commit b2e3591997
21 changed files with 572 additions and 314 deletions

View File

@ -12,7 +12,11 @@ CREATE TABLE `users`(
`session` varchar(200) DEFAULT '' not null,
`email` varchar(200) DEFAULT '' not null,
`avatar` varchar(20) DEFAULT '' not null,
primary key(`uid`)
`message` text not null,
`url_prefix` varchar(20) DEFAULT '' not null,
`url_name` varchar(100) DEFAULT '' not null,
primary key(`uid`),
unique(`name`)
) CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;
CREATE TABLE `users_groups`(
@ -76,16 +80,17 @@ CREATE TABLE `users_replies`(
primary key(`rid`)
) CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;
/*CREATE TABLE `replies_reports` (
`rid` int not null AUTO_INCREMENT,
`reportedBy` int not null,
`reportedContent` text not null,
`resolved` tinyint DEFAULT 0 not null,
primary key(`rid`)
);*/
CREATE TABLE `settings`(
`name` varchar(200) not null,
`content` varchar(250) not null,
`type` varchar(50) not null,
unique(`name`)
);
INSERT INTO users(`name`,`group`,`is_super_admin`,`createdAt`,`lastActiveAt`)
VALUES ('Admin',1,1,NOW(),NOW());
INSERT INTO settings(`name`,`content`,`type`) VALUES ('url_tags','1','bool');
INSERT INTO users(`name`,`group`,`is_super_admin`,`createdAt`,`lastActiveAt`,`message`)
VALUES ('Admin',1,1,NOW(),NOW(),'');
INSERT INTO users_groups(`name`,`permissions`,`is_mod`,`is_admin`,`tag`) VALUES ('Administrator','{}',1,1,"Admin");
INSERT INTO users_groups(`name`,`permissions`,`is_mod`,`tag`) VALUES ('Moderator','{}',1,"Mod");

Binary file not shown.

Binary file not shown.

BIN
images/url_tags.PNG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

294
main.go
View File

@ -2,15 +2,12 @@ package main
import (
"net/http"
"database/sql"
_ "github.com/go-sql-driver/mysql"
"log"
"mime"
"strings"
"strconv"
"path/filepath"
"os"
"io/ioutil"
"os"
"html/template"
)
@ -23,274 +20,16 @@ const megabyte int = 1024 * 1024
const saltLength int = 32
const sessionLength int = 80
var db *sql.DB
var get_session_stmt *sql.Stmt
var create_topic_stmt *sql.Stmt
var create_reply_stmt *sql.Stmt
var update_forum_cache_stmt *sql.Stmt
var edit_topic_stmt *sql.Stmt
var edit_reply_stmt *sql.Stmt
var delete_reply_stmt *sql.Stmt
var delete_topic_stmt *sql.Stmt
var stick_topic_stmt *sql.Stmt
var unstick_topic_stmt *sql.Stmt
var login_stmt *sql.Stmt
var update_session_stmt *sql.Stmt
var logout_stmt *sql.Stmt
var set_password_stmt *sql.Stmt
var get_password_stmt *sql.Stmt
var set_avatar_stmt *sql.Stmt
var set_username_stmt *sql.Stmt
var register_stmt *sql.Stmt
var username_exists_stmt *sql.Stmt
var change_group_stmt *sql.Stmt
var create_profile_reply_stmt *sql.Stmt
var edit_profile_reply_stmt *sql.Stmt
var delete_profile_reply_stmt *sql.Stmt
var create_forum_stmt *sql.Stmt
var delete_forum_stmt *sql.Stmt
var update_forum_stmt *sql.Stmt
var templates = template.Must(template.ParseGlob("templates/*"))
var custom_pages = template.Must(template.ParseGlob("pages/*"))
var no_css_tmpl = template.CSS("")
var staff_css_tmpl = template.CSS(staff_css)
var settings map[string]interface{} = make(map[string]interface{})
var external_sites map[string]string = make(map[string]string)
var groups map[int]Group = make(map[int]Group)
var forums map[int]Forum = make(map[int]Forum)
var static_files map[string]SFile = make(map[string]SFile)
func init_database(err error) {
if(dbpassword != ""){
dbpassword = ":" + dbpassword
}
db, err = sql.Open("mysql",dbuser + dbpassword + "@tcp(" + dbhost + ":" + dbport + ")/" + dbname + "?collation=utf8mb4_general_ci")
if err != nil {
log.Fatal(err)
}
// Make sure that the connection is alive..
err = db.Ping()
if err != nil {
log.Fatal(err)
}
log.Print("Preparing get_session statement.")
get_session_stmt, err = db.Prepare("SELECT `uid`, `name`, `group`, `is_super_admin`, `session`, `avatar` FROM `users` WHERE `uid` = ? AND `session` = ? AND `session` <> ''")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing create_topic statement.")
create_topic_stmt, err = db.Prepare("INSERT INTO topics(title,content,parsed_content,createdAt,createdBy) VALUES(?,?,?,NOW(),?)")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing create_reply statement.")
create_reply_stmt, err = db.Prepare("INSERT INTO replies(tid,content,parsed_content,createdAt,createdBy) VALUES(?,?,?,NOW(),?)")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing update_forum_cache statement.")
update_forum_cache_stmt, err = db.Prepare("UPDATE forums SET lastTopic = ?, lastTopicID = ?, lastReplyer = ?, lastReplyerID = ?, lastTopicTime = NOW() WHERE fid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing edit_topic statement.")
edit_topic_stmt, err = db.Prepare("UPDATE topics SET title = ?, content = ?, parsed_content = ?, is_closed = ? WHERE tid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing edit_reply statement.")
edit_reply_stmt, err = db.Prepare("UPDATE replies SET content = ?, parsed_content = ? WHERE rid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing delete_reply statement.")
delete_reply_stmt, err = db.Prepare("DELETE FROM replies WHERE rid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing delete_topic statement.")
delete_topic_stmt, err = db.Prepare("DELETE FROM topics WHERE tid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing stick_topic statement.")
stick_topic_stmt, err = db.Prepare("UPDATE topics SET sticky = 1 WHERE tid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing unstick_topic statement.")
unstick_topic_stmt, err = db.Prepare("UPDATE topics SET sticky = 0 WHERE tid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing login statement.")
login_stmt, err = db.Prepare("SELECT `uid`, `name`, `password`, `salt` FROM `users` WHERE `name` = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing update_session statement.")
update_session_stmt, err = db.Prepare("UPDATE users SET session = ? WHERE uid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing logout statement.")
logout_stmt, err = db.Prepare("UPDATE users SET session = '' WHERE uid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing set_password statement.")
set_password_stmt, err = db.Prepare("UPDATE users SET password = ?, salt = ? WHERE uid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing get_password statement.")
get_password_stmt, err = db.Prepare("SELECT `password`, `salt` FROM `users` WHERE `uid` = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing set_avatar statement.")
set_avatar_stmt, err = db.Prepare("UPDATE users SET avatar = ? WHERE uid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing set_username statement.")
set_username_stmt, err = db.Prepare("UPDATE users SET name = ? WHERE uid = ?")
if err != nil {
log.Fatal(err)
}
// Add an admin version of register_stmt with more flexibility
// create_account_stmt, err = db.Prepare("INSERT INTO
log.Print("Preparing register statement.")
register_stmt, err = db.Prepare("INSERT INTO users(`name`,`password`,`salt`,`group`,`is_super_admin`,`session`) VALUES(?,?,?," + strconv.Itoa(default_group) + ",0,?)")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing username_exists statement.")
username_exists_stmt, err = db.Prepare("SELECT `name` FROM `users` WHERE `name` = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing change_group statement.")
change_group_stmt, err = db.Prepare("UPDATE `users` SET `group` = ? WHERE `uid` = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing create_profile_reply statement.")
create_profile_reply_stmt, err = db.Prepare("INSERT INTO users_replies(uid,content,parsed_content,createdAt,createdBy) VALUES(?,?,?,NOW(),?)")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing edit_profile_reply statement.")
edit_profile_reply_stmt, err = db.Prepare("UPDATE users_replies SET content = ?, parsed_content = ? WHERE rid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing delete_profile_reply statement.")
delete_profile_reply_stmt, err = db.Prepare("DELETE FROM users_replies WHERE rid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing create_forum statement.")
create_forum_stmt, err = db.Prepare("INSERT INTO forums(name) VALUES(?)")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing delete_forum statement.")
delete_forum_stmt, err = db.Prepare("DELETE FROM forums WHERE fid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing update_forum statement.")
update_forum_stmt, err = db.Prepare("UPDATE forums SET name = ? WHERE fid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Loading the usergroups.")
rows, err := db.Query("SELECT gid,name,permissions,is_mod,is_admin,is_banned,tag FROM users_groups")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
group := Group{0,"","",false,false,false,""}
err := rows.Scan(&group.ID, &group.Name, &group.Permissions, &group.Is_Mod, &group.Is_Admin, &group.Is_Banned, &group.Tag)
if err != nil {
log.Fatal(err)
}
groups[group.ID] = group
}
err = rows.Err()
if err != nil {
log.Fatal(err)
}
log.Print("Loading the forums.")
rows, err = db.Query("SELECT fid, name, active, lastTopic, lastTopicID, lastReplyer, lastReplyerID, lastTopicTime FROM forums")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
forum := Forum{0,"",true,"",0,"",0,""}
err := rows.Scan(&forum.ID, &forum.Name, &forum.Active, &forum.LastTopic, &forum.LastTopicID, &forum.LastReplyer, &forum.LastReplyerID, &forum.LastTopicTime)
if err != nil {
log.Fatal(err)
}
if forum.LastTopicID != 0 {
forum.LastTopicTime, err = relative_time(forum.LastTopicTime)
if err != nil {
log.Fatal(err)
}
} else {
forum.LastTopic = "None"
forum.LastTopicTime = ""
}
forums[forum.ID] = forum
}
err = rows.Err()
if err != nil {
log.Fatal(err)
}
log.Print("Adding the uncategorised forum")
forums[0] = Forum{0,"Uncategorised",uncategorised_forum_visible,"",0,"",0,""}
log.Print("Adding the reports forum")
forums[-1] = Forum{-1,"Reports",false,"",0,"",0,""}
}
func main(){
var err error
init_database(err);
@ -316,9 +55,7 @@ func main(){
log.Fatal(err)
}
//parse_map["grinning"] = []byte("😀")
//parse_map["grin"] = []byte("😁")
//parse_map["joy"] = []byte("😂")
external_sites["YT"] = "https://www.youtube.com/"
// In a directory to stop it clashing with the other paths
http.HandleFunc("/static/", route_static)
@ -333,14 +70,14 @@ func main(){
http.HandleFunc("/topics/", route_topics)
http.HandleFunc("/forums/", route_forums)
http.HandleFunc("/forum/", route_forum)
http.HandleFunc("/topic/create/submit/", route_create_topic) //POST
http.HandleFunc("/topic/create/submit/", route_create_topic)
http.HandleFunc("/topic/", route_topic_id)
http.HandleFunc("/reply/create/", route_create_reply) //POST
//http.HandleFunc("/reply/edit/", route_reply_edit) //POST
//http.HandleFunc("/reply/delete/", route_reply_delete) //POST
http.HandleFunc("/reply/edit/submit/", route_reply_edit_submit) //POST
http.HandleFunc("/reply/delete/submit/", route_reply_delete_submit) //POST
http.HandleFunc("/topic/edit/submit/", route_edit_topic) //POST
http.HandleFunc("/reply/create/", route_create_reply)
//http.HandleFunc("/reply/edit/", route_reply_edit)
//http.HandleFunc("/reply/delete/", route_reply_delete)
http.HandleFunc("/reply/edit/submit/", route_reply_edit_submit)
http.HandleFunc("/reply/delete/submit/", route_reply_delete_submit)
http.HandleFunc("/topic/edit/submit/", route_edit_topic)
http.HandleFunc("/topic/delete/submit/", route_delete_topic)
http.HandleFunc("/topic/stick/submit/", route_stick_topic)
http.HandleFunc("/topic/unstick/submit/", route_unstick_topic)
@ -352,8 +89,8 @@ func main(){
http.HandleFunc("/accounts/login/", route_login)
http.HandleFunc("/accounts/create/", route_register)
http.HandleFunc("/accounts/logout/", route_logout)
http.HandleFunc("/accounts/login/submit/", route_login_submit) // POST
http.HandleFunc("/accounts/create/submit/", route_register_submit) // POST
http.HandleFunc("/accounts/login/submit/", route_login_submit)
http.HandleFunc("/accounts/create/submit/", route_register_submit)
//http.HandleFunc("/accounts/list/", route_login) // Redirect /accounts/ and /user/ to here..
//http.HandleFunc("/accounts/create/full/", route_logout)
@ -368,7 +105,7 @@ func main(){
http.HandleFunc("/profile/reply/create/", route_profile_reply_create)
http.HandleFunc("/profile/reply/edit/submit/", route_profile_reply_edit_submit)
http.HandleFunc("/profile/reply/delete/submit/", route_profile_reply_delete_submit)
//http.HandleFunc("/user/:id/edit/", route_logout)
//http.HandleFunc("/user/edit/submit/", route_logout)
http.HandleFunc("/users/ban/", route_ban)
http.HandleFunc("/users/ban/submit/", route_ban_submit)
http.HandleFunc("/users/unban/", route_unban)
@ -379,6 +116,9 @@ func main(){
http.HandleFunc("/panel/forums/delete/", route_panel_forums_delete)
http.HandleFunc("/panel/forums/delete/submit/", route_panel_forums_delete_submit)
http.HandleFunc("/panel/forums/edit/submit/", route_panel_forums_edit_submit)
http.HandleFunc("/panel/settings/", route_panel_settings)
http.HandleFunc("/panel/settings/edit/", route_panel_setting)
http.HandleFunc("/panel/settings/edit/submit/", route_panel_setting_edit)
http.HandleFunc("/", default_route)

View File

@ -604,3 +604,94 @@ func route_panel_forums_edit_submit(w http.ResponseWriter, r *http.Request) {
http.Redirect(w,r,"/panel/forums/",http.StatusSeeOther)
}
func route_panel_settings(w http.ResponseWriter, r *http.Request){
user := SessionCheck(w,r)
if !user.Is_Admin {
NoPermissions(w,r,user)
return
}
var settingList map[string]interface{} = make(map[string]interface{})
for name, content := range settings {
settingList[name] = content
}
pi := Page{"Setting Manager","panel-settings",user,tList,settingList}
templates.ExecuteTemplate(w,"panel-settings.html", pi)
}
func route_panel_setting(w http.ResponseWriter, r *http.Request){
user := SessionCheck(w,r)
if !user.Is_Admin {
NoPermissions(w,r,user)
return
}
setting := Setting{"","",""}
setting.Name = r.URL.Path[len("/panel/settings/edit/"):]
err := db.QueryRow("SELECT content, type from settings where name = ?", setting.Name).Scan(&setting.Content, &setting.Type)
if err == sql.ErrNoRows {
LocalError("The setting you want to edit doesn't exist.",w,r,user)
return
} else if err != nil {
InternalError(err,w,r,user)
return
}
pi := Page{"Edit Setting","panel-setting",user,tList,setting}
templates.ExecuteTemplate(w,"panel-setting.html", pi)
}
func route_panel_setting_edit(w http.ResponseWriter, r *http.Request) {
user := SessionCheck(w,r)
if !user.Is_Admin {
NoPermissions(w,r,user)
return
}
err := r.ParseForm()
if err != nil {
LocalError("Bad Form", w, r, user)
return
}
if r.FormValue("session") != user.Session {
SecurityError(w,r,user)
return
}
var stype string
sname := r.URL.Path[len("/panel/settings/edit/submit/"):]
scontent := r.PostFormValue("setting-value")
err = db.QueryRow("SELECT name, type from settings where name = ?", sname).Scan(&sname, &stype)
if err == sql.ErrNoRows {
LocalError("The setting you want to edit doesn't exist.",w,r,user)
return
} else if err != nil {
InternalError(err,w,r,user)
return
}
if stype == "bool" {
if scontent == "on" || scontent == "1" {
scontent = "1"
} else {
scontent = "0"
}
}
_, err = update_setting_stmt.Exec(scontent, sname)
if err != nil {
InternalError(err,w,r,user)
return
}
errmsg := parseSetting(sname, scontent, stype)
if errmsg != "" {
LocalError(errmsg,w,r,user)
return
}
http.Redirect(w,r,"/panel/settings/",http.StatusSeeOther)
}

298
mysql.go Normal file
View File

@ -0,0 +1,298 @@
package main
import "database/sql"
import _ "github.com/go-sql-driver/mysql"
import "strconv"
import "log"
var db *sql.DB
var get_session_stmt *sql.Stmt
var create_topic_stmt *sql.Stmt
var create_reply_stmt *sql.Stmt
var update_forum_cache_stmt *sql.Stmt
var edit_topic_stmt *sql.Stmt
var edit_reply_stmt *sql.Stmt
var delete_reply_stmt *sql.Stmt
var delete_topic_stmt *sql.Stmt
var stick_topic_stmt *sql.Stmt
var unstick_topic_stmt *sql.Stmt
var login_stmt *sql.Stmt
var update_session_stmt *sql.Stmt
var logout_stmt *sql.Stmt
var set_password_stmt *sql.Stmt
var get_password_stmt *sql.Stmt
var set_avatar_stmt *sql.Stmt
var set_username_stmt *sql.Stmt
var register_stmt *sql.Stmt
var username_exists_stmt *sql.Stmt
var change_group_stmt *sql.Stmt
var create_profile_reply_stmt *sql.Stmt
var edit_profile_reply_stmt *sql.Stmt
var delete_profile_reply_stmt *sql.Stmt
var create_forum_stmt *sql.Stmt
var delete_forum_stmt *sql.Stmt
var update_forum_stmt *sql.Stmt
var update_setting_stmt *sql.Stmt
func init_database(err error) {
if(dbpassword != ""){
dbpassword = ":" + dbpassword
}
db, err = sql.Open("mysql",dbuser + dbpassword + "@tcp(" + dbhost + ":" + dbport + ")/" + dbname + "?collation=utf8mb4_general_ci")
if err != nil {
log.Fatal(err)
}
// Make sure that the connection is alive..
err = db.Ping()
if err != nil {
log.Fatal(err)
}
log.Print("Preparing get_session statement.")
get_session_stmt, err = db.Prepare("SELECT `uid`, `name`, `group`, `is_super_admin`, `session`, `avatar`, `message`, `url_prefix`, `url_name` FROM `users` WHERE `uid` = ? AND `session` = ? AND `session` <> ''")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing create_topic statement.")
create_topic_stmt, err = db.Prepare("INSERT INTO topics(title,content,parsed_content,createdAt,createdBy) VALUES(?,?,?,NOW(),?)")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing create_reply statement.")
create_reply_stmt, err = db.Prepare("INSERT INTO replies(tid,content,parsed_content,createdAt,createdBy) VALUES(?,?,?,NOW(),?)")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing update_forum_cache statement.")
update_forum_cache_stmt, err = db.Prepare("UPDATE forums SET lastTopic = ?, lastTopicID = ?, lastReplyer = ?, lastReplyerID = ?, lastTopicTime = NOW() WHERE fid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing edit_topic statement.")
edit_topic_stmt, err = db.Prepare("UPDATE topics SET title = ?, content = ?, parsed_content = ?, is_closed = ? WHERE tid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing edit_reply statement.")
edit_reply_stmt, err = db.Prepare("UPDATE replies SET content = ?, parsed_content = ? WHERE rid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing delete_reply statement.")
delete_reply_stmt, err = db.Prepare("DELETE FROM replies WHERE rid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing delete_topic statement.")
delete_topic_stmt, err = db.Prepare("DELETE FROM topics WHERE tid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing stick_topic statement.")
stick_topic_stmt, err = db.Prepare("UPDATE topics SET sticky = 1 WHERE tid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing unstick_topic statement.")
unstick_topic_stmt, err = db.Prepare("UPDATE topics SET sticky = 0 WHERE tid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing login statement.")
login_stmt, err = db.Prepare("SELECT `uid`, `name`, `password`, `salt` FROM `users` WHERE `name` = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing update_session statement.")
update_session_stmt, err = db.Prepare("UPDATE users SET session = ? WHERE uid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing logout statement.")
logout_stmt, err = db.Prepare("UPDATE users SET session = '' WHERE uid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing set_password statement.")
set_password_stmt, err = db.Prepare("UPDATE users SET password = ?, salt = ? WHERE uid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing get_password statement.")
get_password_stmt, err = db.Prepare("SELECT `password`, `salt` FROM `users` WHERE `uid` = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing set_avatar statement.")
set_avatar_stmt, err = db.Prepare("UPDATE users SET avatar = ? WHERE uid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing set_username statement.")
set_username_stmt, err = db.Prepare("UPDATE users SET name = ? WHERE uid = ?")
if err != nil {
log.Fatal(err)
}
// Add an admin version of register_stmt with more flexibility
// create_account_stmt, err = db.Prepare("INSERT INTO
log.Print("Preparing register statement.")
register_stmt, err = db.Prepare("INSERT INTO users(`name`,`password`,`salt`,`group`,`is_super_admin`,`session`,`message`) VALUES(?,?,?," + strconv.Itoa(default_group) + ",0,?,'')")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing username_exists statement.")
username_exists_stmt, err = db.Prepare("SELECT `name` FROM `users` WHERE `name` = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing change_group statement.")
change_group_stmt, err = db.Prepare("UPDATE `users` SET `group` = ? WHERE `uid` = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing create_profile_reply statement.")
create_profile_reply_stmt, err = db.Prepare("INSERT INTO users_replies(uid,content,parsed_content,createdAt,createdBy) VALUES(?,?,?,NOW(),?)")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing edit_profile_reply statement.")
edit_profile_reply_stmt, err = db.Prepare("UPDATE users_replies SET content = ?, parsed_content = ? WHERE rid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing delete_profile_reply statement.")
delete_profile_reply_stmt, err = db.Prepare("DELETE FROM users_replies WHERE rid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing create_forum statement.")
create_forum_stmt, err = db.Prepare("INSERT INTO forums(name) VALUES(?)")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing delete_forum statement.")
delete_forum_stmt, err = db.Prepare("DELETE FROM forums WHERE fid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing update_forum statement.")
update_forum_stmt, err = db.Prepare("UPDATE forums SET name = ? WHERE fid = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing update_setting statement.")
update_setting_stmt, err = db.Prepare("UPDATE settings SET content = ? WHERE name = ?")
if err != nil {
log.Fatal(err)
}
log.Print("Loading the usergroups.")
rows, err := db.Query("SELECT gid,name,permissions,is_mod,is_admin,is_banned,tag FROM users_groups")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
group := Group{0,"","",false,false,false,""}
err := rows.Scan(&group.ID, &group.Name, &group.Permissions, &group.Is_Mod, &group.Is_Admin, &group.Is_Banned, &group.Tag)
if err != nil {
log.Fatal(err)
}
groups[group.ID] = group
}
err = rows.Err()
if err != nil {
log.Fatal(err)
}
log.Print("Loading the forums.")
rows, err = db.Query("SELECT fid, name, active, lastTopic, lastTopicID, lastReplyer, lastReplyerID, lastTopicTime FROM forums")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
forum := Forum{0,"",true,"",0,"",0,""}
err := rows.Scan(&forum.ID, &forum.Name, &forum.Active, &forum.LastTopic, &forum.LastTopicID, &forum.LastReplyer, &forum.LastReplyerID, &forum.LastTopicTime)
if err != nil {
log.Fatal(err)
}
if forum.LastTopicID != 0 {
forum.LastTopicTime, err = relative_time(forum.LastTopicTime)
if err != nil {
log.Fatal(err)
}
} else {
forum.LastTopic = "None"
forum.LastTopicTime = ""
}
forums[forum.ID] = forum
}
err = rows.Err()
if err != nil {
log.Fatal(err)
}
log.Print("Adding the uncategorised forum")
forums[0] = Forum{0,"Uncategorised",uncategorised_forum_visible,"",0,"",0,""}
log.Print("Adding the reports forum")
forums[-1] = Forum{-1,"Reports",false,"",0,"",0,""}
log.Print("Loading the settings.")
rows, err = db.Query("SELECT name, content, type FROM settings")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
var sname string
var scontent string
var stype string
for rows.Next() {
err := rows.Scan(&sname, &scontent, &stype)
if err != nil {
log.Fatal(err)
}
errmsg := parseSetting(sname, scontent, stype)
if errmsg != "" {
log.Fatal(err)
}
}
err = rows.Err()
if err != nil {
log.Fatal(err)
}
}

View File

@ -91,6 +91,7 @@ li:not(:last-child)
padding-top: 0px;
width: 30%;
float: left;
margin-right: 8px;
}
.colblock_right
{

View File

@ -16,4 +16,7 @@ type Reply struct
Css template.CSS
ContentLines int
Tag string
URL string
URLPrefix string
URLName string
}

View File

@ -52,10 +52,10 @@ func route_overview(w http.ResponseWriter, r *http.Request){
func route_custom_page(w http.ResponseWriter, r *http.Request){
user := SessionCheck(w,r)
name := r.URL.Path[len("/pages/"):]
name := r.URL.Path[len("/pages/"):]
pi := Page{"Page","page",user,tList,0}
err := custom_pages.ExecuteTemplate(w,name, pi)
err := custom_pages.ExecuteTemplate(w,name,pi)
if err != nil {
NotFound(w,r,user)
}
@ -109,7 +109,7 @@ func route_topics(w http.ResponseWriter, r *http.Request){
avatar = strings.Replace(noavatar,"{id}",strconv.Itoa(createdBy),1)
}
topicList[currentID] = TopicUser{tid,title,content,createdBy,is_closed,sticky, createdAt,parentID,status,name,avatar,"",0,""}
topicList[currentID] = TopicUser{tid,title,content,createdBy,is_closed,sticky, createdAt,parentID,status,name,avatar,"",0,"","","",""}
currentID++
}
err = rows.Err()
@ -192,7 +192,7 @@ func route_forum(w http.ResponseWriter, r *http.Request){
avatar = strings.Replace(noavatar,"{id}",strconv.Itoa(createdBy),1)
}
topicList[currentID] = TopicUser{tid,title,content,createdBy,is_closed,sticky, createdAt,parentID,status,name,avatar,"",0,""}
topicList[currentID] = TopicUser{tid,title,content,createdBy,is_closed,sticky,createdAt,parentID,status,name,avatar,"",0,"","","",""}
currentID++
}
err = rows.Err()
@ -243,6 +243,7 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
user := SessionCheck(w,r)
var(
err error
ok bool
rid int
content string
replyContent string
@ -255,6 +256,9 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
replyCss template.CSS
replyLines int
replyTag string
replyURL string
replyURLPrefix string
replyURLName string
is_super_admin bool
group int
@ -263,7 +267,7 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
)
replyList = make(map[int]interface{})
currentID = 0
topic := TopicUser{0,"","",0,false,false,"",0,"","","",no_css_tmpl,0,""}
topic := TopicUser{0,"","",0,false,false,"",0,"","","",no_css_tmpl,0,"","","",""}
topic.ID, err = strconv.Atoi(r.URL.Path[len("/topic/"):])
if err != nil {
@ -272,8 +276,7 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
}
// 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)
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)
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)
if err == sql.ErrNoRows {
NotFound(w,r,user)
return
@ -305,10 +308,19 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
} else {
topic.Tag = ""
}
if settings["url_tags"] == false {
topic.URLName = ""
} else {
topic.URL, ok = external_sites[topic.URLPrefix]
if !ok {
topic.URL = topic.URLName
} else {
topic.URL = replyURL + topic.URLName
}
}
// Get the replies..
//rows, err := db.Query("select rid, content, createdBy, createdAt from replies where tid = ?", tid)
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)
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)
if err != nil {
InternalError(err,w,r,user)
return
@ -316,7 +328,7 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
defer rows.Close()
for rows.Next() {
err := rows.Scan(&rid, &replyContent, &replyCreatedBy, &replyCreatedAt, &replyLastEdit, &replyLastEditBy, &replyAvatar, &replyCreatedByName, &is_super_admin, &group)
err := rows.Scan(&rid, &replyContent, &replyCreatedBy, &replyCreatedAt, &replyLastEdit, &replyLastEditBy, &replyAvatar, &replyCreatedByName, &is_super_admin, &group, &replyURLPrefix, &replyURLName)
if err != nil {
InternalError(err,w,r,user)
return
@ -340,8 +352,18 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
} else {
replyTag = ""
}
if settings["url_tags"] == false {
replyURLName = ""
} else {
replyURL, ok = external_sites[replyURLPrefix]
if !ok {
replyURL = replyURLName
} else {
replyURL = replyURL + replyURLName
}
}
replyList[currentID] = Reply{rid,topic.ID,replyContent,template.HTML(parse_message(replyContent)),replyCreatedBy,replyCreatedByName,replyCreatedAt,replyLastEdit,replyLastEditBy,replyAvatar,replyCss,replyLines,replyTag}
replyList[currentID] = Reply{rid,topic.ID,replyContent,template.HTML(parse_message(replyContent)),replyCreatedBy,replyCreatedByName,replyCreatedAt,replyLastEdit,replyLastEditBy,replyAvatar,replyCss,replyLines,replyTag,replyURL,replyURLPrefix,replyURLName}
currentID++
}
err = rows.Err()
@ -381,7 +403,7 @@ func route_profile(w http.ResponseWriter, r *http.Request){
replyList = make(map[int]interface{})
currentID = 0
puser := User{0,"",0,false,false,false,false,false,"",false,""}
puser := User{0,"",0,false,false,false,false,false,"",false,"","","",""}
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)
@ -393,7 +415,7 @@ func route_profile(w http.ResponseWriter, r *http.Request){
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)
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)
if err == sql.ErrNoRows {
NotFound(w,r,user)
return
@ -455,7 +477,7 @@ func route_profile(w http.ResponseWriter, r *http.Request){
replyTag = ""
}
replyList[currentID] = Reply{rid,puser.ID,replyContent,template.HTML(parse_message(replyContent)),replyCreatedBy,replyCreatedByName,replyCreatedAt,replyLastEdit,replyLastEditBy,replyAvatar,replyCss,replyLines,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()
@ -918,7 +940,7 @@ func route_account_own_edit_username_submit(w http.ResponseWriter, r *http.Reque
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)
LocalError("Unable to change the username. Does someone else already have this name?",w,r,user)
return
}
user.Name = new_username

33
setting.go Normal file
View File

@ -0,0 +1,33 @@
package main
import "strconv"
type Setting struct
{
Name string
Content string
Type string
}
func parseSetting(sname string, scontent string, stype string) string {
var err error
if stype == "bool" {
if scontent == "1" {
settings[sname] = true
} else {
settings[sname] = false
}
} else if stype == "int" {
settings[sname], err = strconv.Atoi(scontent)
if err != nil {
return "You were supposed to enter an integer x.x\nType mismatch in " + sname
}
} else if stype == "int64" {
settings[sname], err = strconv.ParseInt(scontent, 10, 64)
if err != nil {
return "You were supposed to enter an integer x.x\nType mismatch in " + sname
}
} else {
settings[sname] = scontent
}
return ""
}

View File

@ -10,7 +10,7 @@
</div>
<div class="formrow">
<div class="formitem"><a>Password</a></div>
<div class="formitem"><input name="password" type="password" placeholder="*****" /></div>
<div class="formitem"><input name="password" type="password" autocomplete="current-password" placeholder="*****" /></div>
</div>
<div class="formrow">
<div class="formitem"><button name="login-button" class="formbutton">Login</div></div>

View File

@ -7,7 +7,7 @@
{{ if .CurrentUser.Loggedin }}
<li class="menu_account"><a href="/user/edit/critical/">Account</a></li>
<li class="menu_account"><a href="/user/{{.CurrentUser.ID}}">Profile</a></li>
{{ if .CurrentUser.Is_Admin}}<li class="menu_account"><a href="/panel/forums/">Panel</a></li>{{end}}
{{ if .CurrentUser.Is_Super_Mod}}<li class="menu_account"><a href="/panel/forums/">Panel</a></li>{{end}}
<li class="menu_logout"><a href="/accounts/logout?session={{.CurrentUser.Session}}">Logout</a></li>
{{ else }}
<li class="menu_register"><a href="/accounts/create/">Register</a></li>

View File

@ -2,19 +2,22 @@
<div class="colblock_left">
<div class="rowitem"><a>Control Panel</a></div>
<div class="rowitem passive"><a href="/panel/forums/">Forums</a></div>
<div class="rowitem passive"><a>Coming Soon</a></div>
<div class="rowitem passive"><a href="/panel/settings/">Settings</a></div>
<div class="rowitem passive"><a>Coming Soon</a></div>
<div class="rowitem passive"><a>Coming Soon</a></div>
<div class="rowitem passive"><a href="/forum/-1">Reports</a></div>
</div>
<div class="colblock_right">
<div class="rowitem"><a>Forums</a></div>
</div>
<div class="colblock_right">
{{range .ItemList}}
<div class="rowitem editable_parent" style="font-weight: normal;">
<a class="editable_block" style="font-size: 20px;position:relative;top: -2px;text-transform: none;">{{.Name}}</a>
<span style="float: right;">
{{if not (eq .ID 0)}}<span style="float: right;">
<a href="/panel/forums/edit/submit/{{.ID}}" class="username edit_field">Edit</a>
<a href="/panel/forums/delete/{{.ID}}?session={{$.CurrentUser.Session}}" class="username">Delete</a>
</span>
</span>{{end}}
</div>
{{end}}
</div><br />

View File

@ -0,0 +1,33 @@
{{template "header.html" . }}
<div class="colblock_left">
<div class="rowitem"><a>Control Panel</a></div>
<div class="rowitem passive"><a href="/panel/forums/">Forums</a></div>
<div class="rowitem passive"><a href="/panel/settings/">Settings</a></div>
<div class="rowitem passive"><a>Coming Soon</a></div>
<div class="rowitem passive"><a>Coming Soon</a></div>
<div class="rowitem passive"><a href="/forum/-1">Reports</a></div>
</div>
<div class="colblock_right">
<div class="rowitem"><a>Edit Setting</a></div>
</div>
<div class="colblock_right">
<form action="/panel/settings/edit/submit/{{.Something.Name}}?session={{.CurrentUser.Session}}" method="post">
<div class="formrow">
<div class="formitem"><a>Setting Name</a></div>
<div class="formitem">{{.Something.Name}}</div>
</div>
{{if eq .Something.Type "bool"}}
<div class="formrow">
<div class="formitem"><a>Setting Value</a></div>
<div class="formitem"><input name="setting-value" type="checkbox"{{if eq .Something.Content "1"}} checked{{end}} /></div>
</div>
{{else}}<div class="formrow">
<div class="formitem"><a>Setting Value</a></div>
<div class="formitem"><input name="setting-value" type="text" value="{{.Something.Content}}" /></div>
</div>{{end}}
<div class="formrow">
<div class="formitem"><button name="panel-button" class="formbutton">Update Setting</div></div>
</div>
</form>
</div>
{{template "footer.html" . }}

View File

@ -0,0 +1,21 @@
{{template "header.html" . }}
<div class="colblock_left">
<div class="rowitem"><a>Control Panel</a></div>
<div class="rowitem passive"><a href="/panel/forums/">Forums</a></div>
<div class="rowitem passive"><a href="/panel/settings/">Settings</a></div>
<div class="rowitem passive"><a>Coming Soon</a></div>
<div class="rowitem passive"><a>Coming Soon</a></div>
<div class="rowitem passive"><a href="/forum/-1">Reports</a></div>
</div>
<div class="colblock_right">
<div class="rowitem"><a>Settings</a></div>
</div>
<div class="colblock_right">
{{ range $key, $value := .Something }}
<div class="rowitem editable_parent" style="font-weight: normal;">
<a href="/panel/settings/edit/{{$key}}" class="editable_block" style="font-size: 20px;position:relative;top: -2px;text-transform: none;">{{$key}}</a>
<a style="float: right;text-transform: lowercase;">{{$value}}</a>
</div>
{{end}}
</div>
{{template "footer.html" . }}

View File

@ -1,5 +1,5 @@
{{template "header.html" . }}
<div class="colblock_left" style="max-width: 220px;margin-right: 8px;">
<div class="colblock_left" style="max-width: 220px;">
<div class="rowitem" style="padding: 0;"><img src="{{.Something.Avatar}}" style="max-width: 100%;margin: 0;"/></div>
<div class="rowitem">{{.Something.Name}}</div>
<div class="rowitem passive">

View File

@ -10,7 +10,7 @@
</div>
<div class="formrow">
<div class="formitem"><a>Password</a></div>
<div class="formitem"><input name="password" type="password" placeholder="*****" /></div>
<div class="formitem"><input name="password" type="password" autocomplete="new-password" placeholder="*****" /></div>
</div>
<div class="formrow">
<div class="formitem"><a>Confirm Password</a></div>

View File

@ -26,7 +26,8 @@
<textarea name="topic_content" class="show_on_edit topic_content_input">{{.Something.Content}}</textarea>
<br /><br />
<a href="/user/{{.Something.CreatedBy}}" class="username">{{.Something.CreatedByName}}</a>
{{if .Something.Tag}}<a class="username" style="float: right;">{{.Something.Tag}}</a>{{end}}
{{if .Something.Tag}}<a class="username" style="float: right;">{{.Something.Tag}}</a>{{else if .Something.URLName}}<a href="{{.Something.URL}}" class="username" style="color: #505050;float: right;">{{.Something.URLName}}</a>
<a class="username" style="color: #505050;float: right;border-right: 0;">{{.Something.URLPrefix}}</a>{{end}}
</div>
</div><br />
<div class="rowblock" style="overflow: hidden;">
@ -38,7 +39,8 @@
{{if $.CurrentUser.Is_Mod}}<a href="/reply/edit/submit/{{$element.ID}}"><button class="username edit_item">Edit</button></a>
<a href="/reply/delete/submit/{{$element.ID}}"><button class="username delete_item">Delete</button></a>{{end}}
<a href="/reply/report/submit/{{$element.ID}}"><button class="username report_item">Report</button></a>
{{if $element.Tag}}<a class="username" style="float: right;">{{$element.Tag}}</a>{{end}}
{{if $element.Tag}}<a class="username" style="float: right;">{{$element.Tag}}</a>{{else if $element.URLName}}<a href="{{$element.URL}}" class="username" style="color: #505050;float: right;" rel="nofollow">{{$element.URLName}}</a>
<a class="username" style="color: #505050;float: right;border-right: 0;">{{$element.URLPrefix}}</a>{{end}}
</div>{{end}}
</div>
{{if not .CurrentUser.Is_Banned}}

View File

@ -31,4 +31,7 @@ type TopicUser struct
Css template.CSS
ContentLines int
Tag string
URL string
URLPrefix string
URLName string
}

View File

@ -20,6 +20,9 @@ type User struct
Session string
Loggedin bool
Avatar string
Message string
URLPrefix string
URLName string
}
func SetPassword(uid int, password string) (error) {
@ -42,7 +45,7 @@ func SetPassword(uid int, password string) (error) {
}
func SessionCheck(w http.ResponseWriter, r *http.Request) (User) {
user := User{0,"",0,false,false,false,false,false,"",false,""}
user := User{0,"",0,false,false,false,false,false,"",false,"","","",""}
var err error
var cookie *http.Cookie
@ -64,7 +67,7 @@ func SessionCheck(w http.ResponseWriter, r *http.Request) (User) {
user.Session = cookie.Value
// 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.Avatar)
err = get_session_stmt.QueryRow(user.ID,user.Session).Scan(&user.ID, &user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName)
if err == sql.ErrNoRows {
return user
} else if err != nil {
@ -76,6 +79,7 @@ func SessionCheck(w http.ResponseWriter, r *http.Request) (User) {
user.Is_Super_Mod = groups[user.Group].Is_Mod || user.Is_Admin
user.Is_Mod = user.Is_Super_Mod
user.Is_Banned = groups[user.Group].Is_Banned
user.Loggedin = !user.Is_Banned || user.Is_Super_Mod
if user.Is_Banned && user.Is_Super_Mod {
user.Is_Banned = false
}
@ -87,6 +91,5 @@ func SessionCheck(w http.ResponseWriter, r *http.Request) (User) {
} else {
user.Avatar = strings.Replace(noavatar,"{id}",strconv.Itoa(user.ID),1)
}
user.Loggedin = true
return user
}