diff --git a/.htaccess b/.htaccess
new file mode 100644
index 00000000..81855e91
--- /dev/null
+++ b/.htaccess
@@ -0,0 +1,3 @@
+# Gosora doesn't use Apache, this file is just here to stop Apache from blindly serving our config files, etc. when this program isn't intended to be served in such a manner at all
+
+deny from all
\ No newline at end of file
diff --git a/README.md b/README.md
index 79c5bd2f..7d56374e 100644
--- a/README.md
+++ b/README.md
@@ -104,10 +104,14 @@ We're looking for ways to clean-up the plugin system so that all of them (except
![Tempra Simple Mobile](https://github.com/Azareal/Gosora/blob/master/images/tempra-simple-mobile-375px.png)
+![Tempra Cursive Theme](https://github.com/Azareal/Gosora/blob/master/images/tempra-cursive.png)
+
![Tempra Conflux Theme](https://github.com/Azareal/Gosora/blob/master/images/tempra-conflux.png)
![Tempra Conflux Mobile](https://github.com/Azareal/Gosora/blob/master/images/tempra-conflux-mobile-320px.png)
+![Tempra Conflux Mobile](https://github.com/Azareal/Gosora/blob/master/images/tempra-conflux-control-panel.png)
+
![Cosmo Conflux Theme](https://github.com/Azareal/Gosora/blob/master/images/cosmo-conflux.png)
![Cosmo Theme](https://github.com/Azareal/Gosora/blob/master/images/cosmo.png)
diff --git a/forum.go b/forum.go
index 7b2fad0b..988aac15 100644
--- a/forum.go
+++ b/forum.go
@@ -13,9 +13,7 @@ type ForumAdmin struct
Active bool
Preset string
TopicCount int
-
PresetLang string
- PresetEmoji string
}
type Forum struct
diff --git a/gen_router.go b/gen_router.go
index b4a3c09d..9c58a4ec 100644
--- a/gen_router.go
+++ b/gen_router.go
@@ -1,5 +1,6 @@
// Code generated by. DO NOT EDIT.
/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */
+// The router generator might be discontinued in favour of syncmaps in Go 1.9, it will be temporarily used for a couple of months as a lockless alternative to maps
package main
//import "fmt"
diff --git a/group.go b/group.go
index 63754b0a..5c386281 100644
--- a/group.go
+++ b/group.go
@@ -12,7 +12,7 @@ type GroupAdmin struct
ID int
Name string
Rank string
- RankEmoji string
+ RankClass string
CanEdit bool
CanDelete bool
}
diff --git a/images/alerts.png b/images/cosmo-alerts.png
similarity index 100%
rename from images/alerts.png
rename to images/cosmo-alerts.png
diff --git a/images/create-topic.png b/images/create-topic.png
new file mode 100644
index 00000000..c90d9c31
Binary files /dev/null and b/images/create-topic.png differ
diff --git a/images/edit_setting.PNG b/images/edit_setting.PNG
index b9ffa77d..e1b8b7d8 100644
Binary files a/images/edit_setting.PNG and b/images/edit_setting.PNG differ
diff --git a/images/forum-list.PNG b/images/forum-list.PNG
index a2d703d5..4b6fe612 100644
Binary files a/images/forum-list.PNG and b/images/forum-list.PNG differ
diff --git a/images/group_editor.png b/images/group_editor.png
new file mode 100644
index 00000000..73c11969
Binary files /dev/null and b/images/group_editor.png differ
diff --git a/images/group_editor_wip.png b/images/group_editor_wip.png
deleted file mode 100644
index b0d4c781..00000000
Binary files a/images/group_editor_wip.png and /dev/null differ
diff --git a/images/group_list.png b/images/group_list.png
new file mode 100644
index 00000000..98958a3f
Binary files /dev/null and b/images/group_list.png differ
diff --git a/images/group_list_wip.png b/images/group_list_wip.png
deleted file mode 100644
index 18651a73..00000000
Binary files a/images/group_list_wip.png and /dev/null differ
diff --git a/images/panel-dashboard.png b/images/panel-dashboard.png
index 8dd11c87..9d01c097 100644
Binary files a/images/panel-dashboard.png and b/images/panel-dashboard.png differ
diff --git a/images/tempra-cursive.png b/images/tempra-cursive.png
index fed58034..4d731aae 100644
Binary files a/images/tempra-cursive.png and b/images/tempra-cursive.png differ
diff --git a/images/tempra-simple-alerts.png b/images/tempra-simple-alerts.png
new file mode 100644
index 00000000..d470c5bf
Binary files /dev/null and b/images/tempra-simple-alerts.png differ
diff --git a/panel_routes.go b/panel_routes.go
index 8dd7ad41..f2e5503d 100644
--- a/panel_routes.go
+++ b/panel_routes.go
@@ -28,7 +28,7 @@ func route_panel(w http.ResponseWriter, r *http.Request){
NoPermissions(w,r,user)
return
}
-
+
var cpustr, cpuColour string
perc2, err := cpu.Percent(time.Duration(time.Second),true)
if err != nil {
@@ -44,7 +44,7 @@ func route_panel(w http.ResponseWriter, r *http.Request){
cpuColour = "stat_red"
}
}
-
+
var ramstr, ramColour string
memres, err := mem.VirtualMemory()
if err != nil {
@@ -52,7 +52,7 @@ func route_panel(w http.ResponseWriter, r *http.Request){
} else {
total_count, total_unit := convert_byte_unit(float64(memres.Total))
used_count := convert_byte_in_unit(float64(memres.Total - memres.Available),total_unit)
-
+
// Round totals with .9s up, it's how most people see it anyway. Floats are notoriously imprecise, so do it off 0.85
//fmt.Println(used_count)
var totstr string
@@ -63,12 +63,12 @@ func route_panel(w http.ResponseWriter, r *http.Request){
totstr = fmt.Sprintf("%.1f",total_count)
}
//fmt.Println(used_count)
-
+
if used_count > total_count {
used_count = total_count
}
ramstr = fmt.Sprintf("%.1f",used_count) + " / " + totstr + total_unit
-
+
ramperc := ((memres.Total - memres.Available) * 100) / memres.Total
//fmt.Println(ramperc)
if ramperc < 50 {
@@ -79,7 +79,7 @@ func route_panel(w http.ResponseWriter, r *http.Request){
ramColour = "stat_red"
}
}
-
+
var postCount int
err = db.QueryRow("select count(*) from replies where createdAt BETWEEN (now() - interval 1 day) and now()").Scan(&postCount)
if err != nil && err != sql.ErrNoRows {
@@ -87,7 +87,7 @@ func route_panel(w http.ResponseWriter, r *http.Request){
return
}
var postInterval string = "day"
-
+
var postColour string
if postCount > 25 {
postColour = "stat_green"
@@ -96,7 +96,7 @@ func route_panel(w http.ResponseWriter, r *http.Request){
} else {
postColour = "stat_red"
}
-
+
var topicCount int
err = db.QueryRow("select count(*) from topics where createdAt BETWEEN (now() - interval 1 day) and now()").Scan(&topicCount)
if err != nil && err != sql.ErrNoRows {
@@ -104,7 +104,7 @@ func route_panel(w http.ResponseWriter, r *http.Request){
return
}
var topicInterval string = "day"
-
+
var topicColour string
if topicCount > 8 {
topicColour = "stat_green"
@@ -113,7 +113,7 @@ func route_panel(w http.ResponseWriter, r *http.Request){
} else {
topicColour = "stat_red"
}
-
+
var reportCount int
err = db.QueryRow("select count(*) from topics where createdAt BETWEEN (now() - interval 1 day) and now() and parentID = 1").Scan(&reportCount)
if err != nil && err != sql.ErrNoRows {
@@ -121,7 +121,7 @@ func route_panel(w http.ResponseWriter, r *http.Request){
return
}
var reportInterval string = "week"
-
+
var newUserCount int
err = db.QueryRow("select count(*) from users where createdAt BETWEEN (now() - interval 1 day) and now()").Scan(&newUserCount)
if err != nil && err != sql.ErrNoRows {
@@ -129,18 +129,18 @@ func route_panel(w http.ResponseWriter, r *http.Request){
return
}
var newUserInterval string = "week"
-
+
var gridElements []GridElement = []GridElement{
GridElement{"dash-version","v" + version.String(),0,"grid_istat stat_green","","","Gosora is up-to-date :)"},
GridElement{"dash-cpu","CPU: " + cpustr + "%",1,"grid_istat " + cpuColour,"","","The global CPU usage of this server"},
GridElement{"dash-ram","RAM: " + ramstr,2,"grid_istat " + ramColour,"","","The global RAM usage of this server"},
}
-
+
if enable_websockets {
uonline := ws_hub.UserCount()
gonline := ws_hub.GuestCount()
totonline := uonline + gonline
-
+
var onlineColour string
if totonline > 10 {
onlineColour = "stat_green"
@@ -149,7 +149,7 @@ func route_panel(w http.ResponseWriter, r *http.Request){
} else {
onlineColour = "stat_red"
}
-
+
var onlineGuestsColour string
if gonline > 10 {
onlineGuestsColour = "stat_green"
@@ -158,7 +158,7 @@ func route_panel(w http.ResponseWriter, r *http.Request){
} else {
onlineGuestsColour = "stat_red"
}
-
+
var onlineUsersColour string
if uonline > 5 {
onlineUsersColour = "stat_green"
@@ -167,28 +167,28 @@ func route_panel(w http.ResponseWriter, r *http.Request){
} else {
onlineUsersColour = "stat_red"
}
-
+
totonline, totunit := convert_friendly_unit(totonline)
uonline, uunit := convert_friendly_unit(uonline)
gonline, gunit := convert_friendly_unit(gonline)
-
+
gridElements = append(gridElements, GridElement{"dash-totonline",strconv.Itoa(totonline) + totunit + " online",3,"grid_stat " + onlineColour,"","","The number of people who are currently online"})
gridElements = append(gridElements, GridElement{"dash-gonline",strconv.Itoa(gonline) + gunit + " guests online",4,"grid_stat " + onlineGuestsColour,"","","The number of guests who are currently online"})
gridElements = append(gridElements, GridElement{"dash-uonline",strconv.Itoa(uonline) + uunit + " users online",5,"grid_stat " + onlineUsersColour,"","","The number of logged-in users who are currently online"})
}
-
+
gridElements = append(gridElements, GridElement{"dash-postsperday",strconv.Itoa(postCount) + " posts / " + postInterval,6,"grid_stat " + postColour,"","","The number of new posts over the last 24 hours"})
gridElements = append(gridElements, GridElement{"dash-topicsperday",strconv.Itoa(topicCount) + " topics / " + topicInterval,7,"grid_stat " + topicColour,"","","The number of new topics over the last 24 hours"})
gridElements = append(gridElements, GridElement{"dash-totonlineperday","20 online / day",8,"grid_stat stat_disabled","","","Coming Soon!"/*"The people online over the last 24 hours"*/})
-
+
gridElements = append(gridElements, GridElement{"dash-searches","8 searches / week",9,"grid_stat stat_disabled","","","Coming Soon!"/*"The number of searches over the last 7 days"*/})
gridElements = append(gridElements, GridElement{"dash-newusers",strconv.Itoa(newUserCount) + " new users / " + newUserInterval,10,"grid_stat","","","The number of new users over the last 7 days"})
gridElements = append(gridElements, GridElement{"dash-reports",strconv.Itoa(reportCount) + " reports / " + reportInterval,11,"grid_stat","","","The number of reports over the last 7 days"})
-
+
gridElements = append(gridElements, GridElement{"dash-minperuser","2 minutes / user / week",12,"grid_stat stat_disabled","","","Coming Soon!"/*"The average number of number of minutes spent by each active user over the last 7 days"*/})
gridElements = append(gridElements, GridElement{"dash-visitorsperweek","2 visitors / week",13,"grid_stat stat_disabled","","","Coming Soon!"/*"The number of unique visitors we've had over the last 7 days"*/})
gridElements = append(gridElements, GridElement{"dash-postsperuser","5 posts / user / week",14,"grid_stat stat_disabled","","","Coming Soon!"/*"The average number of posts made by each active user over the past week"*/})
-
+
pi := PanelDashboardPage{"Control Panel Dashboard",user,noticeList,gridElements,nil}
templates.ExecuteTemplate(w,"panel-dashboard.html",pi)
}
@@ -202,16 +202,22 @@ func route_panel_forums(w http.ResponseWriter, r *http.Request){
NoPermissions(w,r,user)
return
}
-
+
var forumList []interface{}
for _, forum := range forums {
if forum.Name != "" {
- fadmin := ForumAdmin{forum.ID,forum.Name,forum.Active,forum.Preset,forum.TopicCount,preset_to_lang(forum.Preset),preset_to_emoji(forum.Preset)}
+ fadmin := ForumAdmin{forum.ID,forum.Name,forum.Active,forum.Preset,forum.TopicCount,preset_to_lang(forum.Preset)}
+ if fadmin.Preset == "" {
+ fadmin.Preset = "custom"
+ }
forumList = append(forumList,fadmin)
}
}
pi := Page{"Forum Manager",user,noticeList,forumList,nil}
- templates.ExecuteTemplate(w,"panel-forums.html",pi)
+ err := templates.ExecuteTemplate(w,"panel-forums.html",pi)
+ if err != nil {
+ InternalError(err,w,r)
+ }
}
func route_panel_forums_create_submit(w http.ResponseWriter, r *http.Request){
@@ -223,17 +229,17 @@ func route_panel_forums_create_submit(w http.ResponseWriter, r *http.Request){
NoPermissions(w,r,user)
return
}
-
+
err := r.ParseForm()
if err != nil {
LocalError("Bad Form",w,r,user)
- return
+ return
}
if r.FormValue("session") != user.Session {
SecurityError(w,r,user)
return
}
-
+
var active bool
fname := r.PostFormValue("forum-name")
fpreset := strip_invalid_preset(r.PostFormValue("forum-preset"))
@@ -243,13 +249,13 @@ func route_panel_forums_create_submit(w http.ResponseWriter, r *http.Request){
} else {
active = false
}
-
+
fid, err := create_forum(fname,active,fpreset)
if err != nil {
InternalError(err,w,r)
return
}
-
+
permmap_to_query(preset_to_permmap(fpreset),fid)
http.Redirect(w,r,"/panel/forums/",http.StatusSeeOther)
}
@@ -267,21 +273,21 @@ func route_panel_forums_delete(w http.ResponseWriter, r *http.Request, sfid stri
SecurityError(w,r,user)
return
}
-
+
fid, err := strconv.Atoi(sfid)
if err != nil {
LocalError("The provided Forum ID is not a valid number.",w,r,user)
return
}
-
+
if !forum_exists(fid) {
LocalError("The forum you're trying to delete doesn't exist.",w,r,user)
return
}
-
+
confirm_msg := "Are you sure you want to delete the '" + forums[fid].Name + "' forum?"
yousure := AreYouSure{"/panel/forums/delete/submit/" + strconv.Itoa(fid),confirm_msg}
-
+
pi := Page{"Delete Forum",user,noticeList,tList,yousure}
templates.ExecuteTemplate(w,"areyousure.html",pi)
}
@@ -299,7 +305,7 @@ func route_panel_forums_delete_submit(w http.ResponseWriter, r *http.Request, sf
SecurityError(w,r,user)
return
}
-
+
fid, err := strconv.Atoi(sfid)
if err != nil {
LocalError("The provided Forum ID is not a valid number.",w,r,user)
@@ -309,7 +315,7 @@ func route_panel_forums_delete_submit(w http.ResponseWriter, r *http.Request, sf
LocalError("The forum you're trying to delete doesn't exist.",w,r,user)
return
}
-
+
err = delete_forum(fid)
if err != nil {
InternalError(err,w,r)
@@ -327,7 +333,7 @@ func route_panel_forums_edit(w http.ResponseWriter, r *http.Request, sfid string
NoPermissions(w,r,user)
return
}
-
+
fid, err := strconv.Atoi(sfid)
if err != nil {
LocalError("The provided Forum ID is not a valid number.",w,r,user)
@@ -337,7 +343,7 @@ func route_panel_forums_edit(w http.ResponseWriter, r *http.Request, sfid string
LocalError("The forum you're trying to edit doesn't exist.",w,r,user)
return
}
-
+
pi := Page{"Forum Editor",user,noticeList,tList,nil}
templates.ExecuteTemplate(w,"panel-forum-edit.html",pi)
}
@@ -351,11 +357,11 @@ func route_panel_forums_edit_submit(w http.ResponseWriter, r *http.Request, sfid
NoPermissions(w,r,user)
return
}
-
+
err := r.ParseForm()
if err != nil {
LocalError("Bad Form",w,r,user)
- return
+ return
}
if r.FormValue("session") != user.Session {
SecurityError(w,r,user)
@@ -365,30 +371,30 @@ func route_panel_forums_edit_submit(w http.ResponseWriter, r *http.Request, sfid
if is_js == "" {
is_js = "0"
}
-
+
fid, err := strconv.Atoi(sfid)
if err != nil {
LocalErrorJSQ("The provided Forum ID is not a valid number.",w,r,user,is_js)
return
}
-
- forum_name := r.PostFormValue("forum-name")
- forum_preset := strip_invalid_preset(r.PostFormValue("forum-preset"))
- forum_active := r.PostFormValue("forum-active")
+
+ forum_name := r.PostFormValue("forum_name")
+ forum_preset := strip_invalid_preset(r.PostFormValue("forum_preset"))
+ forum_active := r.PostFormValue("forum_active")
if !forum_exists(fid) {
LocalErrorJSQ("The forum you're trying to edit doesn't exist.",w,r,user,is_js)
return
}
-
+
/*if forum_name == "" && forum_active == "" {
LocalErrorJSQ("You haven't changed anything!",w,r,user,is_js)
return
}*/
-
+
if forum_name == "" {
forum_name = forums[fid].Name
}
-
+
var active bool
if forum_active == "" {
active = forums[fid].Active
@@ -397,13 +403,13 @@ func route_panel_forums_edit_submit(w http.ResponseWriter, r *http.Request, sfid
} else {
active = false
}
-
+
_, err = update_forum_stmt.Exec(forum_name,active,forum_preset,fid)
if err != nil {
InternalErrorJSQ(err,w,r,is_js)
return
}
-
+
if forums[fid].Name != forum_name {
forums[fid].Name = forum_name
}
@@ -413,9 +419,9 @@ func route_panel_forums_edit_submit(w http.ResponseWriter, r *http.Request, sfid
if forums[fid].Preset != forum_preset {
forums[fid].Preset = forum_preset
}
-
+
permmap_to_query(preset_to_permmap(forum_preset),fid)
-
+
if is_js == "0" {
http.Redirect(w,r,"/panel/forums/",http.StatusSeeOther)
} else {
@@ -432,7 +438,7 @@ func route_panel_settings(w http.ResponseWriter, r *http.Request){
NoPermissions(w,r,user)
return
}
-
+
var settingList map[string]interface{} = make(map[string]interface{})
rows, err := db.Query("select name, content, type from settings")
if err != nil {
@@ -440,7 +446,7 @@ func route_panel_settings(w http.ResponseWriter, r *http.Request){
return
}
defer rows.Close()
-
+
var sname, scontent, stype string
for rows.Next() {
err := rows.Scan(&sname,&scontent,&stype)
@@ -448,7 +454,7 @@ func route_panel_settings(w http.ResponseWriter, r *http.Request){
InternalError(err,w,r)
return
}
-
+
if stype == "list" {
llist := settingLabels[sname]
labels := strings.Split(llist,",")
@@ -472,7 +478,7 @@ func route_panel_settings(w http.ResponseWriter, r *http.Request){
InternalError(err,w,r)
return
}
-
+
pi := Page{"Setting Manager",user,noticeList,tList,settingList}
templates.ExecuteTemplate(w,"panel-settings.html",pi)
}
@@ -487,7 +493,7 @@ func route_panel_setting(w http.ResponseWriter, r *http.Request, sname string){
return
}
setting := Setting{sname,"","",""}
-
+
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)
@@ -496,7 +502,7 @@ func route_panel_setting(w http.ResponseWriter, r *http.Request, sname string){
InternalError(err,w,r)
return
}
-
+
var itemList []interface{}
if setting.Type == "list" {
llist, ok := settingLabels[setting.Name]
@@ -504,13 +510,13 @@ func route_panel_setting(w http.ResponseWriter, r *http.Request, sname string){
LocalError("The labels for this setting don't exist",w,r,user)
return
}
-
+
conv, err := strconv.Atoi(setting.Content)
if err != nil {
LocalError("The value of this setting couldn't be converted to an integer",w,r,user)
return
}
-
+
labels := strings.Split(llist,",")
for index, label := range labels {
itemList = append(itemList, OptionLabel{
@@ -520,7 +526,7 @@ func route_panel_setting(w http.ResponseWriter, r *http.Request, sname string){
})
}
}
-
+
pi := Page{"Edit Setting",user,noticeList,itemList,setting}
templates.ExecuteTemplate(w,"panel-setting.html",pi)
}
@@ -534,21 +540,21 @@ func route_panel_setting_edit(w http.ResponseWriter, r *http.Request, sname stri
NoPermissions(w,r,user)
return
}
-
+
err := r.ParseForm()
if err != nil {
LocalError("Bad Form",w,r,user)
- return
+ return
}
if r.FormValue("session") != user.Session {
SecurityError(w,r,user)
return
}
-
+
var stype string
var sconstraints string
scontent := r.PostFormValue("setting-value")
-
+
err = db.QueryRow("select name, type, constraints from settings where name = ?", sname).Scan(&sname, &stype, &sconstraints)
if err == sql.ErrNoRows {
LocalError("The setting you want to edit doesn't exist.",w,r,user)
@@ -557,7 +563,7 @@ func route_panel_setting_edit(w http.ResponseWriter, r *http.Request, sname stri
InternalError(err,w,r)
return
}
-
+
if stype == "bool" {
if scontent == "on" || scontent == "1" {
scontent = "1"
@@ -565,13 +571,13 @@ func route_panel_setting_edit(w http.ResponseWriter, r *http.Request, sname stri
scontent = "0"
}
}
-
+
_, err = update_setting_stmt.Exec(scontent,sname)
if err != nil {
InternalError(err,w,r)
return
}
-
+
errmsg := parseSetting(sname, scontent, stype, sconstraints)
if errmsg != "" {
LocalError(errmsg,w,r,user)
@@ -589,12 +595,12 @@ func route_panel_plugins(w http.ResponseWriter, r *http.Request){
NoPermissions(w,r,user)
return
}
-
+
var pluginList []interface{}
for _, plugin := range plugins {
pluginList = append(pluginList,plugin)
}
-
+
pi := Page{"Plugin Manager",user,noticeList,pluginList,nil}
templates.ExecuteTemplate(w,"panel-plugins.html",pi)
}
@@ -612,20 +618,20 @@ func route_panel_plugins_activate(w http.ResponseWriter, r *http.Request, uname
SecurityError(w,r,user)
return
}
-
+
plugin, ok := plugins[uname]
if !ok {
LocalError("The plugin isn't registered in the system",w,r,user)
return
}
-
+
var active bool
err := db.QueryRow("select active from plugins where uname = ?", uname).Scan(&active)
if err != nil && err != sql.ErrNoRows {
InternalError(err,w,r)
return
}
-
+
if plugins[uname].Activate != nil {
err = plugins[uname].Activate()
if err != nil {
@@ -633,7 +639,7 @@ func route_panel_plugins_activate(w http.ResponseWriter, r *http.Request, uname
return
}
}
-
+
has_plugin := err != sql.ErrNoRows
if has_plugin {
if active {
@@ -652,7 +658,7 @@ func route_panel_plugins_activate(w http.ResponseWriter, r *http.Request, uname
return
}
}
-
+
log.Print("Activating plugin '" + plugin.Name + "'")
plugin.Active = true
plugins[uname] = plugin
@@ -669,18 +675,18 @@ func route_panel_plugins_deactivate(w http.ResponseWriter, r *http.Request, unam
NoPermissions(w,r,user)
return
}
-
+
if r.FormValue("session") != user.Session {
SecurityError(w,r,user)
return
}
-
+
plugin, ok := plugins[uname]
if !ok {
LocalError("The plugin isn't registered in the system",w,r,user)
return
}
-
+
var active bool
err := db.QueryRow("select active from plugins where uname = ?", uname).Scan(&active)
if err == sql.ErrNoRows {
@@ -690,7 +696,7 @@ func route_panel_plugins_deactivate(w http.ResponseWriter, r *http.Request, unam
InternalError(err,w,r)
return
}
-
+
if !active {
LocalError("The plugin you're trying to deactivate isn't active",w,r,user)
return
@@ -700,11 +706,11 @@ func route_panel_plugins_deactivate(w http.ResponseWriter, r *http.Request, unam
InternalError(err,w,r)
return
}
-
+
plugin.Active = false
plugins[uname] = plugin
plugins[uname].Deactivate()
-
+
http.Redirect(w,r,"/panel/plugins/",http.StatusSeeOther)
}
@@ -717,7 +723,7 @@ func route_panel_users(w http.ResponseWriter, r *http.Request){
NoPermissions(w,r,user)
return
}
-
+
var userList []interface{}
rows, err := db.Query("select `uid`,`name`,`group`,`active`,`is_super_admin`,`avatar` from users")
if err != nil {
@@ -725,7 +731,7 @@ func route_panel_users(w http.ResponseWriter, r *http.Request){
return
}
defer rows.Close()
-
+
for rows.Next() {
puser := User{ID: 0,}
err := rows.Scan(&puser.ID, &puser.Name, &puser.Group, &puser.Active, &puser.Is_Super_Admin, &puser.Avatar)
@@ -733,7 +739,7 @@ func route_panel_users(w http.ResponseWriter, r *http.Request){
InternalError(err,w,r)
return
}
-
+
init_user_perms(&puser)
if puser.Avatar != "" {
if puser.Avatar[0] == '.' {
@@ -742,7 +748,7 @@ func route_panel_users(w http.ResponseWriter, r *http.Request){
} else {
puser.Avatar = strings.Replace(noavatar,"{id}",strconv.Itoa(puser.ID),1)
}
-
+
if groups[puser.Group].Tag != "" {
puser.Tag = groups[puser.Group].Tag
} else {
@@ -755,7 +761,7 @@ func route_panel_users(w http.ResponseWriter, r *http.Request){
InternalError(err,w,r)
return
}
-
+
pi := Page{"User Manager",user,noticeList,userList,nil}
err = templates.ExecuteTemplate(w,"panel-users.html",pi)
if err != nil {
@@ -768,19 +774,19 @@ func route_panel_users_edit(w http.ResponseWriter, r *http.Request,suid string){
if !ok {
return
}
-
+
// Even if they have the right permissions, the control panel is only open to supermods+. There are many areas without subpermissions which assume that the current user is a supermod+ and admins are extremely unlikely to give these permissions to someone who isn't at-least a supermod to begin with
if !user.Is_Super_Mod || !user.Perms.EditUser {
NoPermissions(w,r,user)
return
}
-
+
uid, err := strconv.Atoi(suid)
if err != nil {
LocalError("The provided User ID is not a valid number.",w,r,user)
return
}
-
+
targetUser, err := users.CascadeGet(uid)
if err == sql.ErrNoRows {
LocalError("The user you're trying to edit doesn't exist.",w,r,user)
@@ -789,12 +795,12 @@ func route_panel_users_edit(w http.ResponseWriter, r *http.Request,suid string){
InternalError(err,w,r)
return
}
-
+
if targetUser.Is_Admin && !user.Is_Admin {
LocalError("Only administrators can edit the account of an administrator.",w,r,user)
return
}
-
+
var groupList []interface{}
for _, group := range groups[1:] {
if !user.Perms.EditUserGroupAdmin && group.Is_Admin {
@@ -805,7 +811,7 @@ func route_panel_users_edit(w http.ResponseWriter, r *http.Request,suid string){
}
groupList = append(groupList,group)
}
-
+
pi := Page{"User Editor",user,noticeList,groupList,targetUser}
err = templates.ExecuteTemplate(w,"panel-user-edit.html",pi)
if err != nil {
@@ -826,13 +832,13 @@ func route_panel_users_edit_submit(w http.ResponseWriter, r *http.Request, suid
SecurityError(w,r,user)
return
}
-
+
uid, err := strconv.Atoi(suid)
if err != nil {
LocalError("The provided User ID is not a valid number.",w,r,user)
return
}
-
+
targetUser, err := users.CascadeGet(uid)
if err == sql.ErrNoRows {
LocalError("The user you're trying to edit doesn't exist.",w,r,user)
@@ -841,18 +847,18 @@ func route_panel_users_edit_submit(w http.ResponseWriter, r *http.Request, suid
InternalError(err,w,r)
return
}
-
+
if targetUser.Is_Admin && !user.Is_Admin {
LocalError("Only administrators can edit the account of an administrator.",w,r,user)
return
}
-
+
newname := html.EscapeString(r.PostFormValue("user-name"))
if newname == "" {
LocalError("You didn't put in a username.",w,r,user)
return
}
-
+
newemail := html.EscapeString(r.PostFormValue("user-email"))
if newemail == "" {
LocalError("You didn't put in an email address.",w,r,user)
@@ -862,24 +868,24 @@ func route_panel_users_edit_submit(w http.ResponseWriter, r *http.Request, suid
LocalError("You need the EditUserEmail permission to edit the email address of a user.",w,r,user)
return
}
-
+
newpassword := r.PostFormValue("user-password")
if newpassword != "" && !user.Perms.EditUserPassword {
LocalError("You need the EditUserPassword permission to edit the password of a user.",w,r,user)
return
}
-
+
newgroup, err := strconv.Atoi(r.PostFormValue("user-group"))
if err != nil {
LocalError("The provided GroupID is not a valid number.",w,r,user)
return
}
-
+
if (newgroup > groupCapCount) || (newgroup < 0) || groups[newgroup].Name=="" {
LocalError("The group you're trying to place this user in doesn't exist.",w,r,user)
return
}
-
+
if !user.Perms.EditUserGroupAdmin && groups[newgroup].Is_Admin {
LocalError("You need the EditUserGroupAdmin permission to assign someone to an administrator group.",w,r,user)
return
@@ -888,23 +894,23 @@ func route_panel_users_edit_submit(w http.ResponseWriter, r *http.Request, suid
LocalError("You need the EditUserGroupAdmin permission to assign someone to a super mod group.",w,r,user)
return
}
-
+
_, err = update_user_stmt.Exec(newname,newemail,newgroup,targetUser.ID)
if err != nil {
InternalError(err,w,r)
return
}
-
+
if newpassword != "" {
SetPassword(targetUser.ID,newpassword)
}
-
+
err = users.Load(targetUser.ID)
if err != nil {
LocalError("This user no longer exists!",w,r,user)
return
}
-
+
http.Redirect(w,r,"/panel/users/edit/" + strconv.Itoa(targetUser.ID),http.StatusSeeOther)
}
@@ -917,37 +923,37 @@ func route_panel_groups(w http.ResponseWriter, r *http.Request){
NoPermissions(w,r,user)
return
}
-
+
var groupList []interface{}
for _, group := range groups[1:] {
var rank string
- var rank_emoji string
+ var rank_class string
var can_edit bool
var can_delete bool = false
-
+
if group.Is_Admin {
rank = "Admin"
- rank_emoji = "👑"
+ rank_class = "admin"
} else if group.Is_Mod {
rank = "Mod"
- rank_emoji = "👮"
+ rank_class = "mod"
} else if group.Is_Banned {
rank = "Banned"
- rank_emoji = "⛓️"
+ rank_class = "banned"
} else if group.ID == 6 {
rank = "Guest"
- rank_emoji = "👽"
+ rank_class = "guest"
} else {
rank = "Member"
- rank_emoji = "👪"
+ rank_class = "member"
}
-
+
can_edit = user.Perms.EditGroup && (!group.Is_Admin || user.Perms.EditGroupAdmin) && (!group.Is_Mod || user.Perms.EditGroupSuperMod)
-
- groupList = append(groupList, GroupAdmin{group.ID,group.Name,rank,rank_emoji,can_edit,can_delete})
+
+ groupList = append(groupList, GroupAdmin{group.ID,group.Name,rank,rank_class,can_edit,can_delete})
}
//fmt.Printf("%+v\n", groupList)
-
+
pi := Page{"Group Manager",user,noticeList,groupList,nil}
templates.ExecuteTemplate(w,"panel-groups.html",pi)
}
@@ -961,19 +967,19 @@ func route_panel_groups_edit(w http.ResponseWriter, r *http.Request, sgid string
NoPermissions(w,r,user)
return
}
-
+
gid, err := strconv.Atoi(sgid)
if err != nil {
LocalError("The Group ID is not a valid integer.",w,r,user)
return
}
-
+
if !group_exists(gid) {
//fmt.Println("aaaaa monsters")
NotFound(w,r)
return
}
-
+
group := groups[gid]
if group.Is_Admin && !user.Perms.EditGroupAdmin {
LocalError("You need the EditGroupAdmin permission to edit an admin group.",w,r,user)
@@ -983,7 +989,7 @@ func route_panel_groups_edit(w http.ResponseWriter, r *http.Request, sgid string
LocalError("You need the EditGroupSuperMod permission to edit a super-mod group.",w,r,user)
return
}
-
+
var rank string
if group.Is_Admin {
rank = "Admin"
@@ -996,9 +1002,9 @@ func route_panel_groups_edit(w http.ResponseWriter, r *http.Request, sgid string
} else {
rank = "Member"
}
-
+
disable_rank := !user.Perms.EditGroupGlobalPerms || (group.ID == 6)
-
+
pi := EditGroupPage{"Group Editor",user,noticeList,group.ID,group.Name,group.Tag,rank,disable_rank,nil}
err = templates.ExecuteTemplate(w,"panel-group-edit.html",pi)
if err != nil {
@@ -1015,19 +1021,19 @@ func route_panel_groups_edit_perms(w http.ResponseWriter, r *http.Request, sgid
NoPermissions(w,r,user)
return
}
-
+
gid, err := strconv.Atoi(sgid)
if err != nil {
LocalError("The Group ID is not a valid integer.",w,r,user)
return
}
-
+
if !group_exists(gid) {
//fmt.Println("aaaaa monsters")
NotFound(w,r)
return
}
-
+
group := groups[gid]
if group.Is_Admin && !user.Perms.EditGroupAdmin {
LocalError("You need the EditGroupAdmin permission to edit an admin group.",w,r,user)
@@ -1037,7 +1043,7 @@ func route_panel_groups_edit_perms(w http.ResponseWriter, r *http.Request, sgid
LocalError("You need the EditGroupSuperMod permission to edit a super-mod group.",w,r,user)
return
}
-
+
var localPerms []NameLangToggle
localPerms = append(localPerms, NameLangToggle{"ViewTopic",GetLocalPermPhrase("ViewTopic"),group.Perms.ViewTopic})
localPerms = append(localPerms, NameLangToggle{"LikeItem",GetLocalPermPhrase("LikeItem"),group.Perms.LikeItem})
@@ -1050,7 +1056,7 @@ func route_panel_groups_edit_perms(w http.ResponseWriter, r *http.Request, sgid
localPerms = append(localPerms, NameLangToggle{"DeleteReply",GetLocalPermPhrase("DeleteReply"),group.Perms.DeleteReply})
localPerms = append(localPerms, NameLangToggle{"PinTopic",GetLocalPermPhrase("PinTopic"),group.Perms.PinTopic})
localPerms = append(localPerms, NameLangToggle{"CloseTopic",GetLocalPermPhrase("CloseTopic"),group.Perms.CloseTopic})
-
+
var globalPerms []NameLangToggle
globalPerms = append(globalPerms, NameLangToggle{"BanUsers",GetGlobalPermPhrase("BanUsers"),group.Perms.BanUsers})
globalPerms = append(globalPerms, NameLangToggle{"ActivateUsers",GetGlobalPermPhrase("ActivateUsers"),group.Perms.ActivateUsers})
@@ -1071,7 +1077,7 @@ func route_panel_groups_edit_perms(w http.ResponseWriter, r *http.Request, sgid
globalPerms = append(globalPerms, NameLangToggle{"ManagePlugins",GetGlobalPermPhrase("ManagePlugins"),group.Perms.ManagePlugins})
globalPerms = append(globalPerms, NameLangToggle{"ViewAdminLogs",GetGlobalPermPhrase("ViewAdminLogs"),group.Perms.ViewAdminLogs})
globalPerms = append(globalPerms, NameLangToggle{"ViewIPs",GetGlobalPermPhrase("ViewIPs"),group.Perms.ViewIPs})
-
+
pi := EditGroupPermsPage{"Group Editor",user,noticeList,group.ID,group.Name,localPerms,globalPerms,nil}
err = templates.ExecuteTemplate(w,"panel-group-edit-perms.html",pi)
if err != nil {
@@ -1092,19 +1098,19 @@ func route_panel_groups_edit_submit(w http.ResponseWriter, r *http.Request, sgid
SecurityError(w,r,user)
return
}
-
+
gid, err := strconv.Atoi(sgid)
if err != nil {
LocalError("The Group ID is not a valid integer.",w,r,user)
return
}
-
+
if !group_exists(gid) {
//fmt.Println("aaaaa monsters")
NotFound(w,r)
return
}
-
+
group := groups[gid]
if group.Is_Admin && !user.Perms.EditGroupAdmin {
LocalError("You need the EditGroupAdmin permission to edit an admin group.",w,r,user)
@@ -1114,7 +1120,7 @@ func route_panel_groups_edit_submit(w http.ResponseWriter, r *http.Request, sgid
LocalError("You need the EditGroupSuperMod permission to edit a super-mod group.",w,r,user)
return
}
-
+
gname := r.FormValue("group-name")
if gname == "" {
LocalError("The group name can't be left blank.",w,r,user)
@@ -1122,7 +1128,7 @@ func route_panel_groups_edit_submit(w http.ResponseWriter, r *http.Request, sgid
}
gtag := r.FormValue("group-tag")
rank := r.FormValue("group-type")
-
+
var original_rank string
if group.Is_Admin {
original_rank = "Admin"
@@ -1135,7 +1141,7 @@ func route_panel_groups_edit_submit(w http.ResponseWriter, r *http.Request, sgid
} else {
original_rank = "Member"
}
-
+
group_update_mutex.Lock()
defer group_update_mutex.Unlock()
if rank != original_rank {
@@ -1143,14 +1149,14 @@ func route_panel_groups_edit_submit(w http.ResponseWriter, r *http.Request, sgid
LocalError("You need the EditGroupGlobalPerms permission to change the group type.",w,r,user)
return
}
-
+
switch(rank) {
case "Admin":
if !user.Perms.EditGroupAdmin {
LocalError("You need the EditGroupAdmin permission to designate this group as an admin group.",w,r,user)
return
}
-
+
_, err = update_group_rank_stmt.Exec(1,1,0,gid)
if err != nil {
InternalError(err,w,r)
@@ -1164,7 +1170,7 @@ func route_panel_groups_edit_submit(w http.ResponseWriter, r *http.Request, sgid
LocalError("You need the EditGroupSuperMod permission to designate this group as a super-mod group.",w,r,user)
return
}
-
+
_, err = update_group_rank_stmt.Exec(0,1,0,gid)
if err != nil {
InternalError(err,w,r)
@@ -1199,7 +1205,7 @@ func route_panel_groups_edit_submit(w http.ResponseWriter, r *http.Request, sgid
return
}
}
-
+
_, err = update_group_stmt.Exec(gname,gtag,gid)
if err != nil {
InternalError(err,w,r)
@@ -1207,7 +1213,7 @@ func route_panel_groups_edit_submit(w http.ResponseWriter, r *http.Request, sgid
}
groups[gid].Name = gname
groups[gid].Tag = gtag
-
+
http.Redirect(w,r,"/panel/groups/edit/" + strconv.Itoa(gid),http.StatusSeeOther)
}
@@ -1224,19 +1230,19 @@ func route_panel_groups_edit_perms_submit(w http.ResponseWriter, r *http.Request
SecurityError(w,r,user)
return
}
-
+
gid, err := strconv.Atoi(sgid)
if err != nil {
LocalError("The Group ID is not a valid integer.",w,r,user)
return
}
-
+
if !group_exists(gid) {
//fmt.Println("aaaaa monsters")
NotFound(w,r)
return
}
-
+
group := groups[gid]
if group.Is_Admin && !user.Perms.EditGroupAdmin {
LocalError("You need the EditGroupAdmin permission to edit an admin group.",w,r,user)
@@ -1246,7 +1252,7 @@ func route_panel_groups_edit_perms_submit(w http.ResponseWriter, r *http.Request
LocalError("You need the EditGroupSuperMod permission to edit a super-mod group.",w,r,user)
return
}
-
+
//var lpmap map[string]bool = make(map[string]bool)
var pmap map[string]bool = make(map[string]bool)
if user.Perms.EditGroupLocalPerms {
@@ -1256,7 +1262,7 @@ func route_panel_groups_edit_perms_submit(w http.ResponseWriter, r *http.Request
pmap[perm] = (pvalue == "1")
}
}
-
+
//var gpmap map[string]bool = make(map[string]bool)
if user.Perms.EditGroupGlobalPerms {
gplist := GlobalPermList
@@ -1265,25 +1271,25 @@ func route_panel_groups_edit_perms_submit(w http.ResponseWriter, r *http.Request
pmap[perm] = (pvalue == "1")
}
}
-
+
pjson, err := json.Marshal(pmap)
if err != nil {
LocalError("Unable to marshal the data",w,r,user)
return
}
-
+
_, err = update_group_perms_stmt.Exec(pjson,gid)
if err != nil {
InternalError(err,w,r)
return
}
-
+
err = rebuild_group_permissions(gid)
if err != nil {
InternalError(err,w,r)
return
}
-
+
http.Redirect(w,r,"/panel/groups/edit/perms/" + strconv.Itoa(gid),http.StatusSeeOther)
}
@@ -1300,14 +1306,14 @@ func route_panel_groups_create_submit(w http.ResponseWriter, r *http.Request){
SecurityError(w,r,user)
return
}
-
+
group_name := r.PostFormValue("group-name")
if group_name == "" {
LocalError("You need a name for this group!",w,r,user)
return
}
group_tag := r.PostFormValue("group-tag")
-
+
var is_admin, is_mod, is_banned bool
if user.Perms.EditGroupGlobalPerms {
group_type := r.PostFormValue("group-type")
@@ -1328,7 +1334,7 @@ func route_panel_groups_create_submit(w http.ResponseWriter, r *http.Request){
is_banned = true
}
}
-
+
gid, err := create_group(group_name, group_tag, is_admin, is_mod, is_banned)
if err != nil {
InternalError(err,w,r)
@@ -1347,7 +1353,7 @@ func route_panel_themes(w http.ResponseWriter, r *http.Request){
NoPermissions(w,r,user)
return
}
-
+
var pThemeList, vThemeList []Theme
for _, theme := range themes {
if theme.HideFromThemes {
@@ -1358,9 +1364,9 @@ func route_panel_themes(w http.ResponseWriter, r *http.Request){
} else {
vThemeList = append(vThemeList,theme)
}
-
+
}
-
+
pi := ThemesPage{"Theme Manager",user,noticeList,pThemeList,vThemeList,nil}
err := templates.ExecuteTemplate(w,"panel-themes.html",pi)
if err != nil {
@@ -1381,7 +1387,7 @@ func route_panel_themes_default(w http.ResponseWriter, r *http.Request, uname st
SecurityError(w,r,user)
return
}
-
+
theme, ok := themes[uname]
if !ok {
LocalError("The theme isn't registered in the system",w,r,user)
@@ -1391,14 +1397,14 @@ func route_panel_themes_default(w http.ResponseWriter, r *http.Request, uname st
LocalError("You must not enable this theme",w,r,user)
return
}
-
+
var isDefault bool
err := db.QueryRow("select `default` from `themes` where `uname` = ?", uname).Scan(&isDefault)
if err != nil && err != sql.ErrNoRows {
InternalError(err,w,r)
return
}
-
+
has_theme := err != sql.ErrNoRows
if has_theme {
if isDefault {
@@ -1417,17 +1423,17 @@ func route_panel_themes_default(w http.ResponseWriter, r *http.Request, uname st
return
}
}
-
+
_, err = update_theme_stmt.Exec(0,defaultTheme)
if err != nil {
InternalError(err,w,r)
return
}
-
+
log.Print("Setting theme '" + theme.Name + "' as the default theme")
theme.Active = true
themes[uname] = theme
-
+
dTheme, ok := themes[defaultTheme]
if !ok {
InternalError(errors.New("The default theme is missing"),w,r)
@@ -1435,12 +1441,12 @@ func route_panel_themes_default(w http.ResponseWriter, r *http.Request, uname st
}
dTheme.Active = false
themes[defaultTheme] = dTheme
-
+
defaultTheme = uname
reset_template_overrides()
add_theme_static_files(uname)
map_theme_templates(theme)
-
+
http.Redirect(w,r,"/panel/themes/",http.StatusSeeOther)
}
@@ -1453,14 +1459,14 @@ func route_panel_logs_mod(w http.ResponseWriter, r *http.Request){
NoPermissions(w,r,user)
return
}
-
+
rows, err := db.Query("select action, elementID, elementType, ipaddress, actorID, doneAt from moderation_logs")
if err != nil {
InternalError(err,w,r)
return
}
defer rows.Close()
-
+
var logs []Log
var action, elementType, ipaddress, doneAt string
var elementID, actorID int
@@ -1470,12 +1476,12 @@ func route_panel_logs_mod(w http.ResponseWriter, r *http.Request){
InternalError(err,w,r)
return
}
-
+
actor, err := users.CascadeGet(actorID)
if err != nil {
actor = &User{Name:"Unknown"}
}
-
+
switch(action) {
case "lock":
topic, err := topics.CascadeGet(elementID)
@@ -1539,7 +1545,7 @@ func route_panel_logs_mod(w http.ResponseWriter, r *http.Request){
InternalError(err,w,r)
return
}
-
+
pi := LogsPage{"Moderation Logs",user,noticeList,logs,nil}
err = templates.ExecuteTemplate(w,"panel-modlogs.html",pi)
if err != nil {
diff --git a/permissions.go b/permissions.go
index 5b6c53d0..15922558 100644
--- a/permissions.go
+++ b/permissions.go
@@ -1,4 +1,5 @@
package main
+
import "log"
import "fmt"
import "sync"
@@ -78,7 +79,7 @@ type Perms struct
ManagePlugins bool
ViewAdminLogs bool
ViewIPs bool
-
+
// Forum permissions
ViewTopic bool
LikeItem bool
@@ -93,7 +94,7 @@ type Perms struct
PinTopic bool
CloseTopic bool
//CloseOwnTopic bool
-
+
ExtData interface{}
}
@@ -113,7 +114,7 @@ type ForumPerms struct
PinTopic bool
CloseTopic bool
//CloseOwnTopic bool
-
+
Overrides bool
ExtData map[string]bool
}
@@ -122,16 +123,16 @@ func init() {
BlankPerms = Perms{
ExtData: make(map[string]bool),
}
-
+
BlankForumPerms = ForumPerms{
ExtData: make(map[string]bool),
}
-
+
GuestPerms = Perms{
ViewTopic: true,
ExtData: make(map[string]bool),
}
-
+
AllPerms = Perms{
BanUsers: true,
ActivateUsers: true,
@@ -152,7 +153,7 @@ func init() {
ManagePlugins: true,
ViewAdminLogs: true,
ViewIPs: true,
-
+
ViewTopic: true,
LikeItem: true,
CreateTopic: true,
@@ -163,10 +164,10 @@ func init() {
DeleteReply: true,
PinTopic: true,
CloseTopic: true,
-
+
ExtData: make(map[string]bool),
}
-
+
AllForumPerms = ForumPerms{
ViewTopic: true,
LikeItem: true,
@@ -178,11 +179,11 @@ func init() {
DeleteReply: true,
PinTopic: true,
CloseTopic: true,
-
+
Overrides: true,
ExtData: make(map[string]bool),
}
-
+
ReadWriteForumPerms = ForumPerms{
ViewTopic: true,
LikeItem: true,
@@ -191,7 +192,7 @@ func init() {
Overrides: true,
ExtData: make(map[string]bool),
}
-
+
ReadReplyForumPerms = ForumPerms{
ViewTopic: true,
LikeItem: true,
@@ -199,15 +200,15 @@ func init() {
Overrides: true,
ExtData: make(map[string]bool),
}
-
+
ReadForumPerms = ForumPerms{
ViewTopic: true,
Overrides: true,
ExtData: make(map[string]bool),
}
-
+
guest_user.Perms = GuestPerms
-
+
if debug {
fmt.Printf("Guest Perms: ")
fmt.Printf("%+v\n", GuestPerms)
@@ -262,12 +263,12 @@ var permupdate_mutex sync.Mutex
func permmap_to_query(permmap map[string]ForumPerms, fid int) error {
permupdate_mutex.Lock()
defer permupdate_mutex.Unlock()
-
+
_, err := delete_forum_perms_by_forum_stmt.Exec(fid)
if err != nil {
return err
}
-
+
perms, err := json.Marshal(permmap["admins"])
if err != nil {
return err
@@ -276,7 +277,7 @@ func permmap_to_query(permmap map[string]ForumPerms, fid int) error {
if err != nil {
return err
}
-
+
perms, err = json.Marshal(permmap["staff"])
if err != nil {
return err
@@ -285,7 +286,7 @@ func permmap_to_query(permmap map[string]ForumPerms, fid int) error {
if err != nil {
return err
}
-
+
perms, err = json.Marshal(permmap["members"])
if err != nil {
return err
@@ -294,7 +295,7 @@ func permmap_to_query(permmap map[string]ForumPerms, fid int) error {
if err != nil {
return err
}
-
+
perms, err = json.Marshal(permmap["guests"])
if err != nil {
return err
@@ -303,7 +304,7 @@ func permmap_to_query(permmap map[string]ForumPerms, fid int) error {
if err != nil {
return err
}
-
+
return rebuild_forum_permissions(fid)
}
@@ -314,7 +315,7 @@ func rebuild_forum_permissions(fid int) error {
return err
}
defer rows.Close()
-
+
log.Print("Updating the forum permissions")
for rows.Next() {
var gid int
@@ -342,7 +343,7 @@ func rebuild_forum_permissions(fid int) error {
var blank_int_list []int
groups[gid].Forums = blank_list
groups[gid].CanSee = blank_int_list
-
+
for ffid, _ := range forums {
forum_perm, ok := forum_perms[gid][ffid]
if ok {
@@ -353,7 +354,7 @@ func rebuild_forum_permissions(fid int) error {
forum_perm = BlankForumPerms
groups[gid].Forums = append(groups[gid].Forums,forum_perm)
}
-
+
if forum_perm.Overrides {
if forum_perm.ViewTopic {
groups[gid].CanSee = append(groups[gid].CanSee, ffid)
@@ -375,7 +376,7 @@ func build_forum_permissions() error {
func strip_invalid_preset(preset string) string {
switch(preset) {
- case "all","announce","members","staff","admins","archive":
+ case "all","announce","members","staff","admins","archive","custom":
break
default: return ""
}
@@ -384,17 +385,18 @@ func strip_invalid_preset(preset string) string {
func preset_to_lang(preset string) string {
switch(preset) {
- case "all": return ""//return "Everyone"
+ case "all": return "Public"
case "announce": return "Announcements"
case "members": return "Member Only"
case "staff": return "Staff Only"
case "admins": return "Admin Only"
case "archive": return "Archive"
+ case "custom": return "Custom"
}
return ""
}
-func preset_to_emoji(preset string) string {
+/*func preset_to_emoji(preset string) string {
switch(preset) {
case "all": return ""//return "Everyone"
case "announce": return "📣"
@@ -404,7 +406,7 @@ func preset_to_emoji(preset string) string {
case "archive": return "☠️"
}
return ""
-}
+}*/
func rebuild_group_permissions(gid int) error {
var permstr []byte
@@ -413,13 +415,13 @@ func rebuild_group_permissions(gid int) error {
if err != nil {
return err
}
-
+
tmp_perms := Perms{ExtData: make(map[string]bool)}
err = json.Unmarshal(permstr, &tmp_perms)
if err != nil {
return err
}
-
+
groups[gid].Perms = tmp_perms
return nil
}
diff --git a/plugin_bbcode.go b/plugin_bbcode.go
index 3de421d2..5d5fe58b 100644
--- a/plugin_bbcode.go
+++ b/plugin_bbcode.go
@@ -172,6 +172,7 @@ func bbcode_parse_without_code(data interface{}) interface{} {
msg = bbcode_url_label.ReplaceAllString(msg,"$4")
msg = bbcode_quotes.ReplaceAllString(msg,"$1")
}
+
return string(msgbytes)
}
@@ -181,6 +182,7 @@ func bbcode_full_parse(data interface{}) interface{} {
//fmt.Println("BBCode PrePre String:")
//fmt.Println("`"+msg+"`")
//fmt.Println("----")
+
msgbytes := []byte(msg)
has_u := false
has_b := false
@@ -189,6 +191,7 @@ func bbcode_full_parse(data interface{}) interface{} {
has_c := false
complex_bbc := false
msgbytes = append(msgbytes,space_gap...)
+
//fmt.Println("BBCode Simple Pre:")
//fmt.Println("`"+string(msgbytes)+"`")
//fmt.Println("----")
@@ -272,8 +275,7 @@ func bbcode_full_parse(data interface{}) interface{} {
if complex_bbc {
i := 0
- var start int
- var lastTag int
+ var start, lastTag int
var outbytes []byte
//fmt.Println("BBCode Pre:")
//fmt.Println("`"+string(msgbytes)+"`")
@@ -366,5 +368,6 @@ func bbcode_full_parse(data interface{}) interface{} {
} else {
msg = string(msgbytes[0:len(msgbytes) - 10])
}
+
return msg
}
diff --git a/plugin_markdown.go b/plugin_markdown.go
index ff5d7bdd..9474e4c7 100644
--- a/plugin_markdown.go
+++ b/plugin_markdown.go
@@ -1,29 +1,373 @@
package main
+
+//import "fmt"
import "regexp"
+//import "strings"
+
+var markdown_max_depth int = 25 // How deep the parser will go when parsing Markdown strings
+var markdown_unclosed_element []byte
+
+var markdown_bold_tag_open []byte
+var markdown_bold_tag_close []byte
+var markdown_italic_tag_open []byte
+var markdown_italic_tag_close []byte
+var markdown_underline_tag_open []byte
+var markdown_underline_tag_close []byte
+var markdown_strike_tag_open []byte
+var markdown_strike_tag_close []byte
var markdown_bold_italic *regexp.Regexp
var markdown_bold *regexp.Regexp
var markdown_italic *regexp.Regexp
+var markdown_strike *regexp.Regexp
+var markdown_underline *regexp.Regexp
func init() {
plugins["markdown"] = NewPlugin("markdown","Markdown","Azareal","http://github.com/Azareal","","","",init_markdown,nil,deactivate_markdown)
}
func init_markdown() {
+ //plugins["markdown"].AddHook("parse_assign", markdown_regex_parse)
plugins["markdown"].AddHook("parse_assign", markdown_parse)
+
+ markdown_unclosed_element = []byte("[Unclosed Element]")
+
+ markdown_bold_tag_open = []byte("")
+ markdown_bold_tag_close = []byte("")
+ markdown_italic_tag_open = []byte("")
+ markdown_italic_tag_close = []byte("")
+ markdown_underline_tag_open = []byte("")
+ markdown_underline_tag_close = []byte("")
+ markdown_strike_tag_open = []byte("")
+ markdown_strike_tag_close = []byte("")
+
markdown_bold_italic = regexp.MustCompile(`\*\*\*(.*)\*\*\*`)
markdown_bold = regexp.MustCompile(`\*\*(.*)\*\*`)
markdown_italic = regexp.MustCompile(`\*(.*)\*`)
+ //markdown_strike = regexp.MustCompile(`\~\~(.*)\~\~`)
+ markdown_strike = regexp.MustCompile(`\~(.*)\~`)
+ //markdown_underline = regexp.MustCompile(`\_\_(.*)\_\_`)
+ markdown_underline = regexp.MustCompile(`\_(.*)\_`)
}
func deactivate_markdown() {
+ //plugins["markdown"].RemoveHook("parse_assign", markdown_regex_parse)
plugins["markdown"].RemoveHook("parse_assign", markdown_parse)
}
-func markdown_parse(data interface{}) interface{} {
+func markdown_regex_parse(data interface{}) interface{} {
msg := data.(string)
msg = markdown_bold_italic.ReplaceAllString(msg,"$1")
msg = markdown_bold.ReplaceAllString(msg,"$1")
msg = markdown_italic.ReplaceAllString(msg,"$1")
+ msg = markdown_strike.ReplaceAllString(msg,"$1")
+ msg = markdown_underline.ReplaceAllString(msg,"$1")
return msg
-}
\ No newline at end of file
+}
+
+
+// An adapter for the parser, so that the parser can call itself recursively.
+// This is less for the simple Markdown elements like bold and italics and more for the really complicated ones I plan on adding at some point.
+func markdown_parse(data interface{}) interface{} {
+ return _markdown_parse(data.(string) + " ",0)
+}
+
+// Under Construction!
+func _markdown_parse(msg string, n int) string {
+ if n > markdown_max_depth {
+ return "[Markdown Error: Overflowed the max depth of 20]"
+ }
+
+ var outbytes []byte
+ var lastElement int
+ //fmt.Println("enter message loop")
+ //fmt.Printf("Message: %v\n",strings.Replace(msg,"\r","\\r",-1))
+
+ for index := 0; index < len(msg); index++ {
+ /*//fmt.Println("--OUTER MARKDOWN LOOP START--")
+ //fmt.Println("index",index)
+ //fmt.Println("msg[index]",msg[index])
+ //fmt.Println("string(msg[index])",string(msg[index]))
+ //fmt.Println("--OUTER MARKDOWN LOOP END--")
+ //fmt.Println(" ")*/
+
+ switch(msg[index]) {
+ case '_':
+ var startIndex int = index
+ if (index + 1) >= len(msg) {
+ break
+ }
+
+ index++
+ index = markdown_skip_until_char(msg, index, '_')
+ if (index - (startIndex + 1)) < 2 || index >= len(msg) {
+ break
+ }
+
+ sIndex := startIndex + 1
+ lIndex := index
+ index++
+
+ outbytes = append(outbytes, msg[lastElement:startIndex]...)
+ outbytes = append(outbytes, markdown_underline_tag_open...)
+ outbytes = append(outbytes, msg[sIndex:lIndex]...)
+ outbytes = append(outbytes, markdown_underline_tag_close...)
+
+ lastElement = index
+ index--
+ case '~':
+ var startIndex int = index
+ if (index + 1) >= len(msg) {
+ break
+ }
+
+ index++
+ index = markdown_skip_until_char(msg, index, '~')
+ if (index - (startIndex + 1)) < 2 || index >= len(msg) {
+ break
+ }
+
+ sIndex := startIndex + 1
+ lIndex := index
+ index++
+
+ outbytes = append(outbytes, msg[lastElement:startIndex]...)
+ outbytes = append(outbytes, markdown_strike_tag_open...)
+ outbytes = append(outbytes, msg[sIndex:lIndex]...)
+ outbytes = append(outbytes, markdown_strike_tag_close...)
+
+ lastElement = index
+ index--
+ case '*':
+ //fmt.Println("------")
+ //fmt.Println("[]byte(msg):",[]byte(msg))
+ //fmt.Println("len(msg)",len(msg))
+ //fmt.Println("start index",index)
+ //fmt.Println("start msg[index]",msg[index])
+ //fmt.Println("start string(msg[index])",string(msg[index]))
+ //fmt.Println("start []byte(msg[:index])",[]byte(msg[:index]))
+
+ var startIndex int = index
+ var italic bool = true
+ var bold bool
+ if (index + 2) < len(msg) {
+ //fmt.Println("start index + 1",index + 1)
+ //fmt.Println("start msg[index]",msg[index + 1])
+ //fmt.Println("start string(msg[index])",string(msg[index + 1]))
+
+ if msg[index + 1] == '*' {
+ //fmt.Println("two asterisks")
+ bold = true
+ index++
+ if msg[index + 1] != '*' {
+ italic = false
+ } else {
+ //fmt.Println("three asterisks")
+ index++
+ }
+ }
+ }
+
+ //fmt.Println("lastElement",lastElement)
+ //fmt.Println("startIndex:",startIndex)
+ //fmt.Println("msg[startIndex]",msg[startIndex])
+ //fmt.Println("string(msg[startIndex])",string(msg[startIndex]))
+
+ //fmt.Println("preabrupt index",index)
+ //fmt.Println("preabrupt msg[index]",msg[index])
+ //fmt.Println("preabrupt string(msg[index])",string(msg[index]))
+ //fmt.Println("preabrupt []byte(msg[:index])",[]byte(msg[:index]))
+ //fmt.Println("preabrupt msg[:index]",msg[:index])
+
+ // Does the string terminate abruptly?
+ if (index + 1) >= len(msg) {
+ break
+ }
+
+ index++
+
+ //fmt.Println("preskip index",index)
+ //fmt.Println("preskip msg[index]",msg[index])
+ //fmt.Println("preskip string(msg[index])",string(msg[index]))
+
+ index = markdown_skip_until_asterisk(msg,index)
+
+ if index >= len(msg) {
+ break
+ }
+
+ //fmt.Println("index",index)
+ //fmt.Println("[]byte(msg[:index])",[]byte(msg[:index]))
+ //fmt.Println("msg[index]",msg[index])
+
+ sIndex := startIndex
+ lIndex := index
+ if bold && italic {
+ //fmt.Println("bold & italic final code")
+ if (index + 3) >= len(msg) {
+ //fmt.Println("unclosed markdown element @ exit element")
+ outbytes = append(outbytes, msg[lastElement:startIndex]...)
+ outbytes = append(outbytes, markdown_unclosed_element...)
+ lastElement = startIndex
+ break
+ }
+ index += 3
+ sIndex += 3
+ } else if bold {
+ //fmt.Println("bold final code")
+ if (index + 2) >= len(msg) {
+ //fmt.Println("true unclosed markdown element @ exit element")
+ outbytes = append(outbytes, msg[lastElement:startIndex]...)
+ outbytes = append(outbytes, markdown_unclosed_element...)
+ lastElement = startIndex
+ break
+ }
+ index += 2
+ sIndex += 2
+ } else {
+ //fmt.Println("italic final code")
+ if (index + 1) >= len(msg) {
+ //fmt.Println("true unclosed markdown element @ exit element")
+ outbytes = append(outbytes, msg[lastElement:startIndex]...)
+ outbytes = append(outbytes, markdown_unclosed_element...)
+ lastElement = startIndex
+ break
+ }
+ index++
+ sIndex++
+ }
+
+ //fmt.Println("sIndex",sIndex)
+ //fmt.Println("lIndex",lIndex)
+
+ if lIndex <= sIndex {
+ //fmt.Println("unclosed markdown element @ lIndex <= sIndex")
+ outbytes = append(outbytes, msg[lastElement:startIndex]...)
+ outbytes = append(outbytes, markdown_unclosed_element...)
+ lastElement = startIndex
+ break
+ }
+
+ if sIndex < 0 || lIndex < 0 {
+ //fmt.Println("unclosed markdown element @ sIndex < 0 || lIndex < 0")
+ outbytes = append(outbytes, msg[lastElement:startIndex]...)
+ outbytes = append(outbytes, markdown_unclosed_element...)
+ lastElement = startIndex
+ break
+ }
+
+ //fmt.Println("final sIndex",sIndex)
+ //fmt.Println("final lIndex",lIndex)
+ //fmt.Println("final index",index)
+ //fmt.Println("final msg[index]",msg[index])
+ //fmt.Println("final string(msg[index])",string(msg[index]))
+
+ //fmt.Println("final msg[sIndex]",msg[sIndex])
+ //fmt.Println("final string(msg[sIndex])",string(msg[sIndex]))
+ //fmt.Println("final msg[lIndex]",msg[lIndex])
+ //fmt.Println("final string(msg[lIndex])",string(msg[lIndex]))
+
+ //fmt.Println("[]byte(msg[:sIndex])",[]byte(msg[:sIndex]))
+ //fmt.Println("[]byte(msg[:lIndex])",[]byte(msg[:lIndex]))
+
+ outbytes = append(outbytes, msg[lastElement:startIndex]...)
+
+ if bold {
+ outbytes = append(outbytes, markdown_bold_tag_open...)
+ }
+ if italic {
+ outbytes = append(outbytes, markdown_italic_tag_open...)
+ }
+
+ outbytes = append(outbytes, msg[sIndex:lIndex]...)
+
+ if bold {
+ outbytes = append(outbytes, markdown_bold_tag_close...)
+ }
+ if italic {
+ outbytes = append(outbytes, markdown_italic_tag_close...)
+ }
+
+ lastElement = index
+ index--
+ //case '`':
+ //case '_':
+ //case '~':
+ //case 10: // newline
+ }
+ }
+
+ //fmt.Println("exit message loop")
+ //fmt.Println(" ")
+
+ if len(outbytes) == 0 {
+ return msg
+ } else if lastElement < (len(msg) - 1) {
+ return string(outbytes) + msg[lastElement:]
+ }
+ return string(outbytes)
+}
+
+func markdown_find_char(data string ,index int ,char byte) bool {
+ for ; index < len(data); index++ {
+ item := data[index]
+ if item > 32 {
+ return (item == char)
+ }
+ }
+ return false
+}
+
+func markdown_skip_until_char(data string, index int, char byte) int {
+ for ; index < len(data); index++ {
+ if data[index] == char {
+ break
+ }
+ }
+ return index
+}
+
+func markdown_skip_until_asterisk(data string, index int) int {
+SwitchLoop:
+ for ; index < len(data); index++ {
+ switch(data[index]) {
+ case 10:
+ if ((index+1) < len(data)) && markdown_find_char(data,index,'*') {
+ index = markdown_skip_list(data,index)
+ }
+ case '*': break SwitchLoop
+ }
+ }
+ return index
+}
+
+// plugin_markdown doesn't support lists yet, but I want it to be easy to have nested lists when we do have them
+func markdown_skip_list(data string, index int) int {
+ var lastNewline int
+ var datalen int = len(data)
+
+ for ; index < datalen; index++ {
+ SkipListInnerLoop:
+ if data[index] == 10 {
+ lastNewline = index
+ for ; index < datalen; index++ {
+ if data[index] > 32 {
+ break
+ } else if data[index] == 10 {
+ goto SkipListInnerLoop
+ }
+ }
+
+ if index >= datalen {
+ if data[index] != '*' && data[index] != '-' {
+ if (lastNewline + 1) < datalen {
+ return lastNewline + 1
+ }
+ return lastNewline
+ }
+ }
+ }
+ }
+
+ return index
+}
diff --git a/public/global.js b/public/global.js
index 2e60e0a2..def40bb7 100644
--- a/public/global.js
+++ b/public/global.js
@@ -21,12 +21,12 @@ function load_alerts(menu_alerts)
menu_alerts.find(".alertList").html("
");
-
+
$(".submit_edit").click(function(event)
{
event.preventDefault();
@@ -190,21 +184,21 @@ $(document).ready(function(){
var block = block_parent.find('.editable_block').eq(0);
var newContent = block.find('textarea').eq(0).val();
block.html(newContent);
-
+
var form_action = $(this).closest('a').attr("href");
//console.log("Form Action: " + form_action);
$.ajax({ url: form_action, type: "POST", dataType: "json", data: { is_js: "1", edit_item: newContent }
});
});
});
-
+
$(".edit_field").click(function(event)
{
event.preventDefault();
var block_parent = $(this).closest('.editable_parent');
var block = block_parent.find('.editable_block').eq(0);
block.html("");
-
+
$(".submit_edit").click(function(event)
{
event.preventDefault();
@@ -212,7 +206,7 @@ $(document).ready(function(){
var block = block_parent.find('.editable_block').eq(0);
var newContent = block.find('input').eq(0).val();
block.html(newContent);
-
+
var form_action = $(this).closest('a').attr("href");
//console.log("Form Action: " + form_action);
$.ajax({
@@ -223,25 +217,38 @@ $(document).ready(function(){
});
});
});
-
+
$(".edit_fields").click(function(event)
{
event.preventDefault();
+ //console.log("clicked .edit_fields");
var block_parent = $(this).closest('.editable_parent');
+ //console.log(block_parent);
block_parent.find('.hide_on_edit').hide();
block_parent.find('.editable_block').show();
block_parent.find('.editable_block').each(function(){
var field_name = this.getAttribute("data-field");
var field_type = this.getAttribute("data-type");
- if(field_type=="list") {
+ if(field_type=="list")
+ {
var field_value = this.getAttribute("data-value");
if(field_name in form_vars) var it = form_vars[field_name];
else var it = ['No','Yes'];
var itLen = it.length;
var out = "";
+ //console.log("Field Name '" + field_name + "'")
+ //console.log("Field Type",field_type)
+ //console.log("Field Value '" + field_value + "'")
for (var i = 0; i < itLen; i++){
- if(field_value==i) sel = "selected ";
- else sel = "";
+ //console.log("Field Possibility '" + it[i] + "'");
+ if(field_value == i || field_value == it[i]) {
+ sel = "selected ";
+ //console.log("Class List: ",this.classList)
+ this.classList.remove(field_name + '_' + it[i]);
+ //console.log("Removing " + field_name + '_' + it[i]);
+ //console.log(this.classList)
+ this.innerHTML = "";
+ } else sel = "";
out += "";
}
this.innerHTML = "";
@@ -249,22 +256,35 @@ $(document).ready(function(){
else this.innerHTML = "";
});
block_parent.find('.show_on_edit').eq(0).show();
-
+
+ // Remove any handlers already attached to the submitter
+ $(".submit_edit").unbind("click");
+
$(".submit_edit").click(function(event)
{
event.preventDefault();
+ //console.log("running .submit_edit event");
var out_data = {is_js: "1"}
var block_parent = $(this).closest('.editable_parent');
var block = block_parent.find('.editable_block').each(function(){
var field_name = this.getAttribute("data-field");
var field_type = this.getAttribute("data-type");
- if(field_type == "list") var newContent = $(this).find('select :selected').text();
- else var newContent = $(this).find('input').eq(0).val();
-
- this.innerHTML = newContent;
- out_data[field_name] = newContent
+ if(field_type == "list") {
+ var newContent = $(this).find('select :selected').text();
+ this.classList.add(field_name + '_' + newContent);
+ this.innerHTML = "";
+ } else {
+ var newContent = $(this).find('input').eq(0).val();
+ this.innerHTML = newContent;
+ }
+ //console.log(".submit_edit");
+ //console.log("field_name",field_name);
+ //console.log("field_type",field_type);
+ //console.log("newContent",newContent);
+ this.setAttribute("data-value",newContent);
+ out_data[field_name] = newContent;
});
-
+
var form_action = $(this).closest('a').attr("href");
//console.log("Form Action: " + form_action);
//console.log(out_data);
@@ -273,7 +293,7 @@ $(document).ready(function(){
block_parent.find('.show_on_edit').hide();
});
});
-
+
$(".ip_item").each(function(){
var ip = this.textContent;
//console.log("IP: " + ip);
@@ -285,24 +305,24 @@ $(document).ready(function(){
};
}
});
-
+
$(this).click(function() {
$(".selectedAlert").removeClass("selectedAlert");
});
-
+
$(".menu_alerts").ready(function(){
load_alerts($(this));
});
-
+
$(".menu_alerts").click(function(event) {
event.stopPropagation();
if($(this).hasClass("selectedAlert")) return;
this.className += " selectedAlert";
load_alerts($(this));
});
-
+
this.onkeyup = function(event){
if(event.which == 37) this.querySelectorAll("#prevFloat a")[0].click();
if(event.which == 39) this.querySelectorAll("#nextFloat a")[0].click();
};
-});
\ No newline at end of file
+});
diff --git a/router_gen/main.go b/router_gen/main.go
index 22228610..2633e283 100644
--- a/router_gen/main.go
+++ b/router_gen/main.go
@@ -1,4 +1,5 @@
/* WIP Under Construction */
+// The router generator might be discontinued in favour of syncmaps in Go 1.9, it will be temporarily used for a couple of months as a lockless alternative to maps
package main
import "log"
@@ -16,7 +17,7 @@ func main() {
routes()
var out string
- var fdata string = "// Code generated by. DO NOT EDIT.\n/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */\n"
+ var fdata string = "// Code generated by. DO NOT EDIT.\n/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */\n// The router generator might be discontinued in favour of syncmaps in Go 1.9, it will be temporarily used for a couple of months as a lockless alternative to maps\n"
for _, route := range route_list {
var end int
diff --git a/routes.go b/routes.go
index 8ab4b1de..46638483 100644
--- a/routes.go
+++ b/routes.go
@@ -34,7 +34,7 @@ func route_static(w http.ResponseWriter, r *http.Request){
w.WriteHeader(http.StatusNotFound)
return
}
-
+
// Surely, there's a more efficient way of doing this?
if t, err := time.Parse(http.TimeFormat, r.Header.Get("If-Modified-Since")); err == nil && file.Info.ModTime().Before(t.Add(1 * time.Second)) {
w.WriteHeader(http.StatusNotModified)
@@ -72,9 +72,9 @@ func route_overview(w http.ResponseWriter, r *http.Request){
}
pi := Page{"Overview",user,noticeList,tList,nil}
err := templates.ExecuteTemplate(w,"overview.html",pi)
- if err != nil {
- InternalError(err,w,r)
- }
+ if err != nil {
+ InternalError(err,w,r)
+ }
}
func route_custom_page(w http.ResponseWriter, r *http.Request){
@@ -87,19 +87,19 @@ func route_custom_page(w http.ResponseWriter, r *http.Request){
NotFound(w,r)
return
}
-
+
err := templates.ExecuteTemplate(w,"page_" + name,Page{"Page",user,noticeList,tList,nil})
if err != nil {
InternalError(err,w,r)
}
}
-
+
func route_topics(w http.ResponseWriter, r *http.Request){
user, noticeList, ok := SessionCheck(w,r)
if !ok {
return
}
-
+
var fidList []string
group := groups[user.Group]
for _, fid := range group.CanSee {
@@ -107,7 +107,7 @@ func route_topics(w http.ResponseWriter, r *http.Request){
fidList = append(fidList,strconv.Itoa(fid))
}
}
-
+
var topicList []TopicsRow
rows, err := db.Query("select topics.tid, topics.title, topics.content, topics.createdBy, topics.is_closed, topics.sticky, topics.createdAt, topics.lastReplyAt, topics.parentID, topics.likeCount, users.name, users.avatar from topics left join users ON topics.createdBy = users.uid where parentID in("+strings.Join(fidList,",")+") order by topics.sticky DESC, topics.lastReplyAt DESC, topics.createdBy DESC")
//rows, err := get_topic_list_stmt.Query()
@@ -115,7 +115,7 @@ func route_topics(w http.ResponseWriter, r *http.Request){
InternalError(err,w,r)
return
}
-
+
topicItem := TopicsRow{ID: 0}
for rows.Next() {
err := rows.Scan(&topicItem.ID, &topicItem.Title, &topicItem.Content, &topicItem.CreatedBy, &topicItem.Is_Closed, &topicItem.Sticky, &topicItem.CreatedAt, &topicItem.LastReplyAt, &topicItem.ParentID, &topicItem.LikeCount, &topicItem.CreatedByName, &topicItem.Avatar)
@@ -123,7 +123,7 @@ func route_topics(w http.ResponseWriter, r *http.Request){
InternalError(err,w,r)
return
}
-
+
if topicItem.Avatar != "" {
if topicItem.Avatar[0] == '.' {
topicItem.Avatar = "/uploads/avatar_" + strconv.Itoa(topicItem.CreatedBy) + topicItem.Avatar
@@ -131,13 +131,13 @@ func route_topics(w http.ResponseWriter, r *http.Request){
} else {
topicItem.Avatar = strings.Replace(noavatar,"{id}",strconv.Itoa(topicItem.CreatedBy),1)
}
-
+
if topicItem.ParentID >= 0 {
topicItem.ForumName = forums[topicItem.ParentID].Name
} else {
topicItem.ForumName = ""
}
-
+
/*topicItem.CreatedAt, err = relative_time(topicItem.CreatedAt)
if err != nil {
InternalError(err,w,r)
@@ -146,7 +146,7 @@ func route_topics(w http.ResponseWriter, r *http.Request){
if err != nil {
InternalError(err,w,r)
}
-
+
if hooks["trow_assign"] != nil {
topicItem = run_hook("trow_assign", topicItem).(TopicsRow)
}
@@ -158,7 +158,7 @@ func route_topics(w http.ResponseWriter, r *http.Request){
return
}
rows.Close()
-
+
pi := TopicsPage{"Topic List",user,noticeList,topicList,nil}
if template_topics_handle != nil {
template_topics_handle(pi,w)
@@ -177,7 +177,7 @@ func route_forum(w http.ResponseWriter, r *http.Request, sfid string){
PreError("The provided ForumID is not a valid number.",w,r)
return
}
-
+
user, noticeList, ok := ForumSessionCheck(w,r,fid)
if !ok {
return
@@ -187,7 +187,7 @@ func route_forum(w http.ResponseWriter, r *http.Request, sfid string){
NoPermissions(w,r,user)
return
}
-
+
// Calculate the offset
var offset int
last_page := int(forums[fid].TopicCount / items_per_page) + 1
@@ -204,7 +204,7 @@ func route_forum(w http.ResponseWriter, r *http.Request, sfid string){
InternalError(err,w,r)
return
}
-
+
var topicList []TopicUser
topicItem := TopicUser{ID: 0}
for rows.Next() {
@@ -213,7 +213,7 @@ func route_forum(w http.ResponseWriter, r *http.Request, sfid string){
InternalError(err,w,r)
return
}
-
+
if topicItem.Avatar != "" {
if topicItem.Avatar[0] == '.' {
topicItem.Avatar = "/uploads/avatar_" + strconv.Itoa(topicItem.CreatedBy) + topicItem.Avatar
@@ -221,12 +221,12 @@ func route_forum(w http.ResponseWriter, r *http.Request, sfid string){
} else {
topicItem.Avatar = strings.Replace(noavatar,"{id}",strconv.Itoa(topicItem.CreatedBy),1)
}
-
+
topicItem.LastReplyAt, err = relative_time(topicItem.LastReplyAt)
if err != nil {
InternalError(err,w,r)
}
-
+
if hooks["trow_assign"] != nil {
topicItem = run_hook("trow_assign", topicItem).(TopicUser)
}
@@ -238,7 +238,7 @@ func route_forum(w http.ResponseWriter, r *http.Request, sfid string){
return
}
rows.Close()
-
+
pi := ForumPage{forums[fid].Name,user,noticeList,topicList,forums[fid],page,last_page,nil}
if template_forum_handle != nil {
template_forum_handle(pi,w)
@@ -255,7 +255,7 @@ func route_forums(w http.ResponseWriter, r *http.Request){
if !ok {
return
}
-
+
var forumList []Forum
var err error
group := groups[user.Group]
@@ -276,7 +276,7 @@ func route_forums(w http.ResponseWriter, r *http.Request){
forumList = append(forumList, forum)
}
}
-
+
pi := ForumsPage{"Forum List",user,noticeList,forumList,nil}
if template_forums_handle != nil {
template_forums_handle(pi,w)
@@ -287,19 +287,19 @@ func route_forums(w http.ResponseWriter, r *http.Request){
}
}
}
-
+
func route_topic_id(w http.ResponseWriter, r *http.Request){
var err error
var page, offset int
var replyList []Reply
-
+
page, _ = strconv.Atoi(r.FormValue("page"))
tid, err := strconv.Atoi(r.URL.Path[len("/topic/"):])
if err != nil {
PreError("The provided TopicID is not a valid number.",w,r)
return
}
-
+
// Get the topic...
topic, err := get_topicuser(tid)
if err == sql.ErrNoRows {
@@ -310,7 +310,7 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
return
}
topic.Css = no_css_tmpl
-
+
user, noticeList, ok := ForumSessionCheck(w,r,topic.ParentID)
if !ok {
return
@@ -320,20 +320,20 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
NoPermissions(w,r,user)
return
}
-
+
topic.Content = parse_message(topic.Content)
topic.ContentLines = strings.Count(topic.Content,"\n")
-
+
// We don't want users posting in locked topics...
if topic.Is_Closed && !user.Is_Mod {
user.Perms.CreateReply = false
}
-
+
topic.Tag = groups[topic.Group].Tag
if groups[topic.Group].Is_Mod || groups[topic.Group].Is_Admin {
topic.Css = staff_css_tmpl
}
-
+
/*if settings["url_tags"] == false {
topic.URLName = ""
} else {
@@ -344,7 +344,7 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
topic.URL = topic.URL + topic.URLName
}
}*/
-
+
// Calculate the offset
last_page := int(topic.PostCount / items_per_page) + 1
if page > 1 {
@@ -355,7 +355,7 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
} else {
page = 1
}
-
+
// Get the replies..
rows, err := get_topic_replies_offset_stmt.Query(topic.ID, offset)
if err == sql.ErrNoRows {
@@ -365,7 +365,7 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
InternalError(err,w,r)
return
}
-
+
replyItem := Reply{Css: no_css_tmpl}
for rows.Next() {
err := rows.Scan(&replyItem.ID, &replyItem.Content, &replyItem.CreatedBy, &replyItem.CreatedAt, &replyItem.LastEdit, &replyItem.LastEditBy, &replyItem.Avatar, &replyItem.CreatedByName, &replyItem.Group, &replyItem.URLPrefix, &replyItem.URLName, &replyItem.Level, &replyItem.IpAddress, &replyItem.LikeCount, &replyItem.ActionType)
@@ -373,17 +373,17 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
InternalError(err,w,r)
return
}
-
+
replyItem.ParentID = topic.ID
replyItem.ContentHtml = parse_message(replyItem.Content)
replyItem.ContentLines = strings.Count(replyItem.Content,"\n")
-
+
if groups[replyItem.Group].Is_Mod || groups[replyItem.Group].Is_Admin {
replyItem.Css = staff_css_tmpl
} else {
replyItem.Css = no_css_tmpl
}
-
+
if replyItem.Avatar != "" {
if replyItem.Avatar[0] == '.' {
replyItem.Avatar = "/uploads/avatar_" + strconv.Itoa(replyItem.CreatedBy) + replyItem.Avatar
@@ -391,9 +391,9 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
} else {
replyItem.Avatar = strings.Replace(noavatar,"{id}",strconv.Itoa(replyItem.CreatedBy),1)
}
-
+
replyItem.Tag = groups[replyItem.Group].Tag
-
+
/*if settings["url_tags"] == false {
replyItem.URLName = ""
} else {
@@ -404,7 +404,7 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
replyItem.URL = replyItem.URL + replyItem.URLName
}
}*/
-
+
// We really shouldn't have inline HTML, we should do something about this...
if replyItem.ActionType != "" {
switch(replyItem.ActionType) {
@@ -426,7 +426,7 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
}
}
replyItem.Liked = false
-
+
if hooks["rrow_assign"] != nil {
replyItem = run_hook("rrow_assign", replyItem).(Reply)
}
@@ -438,7 +438,7 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
return
}
rows.Close()
-
+
tpage := TopicPage{topic.Title,user,noticeList,replyList,topic,page,last_page,nil}
if template_topic_handle != nil {
template_topic_handle(tpage,w)
@@ -455,19 +455,19 @@ func route_profile(w http.ResponseWriter, r *http.Request){
if !ok {
return
}
-
+
var err error
var replyContent, replyCreatedByName, replyCreatedAt, replyAvatar, replyTag string
var rid, replyCreatedBy, replyLastEdit, replyLastEditBy, replyLines, replyGroup int
var replyCss template.CSS
var replyList []Reply
-
+
pid, err := strconv.Atoi(r.URL.Path[len("/user/"):])
if err != nil {
LocalError("The provided User ID is not a valid number.",w,r,user)
return
}
-
+
var puser *User
if pid == user.ID {
user.Is_Mod = true
@@ -483,7 +483,7 @@ func route_profile(w http.ResponseWriter, r *http.Request){
return
}
}
-
+
// 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.group from users_replies left join users ON users_replies.createdBy = users.uid where users_replies.uid = ?", puser.ID)
if err != nil {
@@ -491,14 +491,14 @@ func route_profile(w http.ResponseWriter, r *http.Request){
return
}
defer rows.Close()
-
+
for rows.Next() {
err := rows.Scan(&rid, &replyContent, &replyCreatedBy, &replyCreatedAt, &replyLastEdit, &replyLastEditBy, &replyAvatar, &replyCreatedByName, &replyGroup)
if err != nil {
InternalError(err,w,r)
return
}
-
+
replyLines = strings.Count(replyContent,"\n")
if groups[replyGroup].Is_Mod || groups[replyGroup].Is_Admin {
replyCss = staff_css_tmpl
@@ -512,7 +512,7 @@ func route_profile(w http.ResponseWriter, r *http.Request){
} else {
replyAvatar = strings.Replace(noavatar,"{id}",strconv.Itoa(replyCreatedBy),1)
}
-
+
if groups[replyGroup].Tag != "" {
replyTag = groups[replyGroup].Tag
} else if puser.ID == replyCreatedBy {
@@ -520,10 +520,10 @@ func route_profile(w http.ResponseWriter, r *http.Request){
} else {
replyTag = ""
}
-
+
replyLiked := false
replyLikeCount := 0
-
+
replyList = append(replyList, Reply{rid,puser.ID,replyContent,parse_message(replyContent),replyCreatedBy,replyCreatedByName,replyGroup,replyCreatedAt,replyLastEdit,replyLastEditBy,replyAvatar,replyCss,replyLines,replyTag,"","","",0,"",replyLiked,replyLikeCount,"",""})
}
err = rows.Err()
@@ -531,7 +531,7 @@ func route_profile(w http.ResponseWriter, r *http.Request){
InternalError(err,w,r)
return
}
-
+
ppage := ProfilePage{puser.Name + "'s Profile",user,noticeList,replyList,*puser,false}
if template_profile_handle != nil {
template_profile_handle(ppage,w)
@@ -553,7 +553,7 @@ func route_topic_create(w http.ResponseWriter, r *http.Request, sfid string){
return
}
}
-
+
user, noticeList, ok := ForumSessionCheck(w,r,fid)
if !ok {
return
@@ -562,7 +562,7 @@ func route_topic_create(w http.ResponseWriter, r *http.Request, sfid string){
NoPermissions(w,r,user)
return
}
-
+
var forumList []Forum
group := groups[user.Group]
for _, fid := range group.CanSee {
@@ -570,7 +570,7 @@ func route_topic_create(w http.ResponseWriter, r *http.Request, sfid string){
forumList = append(forumList, forums[fid])
}
}
-
+
ctpage := CreateTopicPage{"Create Topic",user,noticeList,forumList,fid,nil}
if template_create_topic_handle != nil {
template_create_topic_handle(ctpage,w)
@@ -581,21 +581,21 @@ func route_topic_create(w http.ResponseWriter, r *http.Request, sfid string){
}
}
}
-
+
// POST functions. Authorised users only.
func route_create_topic(w http.ResponseWriter, r *http.Request) {
err := r.ParseForm()
if err != nil {
PreError("Bad Form",w,r)
- return
+ return
}
-
+
fid, err := strconv.Atoi(r.PostFormValue("topic-board"))
if err != nil {
PreError("The provided ForumID is not a valid number.",w,r)
return
}
-
+
user, ok := SimpleForumSessionCheck(w,r,fid)
if !ok {
return
@@ -604,7 +604,7 @@ func route_create_topic(w http.ResponseWriter, r *http.Request) {
NoPermissions(w,r,user)
return
}
-
+
topic_name := html.EscapeString(r.PostFormValue("topic-name"))
content := html.EscapeString(preparse_message(r.PostFormValue("topic-content")))
ipaddress, _, err := net.SplitHostPort(r.RemoteAddr)
@@ -612,7 +612,7 @@ func route_create_topic(w http.ResponseWriter, r *http.Request) {
LocalError("Bad IP",w,r,user)
return
}
-
+
wcount := word_count(content)
res, err := create_topic_stmt.Exec(fid,topic_name,content,parse_message(content),ipaddress,wcount,user.ID)
if err != nil {
@@ -624,14 +624,14 @@ func route_create_topic(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r)
return
}
-
+
_, err = add_topics_to_forum_stmt.Exec(1,fid)
if err != nil {
InternalError(err,w,r)
return
}
forums[fid].TopicCount -= 1
-
+
_, err = update_forum_cache_stmt.Exec(topic_name,lastId,user.Name,user.ID,fid)
if err != nil {
InternalError(err,w,r)
@@ -642,13 +642,13 @@ func route_create_topic(w http.ResponseWriter, r *http.Request) {
forums[fid].LastReplyer = user.Name
forums[fid].LastReplyerID = user.ID
forums[fid].LastTopicTime = ""
-
+
_, err = add_subscription_stmt.Exec(user.ID,lastId,"topic")
if err != nil {
InternalError(err,w,r)
return
}
-
+
http.Redirect(w,r,"/topic/" + strconv.FormatInt(lastId,10), http.StatusSeeOther)
err = increase_post_user_stats(wcount,user.ID,true,user)
if err != nil {
@@ -661,14 +661,14 @@ func route_create_reply(w http.ResponseWriter, r *http.Request) {
err := r.ParseForm()
if err != nil {
PreError("Bad Form",w,r)
- return
+ return
}
tid, err := strconv.Atoi(r.PostFormValue("tid"))
if err != nil {
PreError("Failed to convert the Topic ID",w,r)
return
}
-
+
var topic_name string
var fid int
var createdBy int
@@ -680,7 +680,7 @@ func route_create_reply(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r)
return
}
-
+
user, ok := SimpleForumSessionCheck(w,r,fid)
if !ok {
return
@@ -689,21 +689,21 @@ func route_create_reply(w http.ResponseWriter, r *http.Request) {
NoPermissions(w,r,user)
return
}
-
+
content := preparse_message(html.EscapeString(r.PostFormValue("reply-content")))
ipaddress, _, err := net.SplitHostPort(r.RemoteAddr)
if err != nil {
LocalError("Bad IP",w,r,user)
return
}
-
+
wcount := word_count(content)
_, err = create_reply_stmt.Exec(tid,content,parse_message(content),ipaddress,wcount, user.ID)
if err != nil {
InternalError(err,w,r)
return
}
-
+
_, err = add_replies_to_topic_stmt.Exec(1, tid)
if err != nil {
InternalError(err,w,r)
@@ -714,7 +714,7 @@ func route_create_reply(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r)
return
}
-
+
res, err := add_activity_stmt.Exec(user.ID,createdBy,"reply","topic",tid)
if err != nil {
InternalError(err,w,r)
@@ -725,13 +725,13 @@ func route_create_reply(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r)
return
}
-
+
_, err = notify_watchers_stmt.Exec(lastId)
if err != nil {
InternalError(err,w,r)
return
}
-
+
// Reload the topic...
err = topics.Load(tid)
if err != nil && err != sql.ErrNoRows {
@@ -741,7 +741,7 @@ func route_create_reply(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r)
return
}
-
+
http.Redirect(w,r,"/topic/" + strconv.Itoa(tid), http.StatusSeeOther)
err = increase_post_user_stats(wcount, user.ID, false, user)
if err != nil {
@@ -754,15 +754,15 @@ func route_like_topic(w http.ResponseWriter, r *http.Request) {
err := r.ParseForm()
if err != nil {
PreError("Bad Form",w,r)
- return
+ return
}
-
+
tid, err := strconv.Atoi(r.URL.Path[len("/topic/like/submit/"):])
if err != nil {
PreError("Topic IDs can only ever be numbers.",w,r)
return
}
-
+
var words int
var fid int
var createdBy int
@@ -774,7 +774,7 @@ func route_like_topic(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r)
return
}
-
+
user, ok := SimpleForumSessionCheck(w,r,fid)
if !ok {
return
@@ -783,7 +783,7 @@ func route_like_topic(w http.ResponseWriter, r *http.Request) {
NoPermissions(w,r,user)
return
}
-
+
err = db.QueryRow("select targetItem from likes where sentBy = ? and targetItem = ? and targetType = 'topics'", user.ID, tid).Scan(&tid)
if err != nil && err != sql.ErrNoRows {
InternalError(err,w,r)
@@ -792,7 +792,7 @@ func route_like_topic(w http.ResponseWriter, r *http.Request) {
LocalError("You already liked this!",w,r,user)
return
}
-
+
_, err = users.CascadeGet(createdBy)
if err != nil && err == sql.ErrNoRows {
LocalError("The target user doesn't exist",w,r,user)
@@ -801,7 +801,7 @@ func route_like_topic(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r)
return
}
-
+
//score := words_to_score(words,true)
score := 1
_, err = create_like_stmt.Exec(score,tid,"topics",user.ID)
@@ -809,13 +809,13 @@ func route_like_topic(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r)
return
}
-
+
_, err = add_likes_to_topic_stmt.Exec(1,tid)
if err != nil {
InternalError(err,w,r)
return
}
-
+
res, err := add_activity_stmt.Exec(user.ID,createdBy,"like","topic",tid)
if err != nil {
InternalError(err,w,r)
@@ -826,7 +826,7 @@ func route_like_topic(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r)
return
}
-
+
/*_, err = notify_watchers_stmt.Exec(lastId)
if err != nil {
InternalError(err,w,r)
@@ -837,7 +837,7 @@ func route_like_topic(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r)
return
}
-
+
// Reload the topic...
err = topics.Load(tid)
if err != nil && err != sql.ErrNoRows {
@@ -847,7 +847,7 @@ func route_like_topic(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r)
return
}
-
+
http.Redirect(w,r,"/topic/" + strconv.Itoa(tid),http.StatusSeeOther)
}
@@ -855,15 +855,15 @@ func route_reply_like_submit(w http.ResponseWriter, r *http.Request) {
err := r.ParseForm()
if err != nil {
PreError("Bad Form",w,r)
- return
+ return
}
-
+
rid, err := strconv.Atoi(r.URL.Path[len("/reply/like/submit/"):])
if err != nil {
PreError("The provided Reply ID is not a valid number.",w,r)
return
}
-
+
var tid int
var words int
var createdBy int
@@ -875,7 +875,7 @@ func route_reply_like_submit(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r)
return
}
-
+
var fid int
err = db.QueryRow("select parentID from topics where tid = ?", tid).Scan(&fid)
if err == sql.ErrNoRows {
@@ -885,7 +885,7 @@ func route_reply_like_submit(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r)
return
}
-
+
user, ok := SimpleForumSessionCheck(w,r,fid)
if !ok {
return
@@ -894,7 +894,7 @@ func route_reply_like_submit(w http.ResponseWriter, r *http.Request) {
NoPermissions(w,r,user)
return
}
-
+
err = db.QueryRow("select targetItem from likes where sentBy = ? and targetItem = ? and targetType = 'replies'", user.ID, rid).Scan(&rid)
if err != nil && err != sql.ErrNoRows {
InternalError(err,w,r)
@@ -903,7 +903,7 @@ func route_reply_like_submit(w http.ResponseWriter, r *http.Request) {
LocalError("You already liked this!",w,r,user)
return
}
-
+
_, err = users.CascadeGet(createdBy)
if err != nil && err != sql.ErrNoRows {
LocalError("The target user doesn't exist",w,r,user)
@@ -912,7 +912,7 @@ func route_reply_like_submit(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r)
return
}
-
+
//score := words_to_score(words,false)
score := 1
_, err = create_like_stmt.Exec(score,rid,"replies",user.ID)
@@ -920,13 +920,13 @@ func route_reply_like_submit(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r)
return
}
-
+
_, err = add_likes_to_reply_stmt.Exec(1,rid)
if err != nil {
InternalError(err,w,r)
return
}
-
+
res, err := add_activity_stmt.Exec(user.ID,createdBy,"like","post",rid)
if err != nil {
InternalError(err,w,r)
@@ -937,13 +937,13 @@ func route_reply_like_submit(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r)
return
}
-
+
_, err = notify_one_stmt.Exec(createdBy,lastId)
if err != nil {
InternalError(err,w,r)
return
}
-
+
http.Redirect(w,r,"/topic/" + strconv.Itoa(tid),http.StatusSeeOther)
}
@@ -956,24 +956,24 @@ func route_profile_reply_create(w http.ResponseWriter, r *http.Request) {
NoPermissions(w,r,user)
return
}
-
+
err := r.ParseForm()
if err != nil {
LocalError("Bad Form",w,r,user)
- return
+ return
}
uid, err := strconv.Atoi(r.PostFormValue("uid"))
if err != nil {
LocalError("Invalid UID",w,r,user)
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)
if err != nil {
InternalError(err,w,r)
return
}
-
+
var user_name string
err = db.QueryRow("select name from users where uid = ?", uid).Scan(&user_name)
if err == sql.ErrNoRows {
@@ -983,7 +983,7 @@ func route_profile_reply_create(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r)
return
}
-
+
http.Redirect(w, r, "/user/" + strconv.Itoa(uid), http.StatusSeeOther)
}
@@ -1000,7 +1000,7 @@ func route_report_submit(w http.ResponseWriter, r *http.Request, sitem_id string
Banned(w,r,user)
return
}
-
+
err := r.ParseForm()
if err != nil {
LocalError("Bad Form",w,r,user)
@@ -1010,15 +1010,15 @@ func route_report_submit(w http.ResponseWriter, r *http.Request, sitem_id string
SecurityError(w,r,user)
return
}
-
+
item_id, err := strconv.Atoi(sitem_id)
if err != nil {
LocalError("Bad ID",w,r,user)
return
}
-
+
item_type := r.FormValue("type")
-
+
var fid int = 1
var tid int
var title, content, data string
@@ -1031,7 +1031,7 @@ func route_report_submit(w http.ResponseWriter, r *http.Request, sitem_id string
InternalError(err,w,r)
return
}
-
+
err = db.QueryRow("select title, data from topics where tid = ?",tid).Scan(&title,&data)
if err == sql.ErrNoRows {
LocalError("We were unable to find the topic which the reported post is supposed to be in",w,r,user)
@@ -1050,7 +1050,7 @@ func route_report_submit(w http.ResponseWriter, r *http.Request, sitem_id string
InternalError(err,w,r)
return
}
-
+
err = db.QueryRow("select name from users where uid = ?", tid).Scan(&title)
if err == sql.ErrNoRows {
LocalError("We were unable to find the profile which the reported post is supposed to be on",w,r,user)
@@ -1077,16 +1077,16 @@ func route_report_submit(w http.ResponseWriter, r *http.Request, sitem_id string
}
// Don't try to guess the type
LocalError("Unknown type",w,r,user)
- return
+ return
}
-
+
var count int
rows, err := db.Query("select count(*) as count from topics where data = ? and data != '' and parentID = 1", item_type + "_" + strconv.Itoa(item_id))
if err != nil && err != sql.ErrNoRows {
InternalError(err,w,r)
return
}
-
+
for rows.Next() {
err = rows.Scan(&count)
if err != nil {
@@ -1098,20 +1098,20 @@ func route_report_submit(w http.ResponseWriter, r *http.Request, sitem_id string
LocalError("Someone has already reported this!",w,r,user)
return
}
-
+
title = "Report: " + title
res, err := create_report_stmt.Exec(title,content,parse_message(content),user.ID,item_type + "_" + strconv.Itoa(item_id))
if err != nil {
InternalError(err,w,r)
return
}
-
+
lastId, err := res.LastInsertId()
if err != nil {
InternalError(err,w,r)
return
}
-
+
_, err = add_topics_to_forum_stmt.Exec(1, fid)
if err != nil {
InternalError(err,w,r)
@@ -1122,7 +1122,7 @@ func route_report_submit(w http.ResponseWriter, r *http.Request, sitem_id string
InternalError(err,w,r)
return
}
-
+
http.Redirect(w,r,"/topic/" + strconv.FormatInt(lastId, 10), http.StatusSeeOther)
}
@@ -1148,19 +1148,19 @@ func route_account_own_edit_critical_submit(w http.ResponseWriter, r *http.Reque
LocalError("You need to login to edit your account.",w,r,user)
return
}
-
+
err := r.ParseForm()
if err != nil {
LocalError("Bad Form",w,r,user)
- return
+ return
}
-
+
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")
-
+
err = get_password_stmt.QueryRow(user.ID).Scan(&real_password, &salt)
if err == sql.ErrNoRows {
LocalError("Your account no longer exists.",w,r,user)
@@ -1169,7 +1169,7 @@ func route_account_own_edit_critical_submit(w http.ResponseWriter, r *http.Reque
InternalError(err,w,r)
return
}
-
+
current_password = current_password + salt
err = bcrypt.CompareHashAndPassword([]byte(real_password), []byte(current_password))
if err == bcrypt.ErrMismatchedHashAndPassword {
@@ -1184,14 +1184,14 @@ func route_account_own_edit_critical_submit(w http.ResponseWriter, r *http.Reque
return
}
SetPassword(user.ID, new_password)
-
+
// Log the user out as a safety precaution
_, err = logout_stmt.Exec(user.ID)
if err != nil {
InternalError(err,w,r)
return
}
-
+
noticeList = append(noticeList,"Your password was successfully updated")
pi := Page{"Edit Password",user,noticeList,tList,nil}
templates.ExecuteTemplate(w,"account-own-edit.html", pi)
@@ -1216,7 +1216,7 @@ func route_account_own_edit_avatar_submit(w http.ResponseWriter, r *http.Request
return
}
r.Body = http.MaxBytesReader(w, r.Body, int64(max_request_size))
-
+
user, noticeList, ok := SessionCheck(w,r)
if !ok {
return
@@ -1225,13 +1225,13 @@ func route_account_own_edit_avatar_submit(w http.ResponseWriter, r *http.Request
LocalError("You need to login to edit your account.",w,r,user)
return
}
-
+
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 {
@@ -1242,7 +1242,7 @@ func route_account_own_edit_avatar_submit(w http.ResponseWriter, r *http.Request
return
}
defer infile.Close()
-
+
// We don't want multiple files
if filename != "" {
if filename != hdr.Filename {
@@ -1253,7 +1253,7 @@ func route_account_own_edit_avatar_submit(w http.ResponseWriter, r *http.Request
} else {
filename = hdr.Filename
}
-
+
if ext == "" {
extarr := strings.Split(hdr.Filename,".")
if len(extarr) < 2 {
@@ -1261,7 +1261,7 @@ func route_account_own_edit_avatar_submit(w http.ResponseWriter, r *http.Request
return
}
ext = extarr[len(extarr) - 1]
-
+
reg, err := regexp.Compile("[^A-Za-z0-9]+")
if err != nil {
LocalError("Bad file extension", w, r, user)
@@ -1270,14 +1270,14 @@ func route_account_own_edit_avatar_submit(w http.ResponseWriter, r *http.Request
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)
@@ -1285,7 +1285,7 @@ func route_account_own_edit_avatar_submit(w http.ResponseWriter, r *http.Request
}
}
}
-
+
_, err = set_avatar_stmt.Exec("." + ext, strconv.Itoa(user.ID))
if err != nil {
InternalError(err,w,r)
@@ -1298,7 +1298,7 @@ func route_account_own_edit_avatar_submit(w http.ResponseWriter, r *http.Request
return
}
noticeList = append(noticeList, "Your avatar was successfully updated")
-
+
pi := Page{"Edit Avatar",user,noticeList,tList,nil}
templates.ExecuteTemplate(w,"account-own-edit-avatar.html", pi)
}
@@ -1328,23 +1328,23 @@ func route_account_own_edit_username_submit(w http.ResponseWriter, r *http.Reque
err := r.ParseForm()
if err != nil {
LocalError("Bad Form",w,r,user)
- return
+ return
}
-
+
new_username := html.EscapeString(r.PostFormValue("account-new-username"))
_, err = set_username_stmt.Exec(new_username, strconv.Itoa(user.ID))
if err != nil {
LocalError("Unable to change the username. Does someone else already have this name?",w,r,user)
return
}
-
+
user.Name = new_username
err = users.Load(user.ID)
if err != nil {
LocalError("Your account doesn't exist!",w,r,user)
return
}
-
+
noticeList = append(noticeList,"Your username was successfully updated")
pi := Page{"Edit Username",user,noticeList,tList,nil}
templates.ExecuteTemplate(w,"account-own-edit-username.html", pi)
@@ -1359,7 +1359,7 @@ func route_account_own_edit_email(w http.ResponseWriter, r *http.Request) {
LocalError("You need to login to edit your account.",w,r,user)
return
}
-
+
email := Email{UserID: user.ID}
var emailList []interface{}
rows, err := db.Query("select email, validated from emails where uid = ?", user.ID)
@@ -1367,13 +1367,13 @@ func route_account_own_edit_email(w http.ResponseWriter, r *http.Request) {
log.Fatal(err)
}
defer rows.Close()
-
+
for rows.Next() {
err := rows.Scan(&email.Email, &email.Validated)
if err != nil {
log.Fatal(err)
}
-
+
if email.Email == user.Email {
email.Primary = true
}
@@ -1383,7 +1383,7 @@ func route_account_own_edit_email(w http.ResponseWriter, r *http.Request) {
if err != nil {
log.Fatal(err)
}
-
+
// Was this site migrated from another forum software? Most of them don't have multiple emails for a single user. This also applies when the admin switches enable_emails on after having it off for a while
if len(emailList) == 0 {
email.Email = user.Email
@@ -1391,7 +1391,7 @@ func route_account_own_edit_email(w http.ResponseWriter, r *http.Request) {
email.Primary = true
emailList = append(emailList, email)
}
-
+
if !enable_emails {
noticeList = append(noticeList, "The email system has been turned off. All features involving sending emails have been disabled.")
}
@@ -1409,7 +1409,7 @@ func route_account_own_edit_email_token_submit(w http.ResponseWriter, r *http.Re
return
}
token := r.URL.Path[len("/user/edit/token/"):]
-
+
email := Email{UserID: user.ID}
targetEmail := Email{UserID: user.ID}
var emailList []interface{}
@@ -1419,14 +1419,14 @@ func route_account_own_edit_email_token_submit(w http.ResponseWriter, r *http.Re
return
}
defer rows.Close()
-
+
for rows.Next() {
err := rows.Scan(&email.Email, &email.Validated, &email.Token)
if err != nil {
InternalError(err,w,r)
return
}
-
+
if email.Email == user.Email {
email.Primary = true
}
@@ -1440,7 +1440,7 @@ func route_account_own_edit_email_token_submit(w http.ResponseWriter, r *http.Re
InternalError(err,w,r)
return
}
-
+
if len(emailList) == 0 {
LocalError("A verification email was never sent for you!",w,r,user)
return
@@ -1449,13 +1449,13 @@ func route_account_own_edit_email_token_submit(w http.ResponseWriter, r *http.Re
LocalError("That's not a valid token!",w,r,user)
return
}
-
+
_, err = verify_email_stmt.Exec(user.Email)
if err != nil {
InternalError(err,w,r)
return
}
-
+
// If Email Activation is on, then activate the account while we're here
if settings["activation_type"] == 2 {
_, err = activate_user_stmt.Exec(user.ID)
@@ -1464,7 +1464,7 @@ func route_account_own_edit_email_token_submit(w http.ResponseWriter, r *http.Re
return
}
}
-
+
if !enable_emails {
noticeList = append(noticeList,"The email system has been turned off. All features involving sending emails have been disabled.")
}
@@ -1482,13 +1482,13 @@ func route_logout(w http.ResponseWriter, r *http.Request) {
LocalError("You can't logout without logging in first.",w,r,user)
return
}
-
+
_, err := logout_stmt.Exec(user.ID)
if err != nil {
InternalError(err,w,r)
return
}
-
+
err = users.Load(user.ID)
if err != nil {
LocalError("Your account doesn't exist!",w,r,user)
@@ -1496,7 +1496,7 @@ func route_logout(w http.ResponseWriter, r *http.Request) {
}
http.Redirect(w,r, "/", http.StatusSeeOther)
}
-
+
func route_login(w http.ResponseWriter, r *http.Request) {
user, noticeList, ok := SessionCheck(w,r)
if !ok {
@@ -1522,16 +1522,16 @@ func route_login_submit(w http.ResponseWriter, r *http.Request) {
err := r.ParseForm()
if err != nil {
LocalError("Bad Form",w,r,user)
- return
+ return
}
-
+
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 {
LocalError("That username doesn't exist.",w,r,user)
@@ -1540,14 +1540,14 @@ func route_login_submit(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r)
return
}
-
+
// Emergency password reset mechanism..
if salt == "" {
if password != real_password {
LocalError("That's not the correct password.",w,r,user)
return
}
-
+
// Re-encrypt the password
SetPassword(uid, password)
} else { // Normal login..
@@ -1556,7 +1556,7 @@ func route_login_submit(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r)
return
}
-
+
err := bcrypt.CompareHashAndPassword([]byte(real_password), []byte(password))
if err == bcrypt.ErrMismatchedHashAndPassword {
LocalError("That's not the correct password.",w,r,user)
@@ -1566,19 +1566,19 @@ func route_login_submit(w http.ResponseWriter, r *http.Request) {
return
}
}
-
+
session, err = GenerateSafeString(sessionLength)
if err != nil {
InternalError(err,w,r)
return
}
-
+
_, err = update_session_stmt.Exec(session, uid)
if err != nil {
InternalError(err,w,r)
return
}
-
+
cookie := http.Cookie{Name: "uid",Value: strconv.Itoa(uid),Path: "/",MaxAge: year}
http.SetCookie(w,&cookie)
cookie = http.Cookie{Name: "session",Value: session,Path: "/",MaxAge: year}
@@ -1606,39 +1606,39 @@ func route_register_submit(w http.ResponseWriter, r *http.Request) {
err := r.ParseForm()
if err != nil {
LocalError("Bad Form",w,r,user)
- return
+ return
}
-
+
username := html.EscapeString(r.PostFormValue("username"))
if username == "" {
LocalError("You didn't put in a username.",w,r,user)
- return
+ return
}
email := html.EscapeString(r.PostFormValue("email"))
if email == "" {
LocalError("You didn't put in an email.",w,r,user)
- return
+ return
}
-
+
password := r.PostFormValue("password")
if password == "" {
LocalError("You didn't put in a password.",w,r,user)
- return
+ return
}
if password == "test" || password == "123456" || password == "123" || password == "password" {
LocalError("Your password is too weak.",w,r,user)
- return
+ return
}
-
+
confirm_password := r.PostFormValue("confirm_password")
log.Print("Registration Attempt! Username: " + username)
-
+
// Do the two inputted passwords match..?
if password != confirm_password {
LocalError("The two passwords don't match.",w,r,user)
return
}
-
+
// Is this username already taken..?
err = username_exists_stmt.QueryRow(username).Scan(&username)
if err != nil && err != sql.ErrNoRows {
@@ -1648,7 +1648,7 @@ func route_register_submit(w http.ResponseWriter, r *http.Request) {
LocalError("This username isn't available. Try another.",w,r,user)
return
}
-
+
salt, err := GenerateSafeString(saltLength)
if err != nil {
InternalError(err,w,r)
@@ -1659,14 +1659,14 @@ func route_register_submit(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r)
return
}
-
+
password = password + salt
hashed_password, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
InternalError(err,w,r)
return
}
-
+
var active int
var group int
switch settings["activation_type"] {
@@ -1676,7 +1676,7 @@ func route_register_submit(w http.ResponseWriter, r *http.Request) {
default: // Anything else. E.g. Admin Activation or Email Activation.
group = activation_group
}
-
+
res, err := register_stmt.Exec(username,email,string(hashed_password),salt,group,session,active)
if err != nil {
InternalError(err,w,r)
@@ -1687,7 +1687,7 @@ func route_register_submit(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r)
return
}
-
+
// Check if this user actually owns this email, if email activation is on, automatically flip their account to active when the email is validated. Validation is also useful for determining whether this user should receive any alerts, etc. via email
if enable_emails {
token, err := GenerateSafeString(80)
@@ -1700,13 +1700,13 @@ func route_register_submit(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r)
return
}
-
+
if !SendValidationEmail(username, email, token) {
LocalError("We were unable to send the email for you to confirm that this email address belongs to you. You may not have access to some functionality until you do so. Please ask an administrator for assistance.",w,r,user)
return
}
}
-
+
cookie := http.Cookie{Name: "uid",Value: strconv.FormatInt(lastId, 10),Path: "/",MaxAge: year}
http.SetCookie(w,&cookie)
cookie = http.Cookie{Name: "session",Value: session,Path: "/",MaxAge: year}
@@ -1728,18 +1728,18 @@ func route_api(w http.ResponseWriter, r *http.Request) {
PreErrorJSQ("Bad Form",w,r,is_js)
return
}
-
+
user, ok := SimpleSessionCheck(w,r)
if !ok {
return
}
-
+
action := r.FormValue("action")
if action != "get" && action != "set" {
PreErrorJSQ("Invalid Action",w,r,is_js)
return
}
-
+
module := r.FormValue("module")
switch(module) {
case "alerts": // A feed of events tailored for a specific user
@@ -1747,13 +1747,13 @@ func route_api(w http.ResponseWriter, r *http.Request) {
PreError("You can only fetch alerts in the JSON format!",w,r)
return
}
-
+
w.Header().Set("Content-Type","application/json")
if !user.Loggedin {
w.Write(phrase_login_alerts)
return
}
-
+
var msglist string
var asid int
var actor_id int
@@ -1763,26 +1763,26 @@ func route_api(w http.ResponseWriter, r *http.Request) {
var elementID int
//---
var targetUser *User
-
+
rows, err := get_activity_feed_by_watcher_stmt.Query(user.ID)
if err != nil {
InternalErrorJS(err,w,r)
return
}
-
+
for rows.Next() {
err = rows.Scan(&asid,&actor_id,&targetUser_id,&event,&elementType,&elementID)
if err != nil {
InternalErrorJS(err,w,r)
return
}
-
+
actor, err := users.CascadeGet(actor_id)
if err != nil {
LocalErrorJS("Unable to find the actor",w,r)
return
}
-
+
/*if elementType != "forum" {
targetUser, err = users.CascadeGet(targetUser_id)
if err != nil {
@@ -1790,12 +1790,12 @@ func route_api(w http.ResponseWriter, r *http.Request) {
return
}
}*/
-
+
if event == "friend_invite" {
msglist += `{"msg":"You received a friend invite from {0}","sub":["` + actor.Name + `"],"path":"\/user\/`+strconv.Itoa(actor.ID)+`","avatar":"`+strings.Replace(actor.Avatar,"/","\\/",-1)+`"},`
continue
}
-
+
/*
"You received a friend invite from {user}"
"{x}{mentioned you on}{user}{'s profile}"
@@ -1809,7 +1809,7 @@ func route_api(w http.ResponseWriter, r *http.Request) {
"{x}{replied to}{your topic}{topic}"
"{x}{created a new topic}{topic}"
*/
-
+
var act string
var post_act string
var url string
@@ -1840,7 +1840,7 @@ func route_api(w http.ResponseWriter, r *http.Request) {
}
url = build_topic_url(elementID)
area = topic.Title
-
+
if targetUser_id == user.ID {
post_act = " your topic"
}
@@ -1867,7 +1867,7 @@ func route_api(w http.ResponseWriter, r *http.Request) {
default:
LocalErrorJS("Invalid elementType",w,r)
}
-
+
switch(event) {
case "like":
if elementType == "user" {
@@ -1888,17 +1888,17 @@ func route_api(w http.ResponseWriter, r *http.Request) {
}
case "reply": act = "replied to"
}
-
+
msglist += `{"msg":"{0} ` + start_frag + act + post_act + ` {1}` + end_frag + `","sub":["` + actor.Name + `","` + area + `"],"path":"` + url + `","avatar":"` + actor.Avatar + `"},`
}
-
+
err = rows.Err()
if err != nil {
InternalErrorJS(err,w,r)
return
}
rows.Close()
-
+
if len(msglist) != 0 {
msglist = msglist[0:len(msglist)-1]
}
diff --git a/template_list.go b/template_list.go
index 5311b224..38e7be0e 100644
--- a/template_list.go
+++ b/template_list.go
@@ -60,10 +60,13 @@ var topic_2 []byte = []byte(`"><`)
var topic_3 []byte = []byte(`
-