Added the ability to compile templates down to Pure Go code.

I'm slowly rolling this feature out to the various routes and doing tests.

Added the notice system.
Added the "You are banned" notice.
Added the Sendmail experimental plugin for sending emails without needing a SMTP server.
Added the debug flag for tuning down the amount of noise in the console.
Converted a system notice over to the notice system.
Changed the Activation Function signature to allow it to return errors which abort the process of plugin activation.
Plugins can now set tags. These will be visible in the Plugin Manager at a later date to specify a small snippet of additional information.
Variadic hooks are now first class citizens of the Plugin API rather than just an experiment.
SessionCheck() and the new SimpleSessionCheck() can now halt further processing of a route.
Deleted plugins are no longer shown on the Plugin Manager.
The registration form no longer allows users with blank names, emails or passwords to register.
The registration form now blocks some extremely common passwords.
Added the new status CSS to the /forum/ route.
Simplified some of the range loops in the templates.
This commit is contained in:
Azareal 2016-12-16 10:37:42 +00:00
parent 086239f88c
commit 7b1f27bf41
27 changed files with 1702 additions and 204 deletions

View File

@ -15,6 +15,12 @@ var default_route = route_topics
var default_group = 3
var staff_css = " background-color: #ffeaff;"
var uncategorised_forum_visible = true
var enable_emails = false
var site_email = ""
var smtp_server = ""
var siteurl = "localhost:8080"
var noavatar = "https://api.adorable.io/avatars/285/{id}@" + siteurl + ".png"
var items_per_page = 50
// Developer flag
var debug = true

View File

@ -86,6 +86,7 @@ CREATE TABLE `settings`(
`name` varchar(200) not null,
`content` varchar(250) not null,
`type` varchar(50) not null,
`constraints` varchar(200) DEFAULT '' not null,
unique(`name`)
);

View File

@ -6,7 +6,7 @@ import "net/http"
func InternalError(err error, w http.ResponseWriter, r *http.Request, user User) {
log.Fatal(err)
pi := Page{"Internal Server Error","error",user,tList,"A problem has occured in the system."}
pi := Page{"Internal Server Error","error",user,nList,tList,"A problem has occured in the system."}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
errpage := b.String()
@ -18,7 +18,7 @@ func InternalErrorJSQ(err error, w http.ResponseWriter, r *http.Request, user Us
log.Fatal(err)
errmsg := "A problem has occured in the system."
if is_js == "0" {
pi := Page{"Internal Server Error","error",user,tList,errmsg}
pi := Page{"Internal Server Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
errpage := b.String()
@ -30,7 +30,7 @@ func InternalErrorJSQ(err error, w http.ResponseWriter, r *http.Request, user Us
}
func LocalError(errmsg string, w http.ResponseWriter, r *http.Request, user User) {
pi := Page{"Local Error","error",user,tList,errmsg}
pi := Page{"Local Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
errpage := b.String()
@ -39,7 +39,7 @@ func LocalError(errmsg string, w http.ResponseWriter, r *http.Request, user User
}
func LoginRequired(w http.ResponseWriter, r *http.Request, user User) {
pi := Page{"Local Error","error",user,tList,"You need to login to do that."}
pi := Page{"Local Error","error",user,nList,tList,"You need to login to do that."}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
@ -50,7 +50,7 @@ func LoginRequired(w http.ResponseWriter, r *http.Request, user User) {
func LocalErrorJSQ(errmsg string, w http.ResponseWriter, r *http.Request, user User, is_js string) {
if is_js == "0" {
pi := Page{"Local Error","error",user,tList,errmsg}
pi := Page{"Local Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
errpage := b.String()
@ -63,7 +63,7 @@ func LocalErrorJSQ(errmsg string, w http.ResponseWriter, r *http.Request, user U
func NoPermissions(w http.ResponseWriter, r *http.Request, user User) {
errmsg := "You don't have permission to do that."
pi := Page{"Local Error","error",user,tList,errmsg}
pi := Page{"Local Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
errpage := b.String()
@ -74,7 +74,7 @@ func NoPermissions(w http.ResponseWriter, r *http.Request, user User) {
func NoPermissionsJSQ(w http.ResponseWriter, r *http.Request, user User, is_js string) {
errmsg := "You don't have permission to do that."
if is_js == "0" {
pi := Page{"Local Error","error",user,tList,errmsg}
pi := Page{"Local Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
errpage := b.String()
@ -86,7 +86,7 @@ func NoPermissionsJSQ(w http.ResponseWriter, r *http.Request, user User, is_js s
}
func Banned(w http.ResponseWriter, r *http.Request, user User) {
pi := Page{"Banned","error",user,tList,"You have been banned from this site."}
pi := Page{"Banned","error",user,nList,tList,"You have been banned from this site."}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
errpage := b.String()
@ -96,7 +96,7 @@ func Banned(w http.ResponseWriter, r *http.Request, user User) {
func BannedJSQ(w http.ResponseWriter, r *http.Request, user User, is_js string) {
if is_js == "0" {
pi := Page{"Banned","error",user,tList,"You have been banned from this site."}
pi := Page{"Banned","error",user,nList,tList,"You have been banned from this site."}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
errpage := b.String()
@ -109,7 +109,7 @@ func BannedJSQ(w http.ResponseWriter, r *http.Request, user User, is_js string)
func LoginRequiredJSQ(w http.ResponseWriter, r *http.Request, user User, is_js string) {
if is_js == "0" {
pi := Page{"Local Error","error",user,tList,"You need to login to do that."}
pi := Page{"Local Error","error",user,nList,tList,"You need to login to do that."}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
errpage := b.String()
@ -122,7 +122,7 @@ func LoginRequiredJSQ(w http.ResponseWriter, r *http.Request, user User, is_js s
func SecurityError(w http.ResponseWriter, r *http.Request, user User) {
errmsg := "There was a security issue with your request."
pi := Page{"Security Error","error",user,tList,errmsg}
pi := Page{"Security Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
errpage := b.String()
@ -132,7 +132,7 @@ func SecurityError(w http.ResponseWriter, r *http.Request, user User) {
func NotFound(w http.ResponseWriter, r *http.Request, user User) {
errmsg := "The requested page doesn't exist."
pi := Page{"Not Found","error",user,tList,errmsg}
pi := Page{"Not Found","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
errpage := b.String()
@ -142,7 +142,7 @@ func NotFound(w http.ResponseWriter, r *http.Request, user User) {
func CustomErrorJSQ(errmsg string, errcode int, errtitle string, w http.ResponseWriter, r *http.Request, user User, is_js string) {
if is_js == "0" {
pi := Page{errtitle,"error",user,tList,errmsg}
pi := Page{errtitle,"error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
errpage := b.String()

View File

@ -0,0 +1,67 @@
package main
import "io"
import "os/exec"
import "errors"
import "runtime"
/*
Sending emails in a way you really shouldn't be sending them.
This method doesn't require a SMTP server, but has higher chances of an email being rejected or being seen as spam. Use at your own risk. Only for Linux as Windows doesn't have Sendmail.
*/
func init() {
plugins["sendmail"] = Plugin{"sendmail","Sendmail","Azareal","http://github.com/Azareal","",false,"Linux Only","",init_sendmail,activate_sendmail,deactivate_sendmail}
}
func init_sendmail() {
add_vhook("email_send_intercept", send_sendmail)
}
// Sendmail is only available on Linux
func activate_sendmail() error {
if !enable_emails {
return errors.New("You have emails disabled in your configuration file")
}
if runtime.GOOS != "linux" {
return errors.New("This plugin only supports Linux")
}
return nil
}
func deactivate_sendmail() {
remove_vhook("email_send_intercept")
}
func send_sendmail(data ...interface{}) interface{} {
to := data[0].(string)
subject := data[1].(string)
body := data[2].(string)
msg := "From: " + site_email + "\n"
msg += "To: " + to + "\n"
msg += "Subject: " + subject + "\n\n"
msg += body + "\n"
sendmail := exec.Command("/usr/sbin/sendmail","-t","-i")
stdin, err := sendmail.StdinPipe()
if err != nil {
return false // Possibly disable the plugin and show an error to the admin on the dashboard? Plugin log file?
}
err = sendmail.Start()
if err != nil {
return false
}
io.WriteString(stdin, msg)
err = stdin.Close()
if err != nil {
return false
}
err = sendmail.Wait()
if err != nil {
return false
}
return true
}

View File

@ -13,9 +13,10 @@ type Plugin struct
URL string
Settings string
Active bool
Tag string
Type string
Init func()
Activate func()
Activate func()error
Deactivate func()
}
@ -31,6 +32,18 @@ func run_hook(name string, data interface{}) interface{} {
return hooks[name](data)
}
func run_hook_v(name string, data ...interface{}) {
vhooks[name](data...)
func add_vhook(name string, handler func(...interface{}) interface{}) {
vhooks[name] = handler
}
func remove_vhook(name string) {
delete(vhooks, name)
}
func run_vhook(name string, data ...interface{}) interface{} {
return vhooks[name](data...)
}
func run_vhook_noreturn(name string, data ...interface{}) {
_ = vhooks[name](data...)
}

Binary file not shown.

BIN
images/custom-page.PNG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

47
main.go
View File

@ -23,7 +23,7 @@ const saltLength int = 32
const sessionLength int = 80
var templates = template.Must(template.ParseGlob("templates/*"))
var custom_pages = template.Must(template.ParseGlob("pages/*"))
//var custom_pages = template.Must(template.ParseGlob("pages/*"))
var no_css_tmpl = template.CSS("")
var staff_css_tmpl = template.CSS(staff_css)
var settings map[string]interface{} = make(map[string]interface{})
@ -31,9 +31,52 @@ var external_sites map[string]string = make(map[string]string)
var groups map[int]Group = make(map[int]Group)
var forums map[int]Forum = make(map[int]Forum)
var static_files map[string]SFile = make(map[string]SFile)
var ctemplates map[string]func(Page)string = make(map[string]func(Page)string)
func compile_templates() {
var c CTemplateSet
user := User{0,"",0,false,false,false,false,false,false,"",false,"","","","",""}
var noticeList map[int]string = make(map[int]string)
noticeList[0] = "test"
log.Print("Compiling the templates")
topic := TopicUser{0,"",template.HTML(""),0,false,false,"",0,"","","",no_css_tmpl,0,"","","",""}
var replyList map[int]interface{} = make(map[int]interface{})
replyList[0] = Reply{0,0,"",template.HTML(""),0,"","",0,0,"",no_css_tmpl,0,"","","",""}
var varList map[string]VarItem = make(map[string]VarItem)
varList["extra_data"] = VarItem{"extra_data","tmpl_topic_vars.Something.(TopicUser)","TopicUser"}
pi := Page{"Title","name",user,noticeList,replyList,topic}
topic_id := c.compile_template("topic.html","templates/","Page", pi, varList)
varList = make(map[string]VarItem)
varList["extra_data"] = VarItem{"extra_data","tmpl_profile_vars.Something.(User)","User"}
pi = Page{"Title","name",user,noticeList,replyList,user}
profile := c.compile_template("profile.html","templates/","Page", pi, varList)
log.Print("Writing the templates")
write_template("topic", topic_id)
write_template("profile", profile)
}
func write_template(name string, content string) {
f, err := os.Create("./template_" + name + ".go")
if err != nil {
log.Fatal(err)
}
_, err = f.WriteString(content)
if err != nil {
log.Fatal(err)
}
f.Sync()
f.Close()
}
func main(){
var err error
compile_templates()
init_database(err);
log.Print("Loading the static files.")
@ -60,7 +103,7 @@ func main(){
external_sites["YT"] = "https://www.youtube.com/"
hooks["trow_assign"] = nil
hooks["rrow_assign"] = nil
//fmt.Println(plugins)
templates.ParseGlob("pages/*")
for name, body := range plugins {
log.Print("Added plugin " + name)

View File

@ -10,7 +10,11 @@ import "database/sql"
import _ "github.com/go-sql-driver/mysql"
func route_edit_topic(w http.ResponseWriter, r *http.Request) {
user := SessionCheck(w,r)
user, ok := SimpleSessionCheck(w,r)
if !ok {
return
}
err := r.ParseForm()
if err != nil {
LocalError("Bad Form", w, r, user)
@ -62,7 +66,11 @@ func route_edit_topic(w http.ResponseWriter, r *http.Request) {
}
func route_delete_topic(w http.ResponseWriter, r *http.Request) {
user := SessionCheck(w,r)
user, ok := SimpleSessionCheck(w,r)
if !ok {
return
}
if !user.Is_Mod && !user.Is_Admin {
NoPermissions(w,r,user)
return
@ -88,13 +96,17 @@ func route_delete_topic(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r,user)
return
}
log.Print("The topic '" + strconv.Itoa(tid) + "' was deleted by User ID #" + strconv.Itoa(user.ID) + ".")
log.Print("The topic '" + strconv.Itoa(tid) + "' was deleted by User ID #" + strconv.Itoa(user.ID) + ".")
http.Redirect(w, r, "/", http.StatusSeeOther)
}
func route_stick_topic(w http.ResponseWriter, r *http.Request) {
user := SessionCheck(w,r)
user, ok := SimpleSessionCheck(w,r)
if !ok {
return
}
if !user.Is_Mod && !user.Is_Admin {
NoPermissions(w,r,user)
return
@ -116,7 +128,11 @@ func route_stick_topic(w http.ResponseWriter, r *http.Request) {
}
func route_unstick_topic(w http.ResponseWriter, r *http.Request) {
user := SessionCheck(w,r)
user, ok := SimpleSessionCheck(w,r)
if !ok {
return
}
if !user.Is_Mod && !user.Is_Admin {
NoPermissions(w,r,user)
return
@ -138,7 +154,11 @@ func route_unstick_topic(w http.ResponseWriter, r *http.Request) {
}
func route_reply_edit_submit(w http.ResponseWriter, r *http.Request) {
user := SessionCheck(w,r)
user, ok := SimpleSessionCheck(w,r)
if !ok {
return
}
err := r.ParseForm()
if err != nil {
LocalError("Bad Form", w, r, user)
@ -184,7 +204,11 @@ func route_reply_edit_submit(w http.ResponseWriter, r *http.Request) {
}
func route_reply_delete_submit(w http.ResponseWriter, r *http.Request) {
user := SessionCheck(w,r)
user, ok := SimpleSessionCheck(w,r)
if !ok {
return
}
err := r.ParseForm()
if err != nil {
LocalError("Bad Form", w, r, user)
@ -232,7 +256,11 @@ func route_reply_delete_submit(w http.ResponseWriter, r *http.Request) {
}
func route_profile_reply_edit_submit(w http.ResponseWriter, r *http.Request) {
user := SessionCheck(w,r)
user, ok := SimpleSessionCheck(w,r)
if !ok {
return
}
err := r.ParseForm()
if err != nil {
LocalError("Bad Form", w, r, user)
@ -278,7 +306,11 @@ func route_profile_reply_edit_submit(w http.ResponseWriter, r *http.Request) {
}
func route_profile_reply_delete_submit(w http.ResponseWriter, r *http.Request) {
user := SessionCheck(w,r)
user, ok := SimpleSessionCheck(w,r)
if !ok {
return
}
err := r.ParseForm()
if err != nil {
LocalError("Bad Form", w, r, user)
@ -326,7 +358,11 @@ func route_profile_reply_delete_submit(w http.ResponseWriter, r *http.Request) {
}
func route_ban(w http.ResponseWriter, r *http.Request) {
user := SessionCheck(w,r)
user, noticeList, ok := SessionCheck(w,r)
if !ok {
return
}
if !user.Is_Mod && !user.Is_Admin {
NoPermissions(w,r,user)
return
@ -351,12 +387,16 @@ func route_ban(w http.ResponseWriter, r *http.Request) {
confirm_msg := "Are you sure you want to ban '" + uname + "'?"
yousure := AreYouSure{"/users/ban/submit/" + strconv.Itoa(uid),confirm_msg}
pi := Page{"Ban User","ban-user",user,tList,yousure}
pi := Page{"Ban User","ban-user",user,noticeList,tList,yousure}
templates.ExecuteTemplate(w,"areyousure.html", pi)
}
func route_ban_submit(w http.ResponseWriter, r *http.Request) {
user := SessionCheck(w,r)
user, ok := SimpleSessionCheck(w,r)
if !ok {
return
}
if !user.Is_Mod && !user.Is_Admin {
NoPermissions(w,r,user)
return
@ -410,7 +450,11 @@ func route_ban_submit(w http.ResponseWriter, r *http.Request) {
}
func route_unban(w http.ResponseWriter, r *http.Request) {
user := SessionCheck(w,r)
user, ok := SimpleSessionCheck(w,r)
if !ok {
return
}
if !user.Is_Mod && !user.Is_Admin {
NoPermissions(w,r,user)
return
@ -447,7 +491,11 @@ func route_unban(w http.ResponseWriter, r *http.Request) {
}
func route_panel_forums(w http.ResponseWriter, r *http.Request){
user := SessionCheck(w,r)
user, noticeList, ok := SessionCheck(w,r)
if !ok {
return
}
if !user.Is_Admin {
NoPermissions(w,r,user)
return
@ -463,12 +511,16 @@ func route_panel_forums(w http.ResponseWriter, r *http.Request){
}
}
pi := Page{"Forum Manager","panel-forums",user,forumList,0}
pi := Page{"Forum Manager","panel-forums",user,noticeList,forumList,0}
templates.ExecuteTemplate(w,"panel-forums.html", pi)
}
func route_panel_forums_create_submit(w http.ResponseWriter, r *http.Request){
user := SessionCheck(w,r)
user, ok := SimpleSessionCheck(w,r)
if !ok {
return
}
if !user.Is_Admin {
NoPermissions(w,r,user)
return
@ -502,7 +554,11 @@ func route_panel_forums_create_submit(w http.ResponseWriter, r *http.Request){
}
func route_panel_forums_delete(w http.ResponseWriter, r *http.Request){
user := SessionCheck(w,r)
user, noticeList, ok := SessionCheck(w,r)
if !ok {
return
}
if !user.Is_Admin {
NoPermissions(w,r,user)
return
@ -517,7 +573,7 @@ func route_panel_forums_delete(w http.ResponseWriter, r *http.Request){
return
}
_, ok := forums[fid];
_, ok = forums[fid];
if !ok {
LocalError("The forum you're trying to delete doesn't exist.",w,r,user)
return
@ -526,12 +582,16 @@ func route_panel_forums_delete(w http.ResponseWriter, r *http.Request){
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","panel-forums-delete",user,tList,yousure}
pi := Page{"Delete Forum","panel-forums-delete",user,noticeList,tList,yousure}
templates.ExecuteTemplate(w,"areyousure.html", pi)
}
func route_panel_forums_delete_submit(w http.ResponseWriter, r *http.Request) {
user := SessionCheck(w,r)
user, ok := SimpleSessionCheck(w,r)
if !ok {
return
}
if !user.Is_Admin {
NoPermissions(w,r,user)
return
@ -547,7 +607,7 @@ func route_panel_forums_delete_submit(w http.ResponseWriter, r *http.Request) {
return
}
_, ok := forums[fid];
_, ok = forums[fid];
if !ok {
LocalError("The forum you're trying to delete doesn't exist.",w,r,user)
return
@ -565,7 +625,11 @@ func route_panel_forums_delete_submit(w http.ResponseWriter, r *http.Request) {
}
func route_panel_forums_edit_submit(w http.ResponseWriter, r *http.Request) {
user := SessionCheck(w,r)
user, ok := SimpleSessionCheck(w,r)
if !ok {
return
}
if !user.Is_Admin {
NoPermissions(w,r,user)
return
@ -607,7 +671,11 @@ func route_panel_forums_edit_submit(w http.ResponseWriter, r *http.Request) {
}
func route_panel_settings(w http.ResponseWriter, r *http.Request){
user := SessionCheck(w,r)
user, noticeList, ok := SessionCheck(w,r)
if !ok {
return
}
if !user.Is_Admin {
NoPermissions(w,r,user)
return
@ -618,12 +686,16 @@ func route_panel_settings(w http.ResponseWriter, r *http.Request){
settingList[name] = content
}
pi := Page{"Setting Manager","panel-settings",user,tList,settingList}
pi := Page{"Setting Manager","panel-settings",user, noticeList,tList,settingList}
templates.ExecuteTemplate(w,"panel-settings.html", pi)
}
func route_panel_setting(w http.ResponseWriter, r *http.Request){
user := SessionCheck(w,r)
user, noticeList, ok := SessionCheck(w,r)
if !ok {
return
}
if !user.Is_Admin {
NoPermissions(w,r,user)
return
@ -641,12 +713,16 @@ func route_panel_setting(w http.ResponseWriter, r *http.Request){
return
}
pi := Page{"Edit Setting","panel-setting",user,tList,setting}
pi := Page{"Edit Setting","panel-setting",user,noticeList,tList,setting}
templates.ExecuteTemplate(w,"panel-setting.html", pi)
}
func route_panel_setting_edit(w http.ResponseWriter, r *http.Request) {
user := SessionCheck(w,r)
user, ok := SimpleSessionCheck(w,r)
if !ok {
return
}
if !user.Is_Admin {
NoPermissions(w,r,user)
return
@ -698,7 +774,11 @@ func route_panel_setting_edit(w http.ResponseWriter, r *http.Request) {
}
func route_panel_plugins(w http.ResponseWriter, r *http.Request){
user := SessionCheck(w,r)
user, noticeList, ok := SessionCheck(w,r)
if !ok {
return
}
if !user.Is_Admin {
NoPermissions(w,r,user)
return
@ -712,12 +792,16 @@ func route_panel_plugins(w http.ResponseWriter, r *http.Request){
currentID++
}
pi := Page{"Plugin Manager","panel-plugins",user,pluginList,0}
pi := Page{"Plugin Manager","panel-plugins",user,noticeList,pluginList,0}
templates.ExecuteTemplate(w,"panel-plugins.html", pi)
}
func route_panel_plugins_activate(w http.ResponseWriter, r *http.Request){
user := SessionCheck(w,r)
user, ok := SimpleSessionCheck(w,r)
if !ok {
return
}
if !user.Is_Admin {
NoPermissions(w,r,user)
return
@ -737,6 +821,14 @@ func route_panel_plugins_activate(w http.ResponseWriter, r *http.Request){
return
}
if plugins[uname].Activate != nil {
err = plugins[uname].Activate()
if err != nil {
LocalError(err.Error(),w,r,user)
return
}
}
has_plugin := err != sql.ErrNoRows
if has_plugin {
if active {
@ -756,15 +848,19 @@ func route_panel_plugins_activate(w http.ResponseWriter, r *http.Request){
}
}
log.Print("Activating plugin '" + plugin.Name + "'")
plugin.Active = true
plugins[uname] = plugin
plugins[uname].Init()
http.Redirect(w,r,"/panel/plugins/",http.StatusSeeOther)
}
func route_panel_plugins_deactivate(w http.ResponseWriter, r *http.Request){
user := SessionCheck(w,r)
user, ok := SimpleSessionCheck(w,r)
if !ok {
return
}
if !user.Is_Admin {
NoPermissions(w,r,user)
return
@ -805,7 +901,11 @@ func route_panel_plugins_deactivate(w http.ResponseWriter, r *http.Request){
}
func route_panel_users(w http.ResponseWriter, r *http.Request){
user := SessionCheck(w,r)
user, noticeList, ok := SessionCheck(w,r)
if !ok {
return
}
if !user.Is_Admin {
NoPermissions(w,r,user)
return
@ -860,7 +960,7 @@ func route_panel_users(w http.ResponseWriter, r *http.Request){
return
}
pi := Page{"User Manager","panel-users",user,userList,0}
pi := Page{"User Manager","panel-users",user,noticeList,userList,0}
err = templates.ExecuteTemplate(w,"panel-users.html", pi)
if err != nil {
InternalError(err, w, r, user)

View File

@ -166,7 +166,7 @@ func init_database(err error) {
// create_account_stmt, err = db.Prepare("INSERT INTO
log.Print("Preparing register statement.")
register_stmt, err = db.Prepare("INSERT INTO users(`name`,`password`,`salt`,`group`,`is_super_admin`,`session`,`message`) VALUES(?,?,?," + strconv.Itoa(default_group) + ",0,?,'')")
register_stmt, err = db.Prepare("INSERT INTO users(`name`,`email`,`password`,`salt`,`group`,`is_super_admin`,`session`,`message`) VALUES(?,?,?,?," + strconv.Itoa(default_group) + ",0,?,'')")
if err != nil {
log.Fatal(err)
}
@ -332,7 +332,13 @@ func init_database(err error) {
if err != nil {
log.Fatal(err)
}
plugin := plugins[uname]
// Was the plugin deleted at some point?
plugin, ok := plugins[uname]
if !ok {
continue
}
plugin.Active = active
plugins[uname] = plugin
}

View File

@ -7,6 +7,7 @@ type Page struct
Title string
Name string
CurrentUser User
NoticeList map[int]string
ItemList map[int]interface{}
Something interface{}
}

8
pages/page_test.html Normal file
View File

@ -0,0 +1,8 @@
{{template "header.html" . }}
<div class="rowblock">
<div class="rowitem">Test Page</div>
</div>
<div class="rowblock">
<div class="rowitem passive">Testing</div>
</div>
{{template "footer.html" . }}

View File

@ -1,6 +0,0 @@
{{template "header.html" . }}
<div class="rowblock">
<div class="rowitem">{{.Title}}</div>
</div>
<div class="rowblock">Testing</div>
{{template "footer.html" . }}

View File

@ -2,7 +2,7 @@ package main
import "html/template"
func init() {
plugins["helloworld"] = Plugin{"helloworld","Hello World","Azareal","http://github.com/Azareal","",false,"",init_helloworld,nil,deactivate_helloworld}
plugins["helloworld"] = Plugin{"helloworld","Hello World","Azareal","http://github.com/Azareal","",false,"","",init_helloworld,nil,deactivate_helloworld}
}
// init_helloworld is separate from init() as we don't want the plugin to run if the plugin is disabled

View File

@ -7,7 +7,7 @@ var bold *regexp.Regexp
var italic *regexp.Regexp
func init() {
plugins["markdown"] = Plugin{"markdown","Markdown","Azareal","http://github.com/Azareal","",false,"",init_markdown,nil,deactivate_markdown}
plugins["markdown"] = Plugin{"markdown","Markdown","Azareal","http://github.com/Azareal","",false,"","",init_markdown,nil,deactivate_markdown}
}
func init_markdown() {

View File

@ -14,6 +14,8 @@ func init() {
The Active field should always be set to false in the init() function of a plugin. It's used internally by the software to determine whether an admin has enabled a plugin or not and whether to run it. This will be overwritten by the user's preference.
The Tag field is for providing a tiny snippet of information separate from the description.
The Type field is for the type of the plugin. This gets changed to "go" automatically and we would suggest leaving "".
The Init field is for the initialisation handler which is called by the software to run this plugin. This expects a function. You should add your hooks, init logic, initial queries, etc. in said function.
@ -22,9 +24,12 @@ func init() {
The Deactivate field is for the handler which is called by the software when the admin hits the Deactivate button in the control panel. You should clean-up any resources you have allocated, remove any hooks, close any statements, etc. within this handler.
*/
plugins["skeleton"] = Plugin{"skeleton","Skeleton","Azareal","","",false,"",init_skeleton, activate_skeleton, deactivate_skeleton}
plugins["skeleton"] = Plugin{"skeleton","Skeleton","Azareal","","",false,"","",init_skeleton, activate_skeleton, deactivate_skeleton}
}
func init_skeleton() {}
func activate_skeleton() {}
/* Any errors encountered while trying to activate the plugin are reported back to the admin and the activation is aborted */
func activate_skeleton() error { return nil; }
func deactivate_skeleton() {}

257
routes.go
View File

@ -20,6 +20,7 @@ import "golang.org/x/crypto/bcrypt"
// A blank list to fill out that parameter in Page for routes which don't use it
var tList map[int]interface{}
var nList map[int]string
// GET functions
func route_static(w http.ResponseWriter, r *http.Request){
@ -43,8 +44,12 @@ func route_fstatic(w http.ResponseWriter, r *http.Request){
}
func route_overview(w http.ResponseWriter, r *http.Request){
user := SessionCheck(w,r)
pi := Page{"Overview","overview",user,tList,0}
user, noticeList, ok := SessionCheck(w,r)
if !ok {
return
}
pi := Page{"Overview","overview",user,noticeList,tList,0}
err := templates.ExecuteTemplate(w,"overview.html", pi)
if err != nil {
InternalError(err, w, r, user)
@ -52,21 +57,28 @@ func route_overview(w http.ResponseWriter, r *http.Request){
}
func route_custom_page(w http.ResponseWriter, r *http.Request){
user := SessionCheck(w,r)
user, noticeList, ok := SessionCheck(w,r)
if !ok {
return
}
name := r.URL.Path[len("/pages/"):]
if custom_pages.Lookup(name) == nil {
if templates.Lookup("page_" + name) == nil {
NotFound(w,r,user)
}
pi := Page{"Page","page",user,tList,0}
err := custom_pages.ExecuteTemplate(w,name,pi)
pi := Page{"Page","page",user,noticeList,tList,0}
err := templates.ExecuteTemplate(w,"page_" + name,pi)
if err != nil {
InternalError(err, w, r, user)
}
}
func route_topics(w http.ResponseWriter, r *http.Request){
user := SessionCheck(w,r)
user, noticeList, ok := SessionCheck(w,r)
if !ok {
return
}
var(
topicList map[int]interface{}
currentID int
@ -133,7 +145,7 @@ func route_topics(w http.ResponseWriter, r *http.Request){
msg = ""
}
pi := Page{"Topic List","topics",user,topicList,msg}
pi := Page{"Topic List","topics",user,noticeList,topicList,msg}
err = templates.ExecuteTemplate(w,"topics.html", pi)
if err != nil {
InternalError(err, w, r, user)
@ -141,7 +153,11 @@ func route_topics(w http.ResponseWriter, r *http.Request){
}
func route_forum(w http.ResponseWriter, r *http.Request){
user := SessionCheck(w,r)
user, noticeList, ok := SessionCheck(w,r)
if !ok {
return
}
var(
topicList map[int]interface{}
currentID int
@ -167,7 +183,7 @@ func route_forum(w http.ResponseWriter, r *http.Request){
return
}
_, ok := forums[fid]
_, ok = forums[fid]
if !ok {
NotFound(w,r,user)
return
@ -220,7 +236,7 @@ func route_forum(w http.ResponseWriter, r *http.Request){
msg = ""
}
pi := Page{forums[fid].Name,"forum",user,topicList,msg}
pi := Page{forums[fid].Name,"forum",user,noticeList,topicList,msg}
err = templates.ExecuteTemplate(w,"forum.html", pi)
if err != nil {
InternalError(err, w, r, user)
@ -228,7 +244,11 @@ func route_forum(w http.ResponseWriter, r *http.Request){
}
func route_forums(w http.ResponseWriter, r *http.Request){
user := SessionCheck(w,r)
user, noticeList, ok := SessionCheck(w,r)
if !ok {
return
}
var forumList map[int]interface{} = make(map[int]interface{})
currentID := 0
@ -244,7 +264,7 @@ func route_forums(w http.ResponseWriter, r *http.Request){
return
}
pi := Page{"Forum List","forums",user,forumList,0}
pi := Page{"Forum List","forums",user,noticeList,forumList,0}
err := templates.ExecuteTemplate(w,"forums.html", pi)
if err != nil {
InternalError(err, w, r, user)
@ -252,10 +272,13 @@ func route_forums(w http.ResponseWriter, r *http.Request){
}
func route_topic_id(w http.ResponseWriter, r *http.Request){
user := SessionCheck(w,r)
user, noticeList, ok := SessionCheck(w,r)
if !ok {
return
}
var(
err error
ok bool
rid int
content string
replyContent string
@ -388,15 +411,23 @@ func route_topic_id(w http.ResponseWriter, r *http.Request){
return
}
pi := Page{topic.Title,"topic",user,replyList,topic}
pi := Page{topic.Title,"topic",user,noticeList,replyList,topic}
if ctemplates["topic"] != nil {
w.Write([]byte(ctemplates["topic"](pi)))
} else {
err = templates.ExecuteTemplate(w,"topic.html", pi)
if err != nil {
InternalError(err, w, r, user)
}
}
}
func route_profile(w http.ResponseWriter, r *http.Request){
user := SessionCheck(w,r)
user, noticeList, ok := SessionCheck(w,r)
if !ok {
return
}
var(
err error
rid int
@ -508,7 +539,8 @@ func route_profile(w http.ResponseWriter, r *http.Request){
return
}
pi := Page{puser.Name + "'s Profile","profile",user,replyList,puser}
pi := Page{puser.Name + "'s Profile","profile",user,noticeList,replyList,puser}
//w.Write([]byte(template_profile(pi)))
err = templates.ExecuteTemplate(w,"profile.html", pi)
if err != nil {
InternalError(err, w, r, user)
@ -516,19 +548,27 @@ func route_profile(w http.ResponseWriter, r *http.Request){
}
func route_topic_create(w http.ResponseWriter, r *http.Request){
user := SessionCheck(w,r)
user, noticeList, ok := SessionCheck(w,r)
if !ok {
return
}
if user.Is_Banned {
Banned(w,r,user)
return
}
pi := Page{"Create Topic","create-topic",user,tList,0}
pi := Page{"Create Topic","create-topic",user,noticeList,tList,0}
templates.ExecuteTemplate(w,"create-topic.html", pi)
}
// POST functions. Authorised users only.
func route_create_topic(w http.ResponseWriter, r *http.Request) {
user := SessionCheck(w,r)
user, ok := SimpleSessionCheck(w,r)
if !ok {
return
}
if !user.Loggedin {
LoginRequired(w,r,user)
return
@ -566,7 +606,7 @@ func route_create_topic(w http.ResponseWriter, r *http.Request) {
if success != 1 {
errmsg := "Unable to create the topic"
pi := Page{"Error","error",user,tList,errmsg}
pi := Page{"Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
@ -579,7 +619,11 @@ func route_create_topic(w http.ResponseWriter, r *http.Request) {
}
func route_create_reply(w http.ResponseWriter, r *http.Request) {
user := SessionCheck(w,r)
user, ok := SimpleSessionCheck(w,r)
if !ok {
return
}
if !user.Loggedin {
LoginRequired(w,r,user)
return
@ -602,7 +646,7 @@ func route_create_reply(w http.ResponseWriter, r *http.Request) {
success = 0
errmsg := "Unable to create the reply"
pi := Page{"Error","error",user,tList,errmsg}
pi := Page{"Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
@ -638,7 +682,7 @@ func route_create_reply(w http.ResponseWriter, r *http.Request) {
if success != 1 {
errmsg := "Unable to create the reply"
pi := Page{"Error","error",user,tList,errmsg}
pi := Page{"Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
@ -651,7 +695,11 @@ func route_create_reply(w http.ResponseWriter, r *http.Request) {
}
func route_profile_reply_create(w http.ResponseWriter, r *http.Request) {
user := SessionCheck(w,r)
user, ok := SimpleSessionCheck(w,r)
if !ok {
return
}
if !user.Loggedin {
LoginRequired(w,r,user)
return
@ -674,7 +722,7 @@ func route_profile_reply_create(w http.ResponseWriter, r *http.Request) {
success = 0
errmsg := "Unable to create the reply"
pi := Page{"Error","error",user,tList,errmsg}
pi := Page{"Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
@ -702,7 +750,7 @@ func route_profile_reply_create(w http.ResponseWriter, r *http.Request) {
if success != 1 {
errmsg := "Unable to create the reply"
pi := Page{"Error","error",user,tList,errmsg}
pi := Page{"Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
@ -715,7 +763,11 @@ func route_profile_reply_create(w http.ResponseWriter, r *http.Request) {
}
func route_report_submit(w http.ResponseWriter, r *http.Request) {
user := SessionCheck(w,r)
user, ok := SimpleSessionCheck(w,r)
if !ok {
return
}
if !user.Loggedin {
LoginRequired(w,r,user)
return
@ -798,7 +850,7 @@ func route_report_submit(w http.ResponseWriter, r *http.Request) {
content = content + "<br><br>Original Post: <a href='/topic/" + strconv.Itoa(item_id) + "'>" + title + "</a>"
} else {
if vhooks["report_preassign"] != nil {
run_hook_v("report_preassign", &item_id, &item_type)
run_vhook_noreturn("report_preassign", &item_id, &item_type)
return
}
@ -813,6 +865,7 @@ func route_report_submit(w http.ResponseWriter, r *http.Request) {
InternalError(err,w,r,user)
return
}
for rows.Next() {
err = rows.Scan(&count)
if err != nil {
@ -820,7 +873,6 @@ func route_report_submit(w http.ResponseWriter, r *http.Request) {
return
}
}
if count != 0 {
LocalError("Someone has already reported this!", w, r, user)
return
@ -847,7 +899,7 @@ func route_report_submit(w http.ResponseWriter, r *http.Request) {
if success != 1 {
errmsg := "Unable to create the report"
pi := Page{"Error","error",user,tList,errmsg}
pi := Page{"Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
@ -860,10 +912,14 @@ func route_report_submit(w http.ResponseWriter, r *http.Request) {
}
func route_account_own_edit_critical(w http.ResponseWriter, r *http.Request) {
user := SessionCheck(w,r)
user, noticeList, ok := SessionCheck(w,r)
if !ok {
return
}
if !user.Loggedin {
errmsg := "You need to login to edit your own account."
pi := Page{"Error","error",user,tList,errmsg}
pi := Page{"Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
@ -873,15 +929,19 @@ func route_account_own_edit_critical(w http.ResponseWriter, r *http.Request) {
return
}
pi := Page{"Edit Password","account-own-edit",user,tList,0}
pi := Page{"Edit Password","account-own-edit",user,noticeList,tList,0}
templates.ExecuteTemplate(w,"account-own-edit.html", pi)
}
func route_account_own_edit_critical_submit(w http.ResponseWriter, r *http.Request) {
user := SessionCheck(w,r)
user, noticeList, ok := SessionCheck(w,r)
if !ok {
return
}
if !user.Loggedin {
errmsg := "You need to login to edit your own account."
pi := Page{"Error","error",user,tList,errmsg}
pi := Page{"Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
@ -905,7 +965,7 @@ func route_account_own_edit_critical_submit(w http.ResponseWriter, r *http.Reque
err = get_password_stmt.QueryRow(user.ID).Scan(&real_password, &salt)
if err == sql.ErrNoRows {
pi := Page{"Error","error",user,tList,"Your account doesn't exist."}
pi := Page{"Error","error",user,nList,tList,"Your account doesn't exist."}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
@ -921,7 +981,7 @@ func route_account_own_edit_critical_submit(w http.ResponseWriter, r *http.Reque
current_password = current_password + salt
err = bcrypt.CompareHashAndPassword([]byte(real_password), []byte(current_password))
if err == bcrypt.ErrMismatchedHashAndPassword {
pi := Page{"Error","error",user,tList,"That's not the correct password."}
pi := Page{"Error","error",user,nList,tList,"That's not the correct password."}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
@ -934,7 +994,7 @@ func route_account_own_edit_critical_submit(w http.ResponseWriter, r *http.Reque
return
}
if new_password != confirm_password {
pi := Page{"Error","error",user,tList,"The two passwords don't match."}
pi := Page{"Error","error",user,nList,tList,"The two passwords don't match."}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
@ -952,15 +1012,19 @@ func route_account_own_edit_critical_submit(w http.ResponseWriter, r *http.Reque
return
}
pi := Page{"Edit Password","account-own-edit-success",user,tList,0}
pi := Page{"Edit Password","account-own-edit-success",user,noticeList,tList,0}
templates.ExecuteTemplate(w,"account-own-edit-success.html", pi)
}
func route_account_own_edit_avatar(w http.ResponseWriter, r *http.Request) {
user := SessionCheck(w,r)
user, noticeList, ok := SessionCheck(w,r)
if !ok {
return
}
if !user.Loggedin {
errmsg := "You need to login to edit your own account."
pi := Page{"Error","error",user,tList,errmsg}
pi := Page{"Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
@ -970,7 +1034,7 @@ func route_account_own_edit_avatar(w http.ResponseWriter, r *http.Request) {
return
}
pi := Page{"Edit Avatar","account-own-edit-avatar",user,tList,0}
pi := Page{"Edit Avatar","account-own-edit-avatar",user,noticeList,tList,0}
templates.ExecuteTemplate(w,"account-own-edit-avatar.html", pi)
}
@ -981,10 +1045,13 @@ func route_account_own_edit_avatar_submit(w http.ResponseWriter, r *http.Request
}
r.Body = http.MaxBytesReader(w, r.Body, int64(max_request_size))
user := SessionCheck(w,r)
user, noticeList, ok := SessionCheck(w,r)
if !ok {
return
}
if !user.Loggedin {
errmsg := "You need to login to edit your own account."
pi := Page{"Error","error",user,tList,errmsg}
pi := Page{"Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
@ -1061,16 +1128,21 @@ func route_account_own_edit_avatar_submit(w http.ResponseWriter, r *http.Request
}
user.Avatar = "/uploads/avatar_" + strconv.Itoa(user.ID) + "." + ext
noticeList[len(noticeList)] = "Your avatar was successfully updated"
pi := Page{"Edit Avatar","account-own-edit-avatar-success",user,tList,0}
templates.ExecuteTemplate(w,"account-own-edit-avatar-success.html", pi)
pi := Page{"Edit Avatar","account-own-edit-avatar",user,noticeList,tList,0}
templates.ExecuteTemplate(w,"account-own-edit-avatar.html", pi)
}
func route_account_own_edit_username(w http.ResponseWriter, r *http.Request) {
user := SessionCheck(w,r)
user, noticeList, ok := SessionCheck(w,r)
if !ok {
return
}
if !user.Loggedin {
errmsg := "You need to login to edit your own account."
pi := Page{"Error","error",user,tList,errmsg}
pi := Page{"Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
@ -1080,15 +1152,19 @@ func route_account_own_edit_username(w http.ResponseWriter, r *http.Request) {
return
}
pi := Page{"Edit Username","account-own-edit-username",user,tList,user.Name}
pi := Page{"Edit Username","account-own-edit-username",user,noticeList,tList,user.Name}
templates.ExecuteTemplate(w,"account-own-edit-username.html", pi)
}
func route_account_own_edit_username_submit(w http.ResponseWriter, r *http.Request) {
user := SessionCheck(w,r)
user, noticeList, ok := SessionCheck(w,r)
if !ok {
return
}
if !user.Loggedin {
errmsg := "You need to login to edit your own account."
pi := Page{"Error","error",user,tList,errmsg}
pi := Page{"Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
@ -1112,15 +1188,19 @@ func route_account_own_edit_username_submit(w http.ResponseWriter, r *http.Reque
}
user.Name = new_username
pi := Page{"Edit Username","account-own-edit-username",user,tList,user.Name}
pi := Page{"Edit Username","account-own-edit-username",user,noticeList,tList,user.Name}
templates.ExecuteTemplate(w,"account-own-edit-username.html", pi)
}
func route_logout(w http.ResponseWriter, r *http.Request) {
user := SessionCheck(w,r)
user, ok := SimpleSessionCheck(w,r)
if !ok {
return
}
if !user.Loggedin {
errmsg := "You can't logout without logging in first."
pi := Page{"Error","error",user,tList,errmsg}
pi := Page{"Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
@ -1139,10 +1219,14 @@ func route_logout(w http.ResponseWriter, r *http.Request) {
}
func route_login(w http.ResponseWriter, r *http.Request) {
user := SessionCheck(w,r)
user, noticeList, ok := SessionCheck(w,r)
if !ok {
return
}
if user.Loggedin {
errmsg := "You're already logged in."
pi := Page{"Error","error",user,tList,errmsg}
pi := Page{"Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
@ -1152,15 +1236,19 @@ func route_login(w http.ResponseWriter, r *http.Request) {
return
}
pi := Page{"Login","login",user,tList,0}
pi := Page{"Login","login",user,noticeList,tList,0}
templates.ExecuteTemplate(w,"login.html", pi)
}
func route_login_submit(w http.ResponseWriter, r *http.Request) {
user := SessionCheck(w,r)
user, ok := SimpleSessionCheck(w,r)
if !ok {
return
}
if user.Loggedin {
errmsg := "You're already logged in."
pi := Page{"Error","error",user,tList,errmsg}
pi := Page{"Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
@ -1186,7 +1274,7 @@ func route_login_submit(w http.ResponseWriter, r *http.Request) {
err = login_stmt.QueryRow(username).Scan(&uid, &username, &real_password, &salt)
if err == sql.ErrNoRows {
errmsg := "That username doesn't exist."
pi := Page{"Error","error",user,tList,errmsg}
pi := Page{"Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
@ -1203,7 +1291,7 @@ func route_login_submit(w http.ResponseWriter, r *http.Request) {
if salt == "" {
if password != real_password {
errmsg := "That's not the correct password."
pi := Page{"Error","error",user,tList,errmsg}
pi := Page{"Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
@ -1225,7 +1313,7 @@ func route_login_submit(w http.ResponseWriter, r *http.Request) {
err := bcrypt.CompareHashAndPassword([]byte(real_password), []byte(password))
if err == bcrypt.ErrMismatchedHashAndPassword {
errmsg := "That's not the correct password."
pi := Page{"Error","error",user,tList,errmsg}
pi := Page{"Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
@ -1259,10 +1347,14 @@ func route_login_submit(w http.ResponseWriter, r *http.Request) {
}
func route_register(w http.ResponseWriter, r *http.Request) {
user := SessionCheck(w,r)
user, noticeList, ok := SessionCheck(w,r)
if !ok {
return
}
if user.Loggedin {
errmsg := "You're already logged in."
pi := Page{"Error","error",user,tList,errmsg}
pi := Page{"Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
@ -1272,12 +1364,16 @@ func route_register(w http.ResponseWriter, r *http.Request) {
return
}
pi := Page{"Registration","register",user,tList,0}
pi := Page{"Registration","register",user,noticeList,tList,0}
templates.ExecuteTemplate(w,"register.html", pi)
}
func route_register_submit(w http.ResponseWriter, r *http.Request) {
user := SessionCheck(w,r)
user, ok := SimpleSessionCheck(w,r)
if !ok {
return
}
err := r.ParseForm()
if err != nil {
LocalError("Bad Form", w, r, user)
@ -1285,14 +1381,33 @@ func route_register_submit(w http.ResponseWriter, r *http.Request) {
}
username := html.EscapeString(r.PostFormValue("username"))
if username == "" {
LocalError("You didn't put in a username.", w, r, user)
return
}
email := html.EscapeString(r.PostFormValue("email"))
if email == "" {
LocalError("You didn't put in an email.", w, r, user)
return
}
password := r.PostFormValue("password")
if password == "" {
LocalError("You didn't put in a password.", w, r, user)
return
}
if password == "test" || password == "123456" || password == "123" || password == "password" {
LocalError("Your password is too weak.", w, r, user)
return
}
confirm_password := r.PostFormValue("confirm_password")
log.Print("Registration Attempt! Username: " + username)
// Do the two inputted passwords match..?
if password != confirm_password {
errmsg := "The two passwords don't match."
pi := Page{"Password Mismatch","error",user,tList,errmsg}
pi := Page{"Password Mismatch","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
@ -1309,7 +1424,7 @@ func route_register_submit(w http.ResponseWriter, r *http.Request) {
return
} else if err != sql.ErrNoRows {
errmsg := "This username isn't available. Try another."
pi := Page{"Username Taken","error",user,tList,errmsg}
pi := Page{"Username Taken","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
@ -1338,7 +1453,7 @@ func route_register_submit(w http.ResponseWriter, r *http.Request) {
return
}
res, err := register_stmt.Exec(username,string(hashed_password),salt,session)
res, err := register_stmt.Exec(username,email,string(hashed_password),salt,session)
if err != nil {
InternalError(err,w,r,user)
return

191
template_profile.go Normal file
View File

@ -0,0 +1,191 @@
package main
import "strconv"
func init() {
ctemplates["profile"] = template_profile
}
func template_profile(tmpl_profile_vars Page) (tmpl string) {
var extra_data User = tmpl_profile_vars.Something.(User)
tmpl += `<!doctype html>
<html lang="en">
<head>
<title>`
tmpl += tmpl_profile_vars.Title
tmpl += `</title>
<link href="/static/main.css" rel="stylesheet" type="text/css">
<script type="text/javascript" src="/static/jquery-1.12.3.min.js"></script>
<script type="text/javascript">
var session = "`
tmpl += tmpl_profile_vars.CurrentUser.Session
tmpl += `";
</script>
<script type="text/javascript" src="/static/global.js"></script>
</head>
<body>
<div class="container">
`
tmpl += `<div class="nav">
<ul>
<li class="menu_overview"><a href="/">Overview</a></li>
<li class="menu_forums"><a href="/forums/">Forums</a></li>
<li class="menu_topics"><a href="/">Topics</a></li>
<li class="menu_create_topic"><a href="/topics/create/">Create Topic</a></li>
`
if tmpl_profile_vars.CurrentUser.Loggedin {
tmpl += `
<li class="menu_account"><a href="/user/edit/critical/">Account</a></li>
<li class="menu_account"><a href="/user/`
tmpl += strconv.Itoa(tmpl_profile_vars.CurrentUser.ID)
tmpl += `">Profile</a></li>
`
if tmpl_profile_vars.CurrentUser.Is_Super_Mod {
tmpl += `<li class="menu_account"><a href="/panel/forums/">Panel</a></li>`
}
tmpl += `
<li class="menu_logout"><a href="/accounts/logout?session=`
tmpl += tmpl_profile_vars.CurrentUser.Session
tmpl += `">Logout</a></li>
`
} else {
tmpl += `
<li class="menu_register"><a href="/accounts/create/">Register</a></li>
<li class="menu_login"><a href="/accounts/login/">Login</a></li>
`
}
tmpl += `
</ul>
</div>`
tmpl += `
`
if len(tmpl_profile_vars.NoticeList) != 0 {
for _, item := range tmpl_profile_vars.NoticeList {
tmpl += `<div class="alert">`
tmpl += item
tmpl += `</div>`
}
}
tmpl += `
<div class="colblock_left" style="max-width: 220px;">
<div class="rowitem" style="padding: 0;"><img src="`
tmpl += extra_data.Avatar
tmpl += `" style="max-width: 100%;margin: 0;"/></div>
<div class="rowitem" style="text-transform: capitalize;">
<span style="font-size: 18px;">`
tmpl += extra_data.Name
tmpl += `</span>`
if extra_data.Tag != "" {
tmpl += `<span class="username" style="float: right;">`
tmpl += extra_data.Tag
tmpl += `</span>`
}
tmpl += `
</div>
<div class="rowitem passive">
<a class="username">Add Friend</a>
`
if tmpl_profile_vars.CurrentUser.Is_Super_Mod && !extra_data.Is_Super_Mod {
tmpl += `
`
if extra_data.Is_Banned {
tmpl += `<a href="/users/unban/`
tmpl += strconv.Itoa(extra_data.ID)
tmpl += `" class="username">Unban</a>`
} else {
tmpl += `<a href="/users/ban/`
tmpl += strconv.Itoa(extra_data.ID)
tmpl += `" class="username">Ban</a>`
}
tmpl += `
`
}
tmpl += `
<a href="/report/submit/`
tmpl += strconv.Itoa(extra_data.ID)
tmpl += `?session=`
tmpl += tmpl_profile_vars.CurrentUser.Session
tmpl += `&type=user" class="username report_item">Report</a>
</div>
</div>
<div class="colblock_right">
<div class="rowitem"><a>Comments</a></div>
</div>
<div class="colblock_right" style="overflow: hidden;">
`
if len(tmpl_profile_vars.ItemList) != 0 {
for _, item := range tmpl_profile_vars.ItemList {
tmpl += `
<div class="rowitem passive deletable_block editable_parent" style="`
if item.(Reply).Avatar != "" {
tmpl += `background-image: url(`
tmpl += item.(Reply).Avatar
tmpl += `), url(/static/white-dot.jpg);background-position: 0px `
if item.(Reply).ContentLines <= 5 {
tmpl += `-1`
}
tmpl += `0px;background-repeat: no-repeat, repeat-y;background-size: 128px;padding-left: 136px;`
tmpl += string(item.(Reply).Css)
}
tmpl += `">
<span class="editable_block user_content">`
tmpl += string(item.(Reply).ContentHtml)
tmpl += `</span>
<br /><br />
<a href="/user/`
tmpl += strconv.Itoa(item.(Reply).CreatedBy)
tmpl += `" class="username">`
tmpl += item.(Reply).CreatedByName
tmpl += `</a>
`
if tmpl_profile_vars.CurrentUser.Is_Mod {
tmpl += `<a href="/profile/reply/edit/submit/`
tmpl += strconv.Itoa(item.(Reply).ID)
tmpl += `"><button class="username edit_item">Edit</button></a>
<a href="/profile/reply/delete/submit/`
tmpl += strconv.Itoa(item.(Reply).ID)
tmpl += `"><button class="username delete_item">Delete</button></a>`
}
tmpl += `
<a href="/report/submit/`
tmpl += strconv.Itoa(item.(Reply).ID)
tmpl += `?session=`
tmpl += tmpl_profile_vars.CurrentUser.Session
tmpl += `&type=user-reply"><button class="username report_item">Report</button></a>
`
if item.(Reply).Tag != "" {
tmpl += `<a class="username" style="float: right;">`
tmpl += item.(Reply).Tag
tmpl += `</a>`
}
tmpl += `
</div>`
}
}
tmpl += `
</div>
`
if !tmpl_profile_vars.CurrentUser.Is_Banned {
tmpl += `
<div class="colblock_right">
<form action="/profile/reply/create/" method="post">
<input name="uid" value='`
tmpl += strconv.Itoa(extra_data.ID)
tmpl += `' type="hidden" />
<div class="formrow">
<div class="formitem"><textarea name="reply-content" placeholder="Insert reply here"></textarea></div>
</div>
<div class="formrow">
<div class="formitem"><button name="reply-button" class="formbutton">Create Reply</button></div>
</div>
</form>
</div>
`
}
tmpl += `
`
tmpl += ` <!--<link rel="stylesheet" href="https://use.fontawesome.com/8670aa03ca.css">-->
</div>
</body>
</html>`
return tmpl
}

261
template_topic.go Normal file
View File

@ -0,0 +1,261 @@
package main
import "strconv"
func init() {
ctemplates["topic"] = template_topic
}
func template_topic(tmpl_topic_vars Page) (tmpl string) {
var extra_data TopicUser = tmpl_topic_vars.Something.(TopicUser)
tmpl += `<!doctype html>
<html lang="en">
<head>
<title>`
tmpl += tmpl_topic_vars.Title
tmpl += `</title>
<link href="/static/main.css" rel="stylesheet" type="text/css">
<script type="text/javascript" src="/static/jquery-1.12.3.min.js"></script>
<script type="text/javascript">
var session = "`
tmpl += tmpl_topic_vars.CurrentUser.Session
tmpl += `";
</script>
<script type="text/javascript" src="/static/global.js"></script>
</head>
<body>
<div class="container">
`
tmpl += `<div class="nav">
<ul>
<li class="menu_overview"><a href="/">Overview</a></li>
<li class="menu_forums"><a href="/forums/">Forums</a></li>
<li class="menu_topics"><a href="/">Topics</a></li>
<li class="menu_create_topic"><a href="/topics/create/">Create Topic</a></li>
`
if tmpl_topic_vars.CurrentUser.Loggedin {
tmpl += `
<li class="menu_account"><a href="/user/edit/critical/">Account</a></li>
<li class="menu_account"><a href="/user/`
tmpl += strconv.Itoa(tmpl_topic_vars.CurrentUser.ID)
tmpl += `">Profile</a></li>
`
if tmpl_topic_vars.CurrentUser.Is_Super_Mod {
tmpl += `<li class="menu_account"><a href="/panel/forums/">Panel</a></li>`
}
tmpl += `
<li class="menu_logout"><a href="/accounts/logout?session=`
tmpl += tmpl_topic_vars.CurrentUser.Session
tmpl += `">Logout</a></li>
`
} else {
tmpl += `
<li class="menu_register"><a href="/accounts/create/">Register</a></li>
<li class="menu_login"><a href="/accounts/login/">Login</a></li>
`
}
tmpl += `
</ul>
</div>`
tmpl += `
`
if len(tmpl_topic_vars.NoticeList) != 0 {
for _, item := range tmpl_topic_vars.NoticeList {
tmpl += `<div class="alert">`
tmpl += item
tmpl += `</div>`
}
}
tmpl += `
<div class="rowblock">
<form action='/topic/edit/submit/`
tmpl += strconv.Itoa(extra_data.ID)
tmpl += `' method="post">
<div class="rowitem"`
if extra_data.Sticky {
tmpl += ` style="background-color: #FFFFEA;"`
}
tmpl += `>
<a class='topic_name hide_on_edit'>`
tmpl += extra_data.Title
tmpl += `</a>
<span class='username topic_status_e topic_status_`
tmpl += extra_data.Status
tmpl += ` hide_on_edit' style="font-weight:normal;float: right;">`
tmpl += extra_data.Status
tmpl += `</span>
<span class="username" style="border-right: 0;font-weight: normal;float: right;">Status</span>
`
if tmpl_topic_vars.CurrentUser.Is_Mod {
tmpl += `
<a href='/topic/edit/`
tmpl += strconv.Itoa(extra_data.ID)
tmpl += `' class="username hide_on_edit open_edit" style="font-weight: normal;margin-left: 6px;">Edit</a>
<a href='/topic/delete/submit/`
tmpl += strconv.Itoa(extra_data.ID)
tmpl += `' class="username" style="font-weight: normal;">Delete</a>
`
if extra_data.Sticky {
tmpl += `<a href='/topic/unstick/submit/`
tmpl += strconv.Itoa(extra_data.ID)
tmpl += `' class="username" style="font-weight: normal;">Unpin</a>`
} else {
tmpl += `<a href='/topic/stick/submit/`
tmpl += strconv.Itoa(extra_data.ID)
tmpl += `' class="username" style="font-weight: normal;">Pin</a>`
}
tmpl += `
<input class='show_on_edit topic_name_input' name="topic_name" value='`
tmpl += extra_data.Title
tmpl += `' type="text" />
<select name="topic_status" class='show_on_edit topic_status_input' style='float: right;'>
<option>open</option>
<option>closed</option>
</select>
<button name="topic-button" class="formbutton show_on_edit submit_edit">Update</button>
`
}
tmpl += `
<a href="/report/submit/`
tmpl += strconv.Itoa(extra_data.ID)
tmpl += `?session=`
tmpl += tmpl_topic_vars.CurrentUser.Session
tmpl += `&type=topic" class="username report_item" style="font-weight: normal;">Report</a>
</div>
</form>
</div>
<div class="rowblock">
<div class="rowitem passive editable_parent" style="border-bottom: none;`
if extra_data.Avatar != "" {
tmpl += `background-image: url(`
tmpl += extra_data.Avatar
tmpl += `), url(/static/white-dot.jpg);background-position: 0px `
if extra_data.ContentLines <= 5 {
tmpl += `-1`
}
tmpl += `0px;background-repeat: no-repeat, repeat-y;background-size: 128px;padding-left: 136px;`
tmpl += string(extra_data.Css)
}
tmpl += `">
<span class="hide_on_edit topic_content user_content">`
tmpl += string(tmpl_topic_varsstring(.Something.(TopicUser).Content))
tmpl += `</span>
<textarea name="topic_content" class="show_on_edit topic_content_input">`
tmpl += string(tmpl_topic_varsstring(.Something.(TopicUser).Content))
tmpl += `</textarea>
<br /><br />
<a href="/user/`
tmpl += strconv.Itoa(extra_data.CreatedBy)
tmpl += `" class="username">`
tmpl += extra_data.CreatedByName
tmpl += `</a>
`
if extra_data.Tag != "" {
tmpl += `<a class="username" style="float: right;">`
tmpl += extra_data.Tag
tmpl += `</a>`
} else {
if extra_data.URLName != "" {
tmpl += `<a href="`
tmpl += extra_data.URL
tmpl += `" class="username" style="color: #505050;float: right;">`
tmpl += extra_data.URLName
tmpl += `</a>
<a class="username" style="color: #505050;float: right;border-right: 0;">`
tmpl += extra_data.URLPrefix
tmpl += `</a>`
}
}
tmpl += `
</div>
</div><br />
<div class="rowblock" style="overflow: hidden;">
`
if len(tmpl_topic_vars.ItemList) != 0 {
for _, item := range tmpl_topic_vars.ItemList {
tmpl += `
<div class="rowitem passive deletable_block editable_parent" style="`
if item.(Reply).Avatar != "" {
tmpl += `background-image: url(`
tmpl += item.(Reply).Avatar
tmpl += `), url(/static/white-dot.jpg);background-position: 0px `
if item.(Reply).ContentLines <= 5 {
tmpl += `-1`
}
tmpl += `0px;background-repeat: no-repeat, repeat-y;background-size: 128px;padding-left: 136px;`
tmpl += string(item.(Reply).Css)
}
tmpl += `">
<span class="editable_block user_content">`
tmpl += string(item.(Reply).ContentHtml)
tmpl += `</span>
<br /><br />
<a href="/user/`
tmpl += strconv.Itoa(item.(Reply).CreatedBy)
tmpl += `" class="username">`
tmpl += item.(Reply).CreatedByName
tmpl += `</a>
`
if tmpl_topic_vars.CurrentUser.Is_Mod {
tmpl += `<a href="/reply/edit/submit/`
tmpl += strconv.Itoa(item.(Reply).ID)
tmpl += `"><button class="username edit_item">Edit</button></a>
<a href="/reply/delete/submit/`
tmpl += strconv.Itoa(item.(Reply).ID)
tmpl += `"><button class="username delete_item">Delete</button></a>`
}
tmpl += `
<a href="/report/submit/`
tmpl += strconv.Itoa(item.(Reply).ID)
tmpl += `?session=`
tmpl += tmpl_topic_vars.CurrentUser.Session
tmpl += `&type=reply"><button class="username report_item">Report</button></a>
`
if item.(Reply).Tag != "" {
tmpl += `<a class="username" style="float: right;">`
tmpl += item.(Reply).Tag
tmpl += `</a>`
} else {
if item.(Reply).URLName != "" {
tmpl += `<a href="`
tmpl += item.(Reply).URL
tmpl += `" class="username" style="color: #505050;float: right;" rel="nofollow">`
tmpl += item.(Reply).URLName
tmpl += `</a>
<a class="username" style="color: #505050;float: right;border-right: 0;">`
tmpl += item.(Reply).URLPrefix
tmpl += `</a>`
}
}
tmpl += `
</div>`
}
}
tmpl += `
</div>
`
if !tmpl_topic_vars.CurrentUser.Is_Banned {
tmpl += `
<div class="rowblock">
<form action="/reply/create/" method="post">
<input name="tid" value='`
tmpl += strconv.Itoa(extra_data.ID)
tmpl += `' type="hidden" />
<div class="formrow">
<div class="formitem"><textarea name="reply-content" placeholder="Insert reply here"></textarea></div>
</div>
<div class="formrow">
<div class="formitem"><button name="reply-button" class="formbutton">Create Reply</button></div>
</div>
</form>
</div>
`
}
tmpl += `
`
tmpl += ` <!--<link rel="stylesheet" href="https://use.fontawesome.com/8670aa03ca.css">-->
</div>
</body>
</html>`
return tmpl
}

665
templates.go Normal file
View File

@ -0,0 +1,665 @@
package main
import "log"
import "fmt"
import "strings"
import "reflect"
import "path/filepath"
import "io/ioutil"
import "text/template/parse"
type VarItem struct
{
Name string
Destination string
Type string
}
type VarItemReflect struct
{
Name string
Destination string
Value reflect.Value
}
type CTemplateSet struct
{
tlist map[string]*parse.Tree
dir string
funcMap map[string]interface{}
importMap map[string]string
varList map[string]VarItem
localVars map[string]map[string]VarItemReflect
//tempVars map[string]string
doImports bool
expectsInt interface{}
}
func (c *CTemplateSet) compile_template(name string, dir string, expects string, expectsInt interface{}, varList map[string]VarItem) (out string) {
c.dir = dir
c.doImports = true
c.funcMap = make(map[string]interface{})
c.funcMap["and"] = "&&"
c.funcMap["not"] = "!"
c.funcMap["or"] = "||"
c.funcMap["eq"] = true
c.funcMap["ge"] = true
c.funcMap["gt"] = true
c.funcMap["le"] = true
c.funcMap["lt"] = true
c.funcMap["ne"] = true
c.importMap = make(map[string]string)
c.importMap["strconv"] = "strconv"
c.varList = varList
c.expectsInt = expectsInt
holdreflect := reflect.ValueOf(expectsInt)
res, err := ioutil.ReadFile(dir + name)
if err != nil {
log.Fatal(err)
}
content := string(res)
tree := parse.New(name, c.funcMap)
var treeSet map[string]*parse.Tree = make(map[string]*parse.Tree)
tree, err = tree.Parse(content,"{{","}}", treeSet, c.funcMap)
if err != nil {
log.Fatal(err)
}
if debug {
fmt.Println(name)
}
out = ""
fname := strings.TrimSuffix(name, filepath.Ext(name))
c.tlist = make(map[string]*parse.Tree)
c.tlist[fname] = tree
varholder := "tmpl_" + fname + "_vars"
if debug {
fmt.Println(c.tlist)
}
c.localVars = make(map[string]map[string]VarItemReflect)
c.localVars[fname] = make(map[string]VarItemReflect)
c.localVars[fname]["."] = VarItemReflect{".",varholder,holdreflect}
subtree := c.tlist[fname]
if debug {
fmt.Println(subtree.Root)
}
for _, node := range subtree.Root.Nodes {
if debug {
fmt.Println("Node: " + node.String())
}
out += c.compile_switch(varholder, holdreflect, fname, node)
}
var importList string
if c.doImports {
for _, item := range c.importMap {
importList += "import \"" + item + "\"\n"
}
}
var varString string
for _, varItem := range c.varList {
varString += "var " + varItem.Name + " " + varItem.Type + " = " + varItem.Destination + "\n"
}
out = "package main\n" + importList + "\nfunc init() {\nctemplates[\"" + fname + "\"] = template_" + fname + "\n}\n\nfunc template_" + fname + "(tmpl_" + fname + "_vars " + expects + ") (tmpl string) {\n" + varString + out + "return tmpl\n}\n"
if debug {
fmt.Println("Output!")
fmt.Println(out)
}
return out
}
func (c *CTemplateSet) compile_switch(varholder string, holdreflect reflect.Value, template_name string, node interface{}) (out string) {
switch node := node.(type) {
case *parse.ActionNode:
if debug {
fmt.Println("Action Node")
}
if node.Pipe == nil {
break
}
for _, cmd := range node.Pipe.Cmds {
out += c.compile_subswitch(varholder, holdreflect, template_name, cmd)
}
return out
case *parse.IfNode:
if debug {
fmt.Println("If Node: ")
fmt.Println(node.Pipe)
}
var expr string
for _, cmd := range node.Pipe.Cmds {
if debug {
fmt.Println("If Node Bit: ")
fmt.Println(cmd)
fmt.Println(reflect.ValueOf(cmd).Type().Name())
}
expr += c.compile_varswitch(varholder, holdreflect, template_name, cmd)
}
if node.ElseList == nil {
if debug {
fmt.Println("Branch 1")
}
return "if " + expr + " {\n" + c.compile_switch(varholder, holdreflect, template_name, node.List) + "}\n"
} else {
if debug {
fmt.Println("Branch 2")
}
return "if " + expr + " {\n" + c.compile_switch(varholder, holdreflect, template_name, node.List) + "} else {\n" + c.compile_switch(varholder, holdreflect, template_name, node.ElseList) + "}\n"
}
case *parse.ListNode:
if debug {
fmt.Println("List Node")
}
for _, subnode := range node.Nodes {
out += c.compile_switch(varholder, holdreflect, template_name, subnode)
}
return out
case *parse.RangeNode:
if debug {
fmt.Println("Range Node!")
fmt.Println(node.Pipe)
}
var outVal reflect.Value
for _, cmd := range node.Pipe.Cmds {
if debug {
fmt.Println("Range Bit: ")
fmt.Println(cmd)
}
out, outVal = c.compile_reflectswitch(varholder, holdreflect, template_name, cmd)
}
if debug {
fmt.Println("Returned: ")
fmt.Println(out)
fmt.Println("Range Kind Switch!")
}
switch outVal.Kind() {
case reflect.Map:
var item reflect.Value
for _, key := range outVal.MapKeys() {
item = outVal.MapIndex(key)
}
out = "if len(" + out + ") != 0 {\nfor _, item := range " + out + " {\n" + c.compile_switch("item", item, template_name, node.List) + "}\n}"
case reflect.Invalid:
return ""
}
if node.ElseList != nil {
out += " else {\n" + c.compile_switch(varholder, holdreflect, template_name, node.ElseList) + "}\n"
} else {
out += "\n"
}
return out
case *parse.TemplateNode:
if debug {
fmt.Println("Template Node")
}
return c.compile_subtemplate(varholder, holdreflect, node)
case *parse.TextNode:
return "tmpl += `" + string(node.Text) + "`\n"
default:
panic("Unknown Node in main switch")
}
return ""
}
func (c *CTemplateSet) compile_subswitch(varholder string, holdreflect reflect.Value, template_name string, node *parse.CommandNode) (out string) {
firstWord := node.Args[0]
switch n := firstWord.(type) {
case *parse.FieldNode:
if debug {
fmt.Println("Field Node: ")
fmt.Println(n.Ident)
}
/* Use reflect to determine if the field is for a method, otherwise assume it's a variable. Coming Soon. */
cur := holdreflect
var varbit string
if cur.Kind() == reflect.Interface {
cur = cur.Elem()
varbit += ".(" + cur.Type().Name() + ")"
}
for _, id := range n.Ident {
if debug {
fmt.Println("Data Kind: ")
fmt.Println(cur.Kind().String())
fmt.Println("Field Bit: ")
fmt.Println(id)
}
cur = cur.FieldByName(id)
if cur.Kind() == reflect.Interface {
cur = cur.Elem()
if cur.Kind() == reflect.String && cur.Type().Name() != "string" {
varbit = "string(" + varbit + "." + id + ")"
} else {
varbit += "." + id + ".(" + cur.Type().Name() + ")"
}
} else {
varbit += "." + id
}
if debug {
fmt.Println("End Cycle")
}
}
out = c.compile_varsub(varholder + varbit, cur)
for _, varItem := range c.varList {
if strings.HasPrefix(out, varItem.Destination) {
out = strings.Replace(out, varItem.Destination, varItem.Name, 1)
}
}
return out
case *parse.DotNode:
if debug {
fmt.Println("Dot Node")
fmt.Println(node.String())
}
return c.compile_varsub(varholder, holdreflect)
case *parse.NilNode:
panic("Nil is not a command x.x")
case *parse.VariableNode:
if debug {
fmt.Println("Variable Node")
fmt.Println(n.String())
fmt.Println(n.Ident)
}
out, _ = c.compile_if_varsub(n.String(), varholder, template_name, holdreflect)
return "tmpl += " + out + "\n"
case *parse.StringNode:
return n.Quoted
default:
fmt.Println("Unknown Kind: ")
fmt.Println(reflect.ValueOf(firstWord).Elem().Kind())
fmt.Println("Unknown Type: ")
fmt.Println(reflect.ValueOf(firstWord).Elem().Type().Name())
panic("I don't know what node this is")
}
return ""
}
func (c *CTemplateSet) compile_varswitch(varholder string, holdreflect reflect.Value, template_name string, node *parse.CommandNode) (out string) {
firstWord := node.Args[0]
switch n := firstWord.(type) {
case *parse.FieldNode:
if debug {
fmt.Println("Field Node: ")
fmt.Println(n.Ident)
for _, id := range n.Ident {
fmt.Println("Field Bit: ")
fmt.Println(id)
}
}
/* Use reflect to determine if the field is for a method, otherwise assume it's a variable. Coming Soon. */
return c.compile_boolsub(n.String(), varholder, template_name, holdreflect)
case *parse.ChainNode:
if debug {
fmt.Println("Chain Node: ")
fmt.Println(n.Node)
fmt.Println(node.Args)
}
break
case *parse.IdentifierNode:
if debug {
fmt.Println("Identifier Node: ")
fmt.Println(node)
fmt.Println(node.Args)
}
return c.compile_identswitch(varholder, holdreflect, template_name, node)
case *parse.DotNode:
return varholder
case *parse.VariableNode:
if debug {
fmt.Println("Variable Node")
fmt.Println(n.String())
fmt.Println(n.Ident)
}
out, _ = c.compile_if_varsub(n.String(), varholder, template_name, holdreflect)
return out
case *parse.NilNode:
panic("Nil is not a command x.x")
case *parse.PipeNode:
if debug {
fmt.Println("Pipe Node!")
fmt.Println(n)
}
/*for _, cmd := range n.Cmds {
if debug {
fmt.Println("Pipe Bit: ")
fmt.Println(cmd)
}
out += c.compile_if_varsub_n(n.String(), varholder, template_name, holdreflect)
}*/
if debug {
fmt.Println("Args: ")
fmt.Println(node.Args)
}
/*argcopy := node.Args[1:]
for _, arg := range argcopy {
if debug {
fmt.Println("Pipe Arg: ")
fmt.Println(arg)
fmt.Println(reflect.ValueOf(arg).Elem().Type().Name())
fmt.Println(reflect.ValueOf(arg).Kind())
}
switch arg.(type) {
case *parse.IdentifierNode:
out += c.compile_identswitch(varholder, holdreflect, template_name, node)
break
case *parse.PipeNode:
break
//out += c.compile_if_varsub_n(a.String(), varholder, template_name, holdreflect)
default:
panic("Unknown Pipe Arg type! Did Mario get stuck in the pipes again?")
}
//out += c.compile_varswitch(arg.String(), holdreflect, template_name, arg)
}*/
out += c.compile_identswitch(varholder, holdreflect, template_name, node)
if debug {
fmt.Println("Out: ")
fmt.Println(out)
}
return out
default:
fmt.Println("Unknown Kind: ")
fmt.Println(reflect.ValueOf(firstWord).Elem().Kind())
fmt.Println("Unknown Type: ")
fmt.Println(reflect.ValueOf(firstWord).Elem().Type().Name())
panic("I don't know what node this is! Grr...")
}
return ""
}
func (c *CTemplateSet) compile_identswitch(varholder string, holdreflect reflect.Value, template_name string, node *parse.CommandNode) (out string) {
ArgLoop:
for pos, id := range node.Args {
if debug {
fmt.Println(id)
}
switch id.String() {
case "not":
out += "!"
case "or":
out += " || "
case "and":
out += " && "
case "le":
out += c.compile_if_varsub_n(node.Args[pos + 1].String(), varholder, template_name, holdreflect) + " <= " + c.compile_if_varsub_n(node.Args[pos + 2].String(), varholder, template_name, holdreflect)
break ArgLoop
default:
if debug {
fmt.Println("Variable!")
}
out += c.compile_if_varsub_n(id.String(), varholder, template_name, holdreflect)
}
}
return out
}
func (c *CTemplateSet) compile_reflectswitch(varholder string, holdreflect reflect.Value, template_name string, node *parse.CommandNode) (out string, outVal reflect.Value) {
firstWord := node.Args[0]
switch n := firstWord.(type) {
case *parse.FieldNode:
if debug {
fmt.Println("Field Node: ")
fmt.Println(n.Ident)
for _, id := range n.Ident {
fmt.Println("Field Bit: ")
fmt.Println(id)
}
}
/* Use reflect to determine if the field is for a method, otherwise assume it's a variable. Coming Soon. */
return c.compile_if_varsub(n.String(), varholder, template_name, holdreflect)
case *parse.ChainNode:
if debug {
fmt.Println("Chain Node: ")
fmt.Println(n.Node)
fmt.Println(node.Args)
}
return "", outVal
/*case *parse.IdentifierNode:
fmt.Println("Identifier Node: ")
fmt.Println(node)
fmt.Println(node.Args)
ArgLoop:
for pos, id := range node.Args {
fmt.Println(id)
switch id.String() {
case "not":
out += "!"
case "or":
out += " || "
case "and":
out += " && "
case "le":
out += c.compile_if_varsub_n(node.Args[pos + 1].String(), varholder, holdreflect) + " <= " + c.compile_if_varsub_n(node.Args[pos + 2].String(), varholder, holdreflect)
break ArgLoop
default:
fmt.Println("Variable!")
out += c.compile_if_varsub_n(id.String(), varholder, holdreflect)
}
}
return out*/
case *parse.DotNode:
return varholder, holdreflect
case *parse.NilNode:
panic("Nil is not a command x.x")
default:
//panic("I don't know what node this is")
}
return "", outVal
}
func (c *CTemplateSet) compile_if_varsub_n(varname string, varholder string, template_name string, cur reflect.Value) (out string) {
out, _ = c.compile_if_varsub(varname, varholder, template_name, cur)
return out
}
func (c *CTemplateSet) compile_if_varsub(varname string, varholder string, template_name string, cur reflect.Value) (out string, val reflect.Value) {
if varname[0] != '.' && varname[0] != '$' {
return varname, cur
}
bits := strings.Split(varname,".")
if varname[0] == '$' {
var res VarItemReflect
if varname[1] == '.' {
res = c.localVars[template_name]["."]
} else {
res = c.localVars[template_name][strings.TrimPrefix(bits[0],"$")]
}
out += res.Destination
cur = res.Value
if cur.Kind() == reflect.Interface {
cur = cur.Elem()
}
} else {
if cur.Kind() == reflect.Interface {
cur = cur.Elem()
out += varholder + ".(" + cur.Type().Name() + ")"
} else {
out += varholder
}
}
bits[0] = strings.TrimPrefix(bits[0],"$")
if debug {
fmt.Println("Cur Kind: ")
fmt.Println(cur.Kind())
fmt.Println("Cur Type: ")
fmt.Println(cur.Type().Name())
}
for _, bit := range bits {
if debug {
fmt.Println("Variable Field!")
fmt.Println(bit)
}
if bit == "" {
continue
}
cur = cur.FieldByName(bit)
if cur.Kind() == reflect.Interface {
cur = cur.Elem()
out += "." + bit + ".(" + cur.Type().Name() + ")"
} else {
out += "." + bit
}
if debug {
fmt.Println("Data Kind: ")
fmt.Println(cur.Kind())
fmt.Println("Data Type: ")
fmt.Println(cur.Type().Name())
}
}
for _, varItem := range c.varList {
if strings.HasPrefix(out, varItem.Destination) {
out = strings.Replace(out, varItem.Destination, varItem.Name, 1)
}
}
return out, cur
}
func (c *CTemplateSet) compile_boolsub(varname string, varholder string, template_name string, val reflect.Value) string {
out, val := c.compile_if_varsub(varname, varholder, template_name, val)
switch val.Kind() {
case reflect.Int:
out += " > 0"
case reflect.Bool:
// Do nothing
case reflect.String:
out += " != \"\""
case reflect.Int64:
out += " > 0"
default:
panic("I don't know what this variable's type is o.o\n")
}
return out
}
func (c *CTemplateSet) compile_varsub(varname string, val reflect.Value) string {
for _, varItem := range c.varList {
if strings.HasPrefix(varname, varItem.Destination) {
varname = strings.Replace(varname, varItem.Destination, varItem.Name, 1)
}
}
if val.Kind() == reflect.Interface {
val = val.Elem()
}
switch val.Kind() {
case reflect.Int:
return "tmpl += strconv.Itoa(" + varname + ")\n"
case reflect.Bool:
return "if " + varname + " {\ntmpl += \"true\"} else {\ntmpl += \"false\"\n}\n"
case reflect.String:
if val.Type().Name() != "string" {
return "tmpl += string(" + varname + ")\n"
} else {
return "tmpl += " + varname + "\n"
}
case reflect.Int64:
return "tmpl += strconv.FormatInt(" + varname + ", 10)"
default:
fmt.Println("Unknown Kind: ")
fmt.Println(val.Kind())
fmt.Println("Unknown Type: ")
fmt.Println(val.Type().Name())
panic("// I don't know what this variable's type is o.o\n")
}
}
func (c *CTemplateSet) compile_subtemplate(pvarholder string, pholdreflect reflect.Value, node *parse.TemplateNode) (out string) {
if debug {
fmt.Println("Template Node: " + node.Name)
}
fname := strings.TrimSuffix(node.Name, filepath.Ext(node.Name))
varholder := "tmpl_" + fname + "_vars"
var holdreflect reflect.Value
if node.Pipe != nil {
for _, cmd := range node.Pipe.Cmds {
firstWord := cmd.Args[0]
switch firstWord.(type) {
case *parse.DotNode:
varholder = pvarholder
holdreflect = pholdreflect
break
case *parse.NilNode:
panic("Nil is not a command x.x")
default:
out = "var " + varholder + " := false\n"
out += c.compile_command(cmd)
}
}
}
res, err := ioutil.ReadFile(c.dir + node.Name)
if err != nil {
log.Fatal(err)
}
content := string(res)
tree := parse.New(node.Name, c.funcMap)
var treeSet map[string]*parse.Tree = make(map[string]*parse.Tree)
tree, err = tree.Parse(content,"{{","}}", treeSet, c.funcMap)
if err != nil {
log.Fatal(err)
}
c.tlist[fname] = tree
subtree := c.tlist[fname]
if debug {
fmt.Println(subtree.Root)
}
c.localVars[fname] = make(map[string]VarItemReflect)
c.localVars[fname]["."] = VarItemReflect{".",varholder,holdreflect}
for _, node := range subtree.Root.Nodes {
if debug {
fmt.Println("Node: " + node.String())
}
out += c.compile_switch(varholder, holdreflect, fname, node)
}
return out
}
func (c *CTemplateSet) compile_command(*parse.CommandNode) (out string) {
return ""
}

View File

@ -1,31 +0,0 @@
{{template "header.html" . }}
<div class="alert_success">Your data was successfully updated</div>
<div class="colblock_left">
<div class="rowitem"><a>My Account</a></div>
<div class="rowitem passive"><a href="/user/edit/avatar/">Edit Avatar</a></div>
<div class="rowitem passive"><a href="/user/edit/username/">Edit Username</a></div>
<div class="rowitem passive"><a href="/user/edit/critical/">Edit Password</a></div>
<div class="rowitem passive"><a>Coming Soon</a></div>
<div class="rowitem passive"><a>Coming Soon</a></div>
<div class="rowitem passive"><a>Coming Soon</a></div>
</div>
<div class="colblock_right">
<div class="rowitem"><a>Edit Avatar</a></div>
</div>
{{ if .CurrentUser.HasAvatar }}
<div class="colblock_right">
<div class="rowitem"><img src="{{.CurrentUser.Avatar}}" height="128px" max-width="128px" /></div>
</div>
{{end}}
<div class="colblock_right">
<form action="/user/edit/avatar/submit/" method="post" enctype="multipart/form-data">
<div class="formrow">
<div class="formitem"><a>Upload Avatar</a></div>
<div class="formitem"><input name="account-avatar" type="file" /></div>
</div>
<div class="formrow">
<div class="formitem"><button name="account-button" class="formbutton">Update</div></div>
</div>
</form>
</div>
{{template "footer.html" . }}

View File

@ -4,7 +4,9 @@
</div>
<div class="rowblock">
{{range .ItemList}}<div class="rowitem passive" style="{{ if .Avatar }}background-image: url({{ .Avatar }});background-position: left;background-repeat: no-repeat;background-size: 64px;padding-left: 72px;{{end}}{{ if .Sticky }}background-color: #FFFFCC;{{end}}">
<a href="/topic/{{.ID}}">{{.Title}}</a> {{if .Is_Closed}}<span class="topic_status topic_status_closed">closed</span>{{else}}<span class="topic_status topic_status_open">open</span>{{end}}
<a href="/topic/{{.ID}}">{{.Title}}</a> {{if .Is_Closed}}<span class="username topic_status_e topic_status_closed" style="float: right;">closed</span>
{{else}}<span class="username topic_status_e topic_status_open" style="float: right;">open</span>{{end}}
<span class="username" style="border-right: 0;float: right;">Status</span>
</div>{{end}}
</div>
{{if .Something}}

View File

@ -12,3 +12,4 @@
<body>
<div class="container">
{{template "menu.html" .}}
{{range .NoticeList}}<div class="alert">{{.}}</div>{{end}}

View File

@ -16,15 +16,15 @@
<div class="rowitem"><a>Comments</a></div>
</div>
<div class="colblock_right" style="overflow: hidden;">
{{range $index, $element := .ItemList}}
<div class="rowitem passive deletable_block editable_parent" style="{{ if $element.Avatar }}background-image: url({{$element.Avatar}}), url(/static/white-dot.jpg);background-position: 0px {{if le $element.ContentLines 5}}-1{{end}}0px;background-repeat: no-repeat, repeat-y;background-size: 128px;padding-left: 136px;{{$element.Css}}{{end}}">
<span class="editable_block user_content">{{$element.ContentHtml}}</span>
{{range .ItemList}}
<div class="rowitem passive deletable_block editable_parent" style="{{ if .Avatar }}background-image: url({{.Avatar}}), url(/static/white-dot.jpg);background-position: 0px {{if le .ContentLines 5}}-1{{end}}0px;background-repeat: no-repeat, repeat-y;background-size: 128px;padding-left: 136px;{{.Css}}{{end}}">
<span class="editable_block user_content">{{.ContentHtml}}</span>
<br /><br />
<a href="/user/{{$element.CreatedBy}}" class="username">{{$element.CreatedByName}}</a>
{{if $.CurrentUser.Is_Mod}}<a href="/profile/reply/edit/submit/{{$element.ID}}"><button class="username edit_item">Edit</button></a>
<a href="/profile/reply/delete/submit/{{$element.ID}}"><button class="username delete_item">Delete</button></a>{{end}}
<a href="/report/submit/{{$element.ID}}?session={{$.CurrentUser.Session}}&type=user-reply"><button class="username report_item">Report</button></a>
{{ if $element.Tag }}<a class="username" style="float: right;">{{$element.Tag}}</a>{{end}}
<a href="/user/{{.CreatedBy}}" class="username">{{.CreatedByName}}</a>
{{if $.CurrentUser.Is_Mod}}<a href="/profile/reply/edit/submit/{{.ID}}"><button class="username edit_item">Edit</button></a>
<a href="/profile/reply/delete/submit/{{.ID}}"><button class="username delete_item">Delete</button></a>{{end}}
<a href="/report/submit/{{.ID}}?session={{$.CurrentUser.Session}}&type=user-reply"><button class="username report_item">Report</button></a>
{{ if .Tag }}<a class="username" style="float: right;">{{.Tag}}</a>{{end}}
</div>{{end}}
</div>
{{if not .CurrentUser.Is_Banned}}

View File

@ -8,6 +8,10 @@
<div class="formitem"><a>Account Name</a></div>
<div class="formitem"><input name="username" type="text" placeholder="Account Name" /></div>
</div>
<div class="formrow">
<div class="formitem"><a>Email</a></div>
<div class="formitem"><input name="email" type="email" placeholder="joe.doe@example.com" /></div>
</div>
<div class="formrow">
<div class="formitem"><a>Password</a></div>
<div class="formitem"><input name="password" type="password" autocomplete="new-password" placeholder="*****" /></div>

View File

@ -32,16 +32,16 @@
</div>
</div><br />
<div class="rowblock" style="overflow: hidden;">
{{range $index, $element := .ItemList}}
<div class="rowitem passive deletable_block editable_parent" style="{{ if $element.Avatar }}background-image: url({{$element.Avatar}}), url(/static/white-dot.jpg);background-position: 0px {{if le $element.ContentLines 5}}-1{{end}}0px;background-repeat: no-repeat, repeat-y;background-size: 128px;padding-left: 136px;{{$element.Css}}{{end}}">
<span class="editable_block user_content">{{$element.ContentHtml}}</span>
{{range .ItemList}}
<div class="rowitem passive deletable_block editable_parent" style="{{ if .Avatar }}background-image: url({{.Avatar}}), url(/static/white-dot.jpg);background-position: 0px {{if le .ContentLines 5}}-1{{end}}0px;background-repeat: no-repeat, repeat-y;background-size: 128px;padding-left: 136px;{{.Css}}{{end}}">
<span class="editable_block user_content">{{.ContentHtml}}</span>
<br /><br />
<a href="/user/{{$element.CreatedBy}}" class="username">{{$element.CreatedByName}}</a>
{{if $.CurrentUser.Is_Mod}}<a href="/reply/edit/submit/{{$element.ID}}"><button class="username edit_item">Edit</button></a>
<a href="/reply/delete/submit/{{$element.ID}}"><button class="username delete_item">Delete</button></a>{{end}}
<a href="/report/submit/{{$element.ID}}?session={{$.CurrentUser.Session}}&type=reply"><button class="username report_item">Report</button></a>
{{if $element.Tag}}<a class="username" style="float: right;">{{$element.Tag}}</a>{{else if $element.URLName}}<a href="{{$element.URL}}" class="username" style="color: #505050;float: right;" rel="nofollow">{{$element.URLName}}</a>
<a class="username" style="color: #505050;float: right;border-right: 0;">{{$element.URLPrefix}}</a>{{end}}
<a href="/user/{{.CreatedBy}}" class="username">{{.CreatedByName}}</a>
{{if $.CurrentUser.Is_Mod}}<a href="/reply/edit/submit/{{.ID}}"><button class="username edit_item">Edit</button></a>
<a href="/reply/delete/submit/{{.ID}}"><button class="username delete_item">Delete</button></a>{{end}}
<a href="/report/submit/{{.ID}}?session={{$.CurrentUser.Session}}&type=reply"><button class="username report_item">Report</button></a>
{{if .Tag}}<a class="username" style="float: right;">{{.Tag}}</a>{{else if .URLName}}<a href="{{.URL}}" class="username" style="color: #505050;float: right;" rel="nofollow">{{.URLName}}</a>
<a class="username" style="color: #505050;float: right;border-right: 0;">{{.URLPrefix}}</a>{{end}}
</div>{{end}}
</div>
{{if not .CurrentUser.Is_Banned}}

74
user.go
View File

@ -1,5 +1,5 @@
package main
import "log"
//import "log"
import "strings"
import "strconv"
import "net/http"
@ -46,35 +46,81 @@ func SetPassword(uid int, password string) (error) {
return nil
}
func SessionCheck(w http.ResponseWriter, r *http.Request) (User) {
user := User{0,"",0,false,false,false,false,false,false,"",false,"","","","",""}
var err error
var cookie *http.Cookie
func SessionCheck(w http.ResponseWriter, r *http.Request) (user User, noticeList map[int]string, success bool) {
// Are there any session cookies..?
// Assign it to user.name to avoid having to create a temporary variable for the type conversion
cookie, err = r.Cookie("uid")
cookie, err := r.Cookie("uid")
if err != nil {
return user
return user, noticeList, true
}
user.Name = cookie.Value
user.ID, err = strconv.Atoi(user.Name)
if err != nil {
return user
return user, noticeList, true
}
cookie, err = r.Cookie("session")
if err != nil {
return user
return user, noticeList, true
}
user.Session = cookie.Value
// Is this session valid..?
err = get_session_stmt.QueryRow(user.ID,user.Session).Scan(&user.ID, &user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName)
if err == sql.ErrNoRows {
return user
return user, noticeList, true
} else if err != nil {
log.Print(err)
return user
InternalError(err,w,r,user)
return user, noticeList, false
}
user.Is_Admin = user.Is_Super_Admin || groups[user.Group].Is_Admin
user.Is_Super_Mod = groups[user.Group].Is_Mod || user.Is_Admin
user.Is_Mod = user.Is_Super_Mod
user.Is_Banned = groups[user.Group].Is_Banned
user.Loggedin = !user.Is_Banned || user.Is_Super_Mod
if user.Is_Banned && user.Is_Super_Mod {
user.Is_Banned = false
}
if user.Is_Banned {
noticeList[0] = "You have been banned. Your ability to post has been revoked."
}
if user.Avatar != "" {
if user.Avatar[0] == '.' {
user.Avatar = "/uploads/avatar_" + strconv.Itoa(user.ID) + user.Avatar
}
} else {
user.Avatar = strings.Replace(noavatar,"{id}",strconv.Itoa(user.ID),1)
}
return user, noticeList, true
}
func SimpleSessionCheck(w http.ResponseWriter, r *http.Request) (user User, success bool) {
// Are there any session cookies..?
// Assign it to user.name to avoid having to create a temporary variable for the type conversion
cookie, err := r.Cookie("uid")
if err != nil {
return user, true
}
user.Name = cookie.Value
user.ID, err = strconv.Atoi(user.Name)
if err != nil {
return user, true
}
cookie, err = r.Cookie("session")
if err != nil {
return user, true
}
user.Session = cookie.Value
// Is this session valid..?
err = get_session_stmt.QueryRow(user.ID,user.Session).Scan(&user.ID, &user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName)
if err == sql.ErrNoRows {
return user, true
} else if err != nil {
InternalError(err,w,r,user)
return user, false
}
user.Is_Admin = user.Is_Super_Admin || groups[user.Group].Is_Admin
@ -93,5 +139,5 @@ func SessionCheck(w http.ResponseWriter, r *http.Request) (User) {
} else {
user.Avatar = strings.Replace(noavatar,"{id}",strconv.Itoa(user.ID),1)
}
return user
return user, true
}