Added the BBCode plugin.

Restructured the plugin system.
Multiple plugins can bind to the same hook now (not available for variadic hooks yet!)
The parser is now benchmarked. The bench_round4 is run with both plugin_markdown and plugin_bbcode enabled.
Added a benchmark for the BBCode plugin.
Moved some of the template writing logic into a more generalised function.
URLs are now recognised by the system and linked.
Converted more custom errors into LocalError calls.
Faster and less bandwidth intensive Emojis on Edge.
Fixed a bug with replies not working.
This commit is contained in:
Azareal 2017-01-05 14:41:14 +00:00
parent 33c2f4ccb0
commit e90d96961f
20 changed files with 406 additions and 212 deletions

View File

@ -2,8 +2,8 @@
package main
import "log"
var plugins map[string]Plugin = make(map[string]Plugin)
var hooks map[string]func(interface{})interface{} = make(map[string]func(interface{})interface{})
var plugins map[string]*Plugin = make(map[string]*Plugin)
var hooks map[string][]func(interface{})interface{} = make(map[string][]func(interface{})interface{})
var vhooks map[string]func(...interface{})interface{} = make(map[string]func(...interface{})interface{})
type Plugin struct
@ -19,11 +19,64 @@ type Plugin struct
Init func()
Activate func()error
Deactivate func()
Hooks map[string]int
}
/*func add_hook(name string, handler func(interface{})interface{}) {
hooks[name] = handler
}*/
func NewPlugin(uname string, name string, author string, url string, settings string, tag string, ptype string, init func(), activate func()error, deactivate func()) *Plugin {
return &Plugin{
UName: uname,
Name: name,
Author: author,
URL: url,
Settings: settings,
Tag: tag,
Type: ptype,
Init: init,
Activate: activate,
Deactivate: deactivate,
/*
The Active field should never be altered by 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.
*/
Active: false,
Hooks: make(map[string]int),
}
}
func (plugin *Plugin) AddHook(name string, handler interface{}) {
switch h := handler.(type) {
case func(interface{})interface{}:
if len(hooks[name]) == 0 {
var hookSlice []func(interface{})interface{}
hookSlice = append(hookSlice, h)
hooks[name] = hookSlice
} else {
hooks[name] = append(hooks[name], h)
}
plugin.Hooks[name] = len(hooks[name])
case func(...interface{}) interface{}:
vhooks[name] = h
plugin.Hooks[name] = 0
default:
panic("I don't recognise this kind of handler!") // Should this be an error for the plugin instead of a panic()?
}
}
func (plugin *Plugin) RemoveHook(name string, handler interface{}) {
switch handler.(type) {
case func(interface{})interface{}:
key := plugin.Hooks[name]
hook := hooks[name]
hook = append(hook[:key], hook[key + 1:]...)
hooks[name] = hook
case func(...interface{}) interface{}:
delete(vhooks, name)
default:
panic("I don't recognise this kind of handler!") // Should this be an error for the plugin instead of a panic()?
}
delete(plugin.Hooks, name)
}
func init_plugins() {
for name, body := range plugins {
@ -35,27 +88,11 @@ func init_plugins() {
}
}
func add_hook(name string, handler interface{}) {
switch h := handler.(type) {
case func(interface{})interface{}:
hooks[name] = h
case func(...interface{}) interface{}:
vhooks[name] = h
default:
panic("I don't recognise this kind of handler!") // Should this be an error for the plugin instead of a panic()?
}
}
func remove_hook(name string/*, plugin string */) {
delete(hooks, name)
}
func run_hook(name string, data interface{}) interface{} {
return hooks[name](data)
}
func remove_vhook(name string) {
delete(vhooks, name)
for _, hook := range hooks[name] {
data = hook(data)
}
return data
}
func run_vhook(name string, data ...interface{}) interface{} {

View File

@ -714,6 +714,138 @@ func BenchmarkCustomRouter(b *testing.B) {
})
}
func BenchmarkParser(b *testing.B) {
b.ReportAllocs()
b.Run("empty_post", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = parse_message("")
}
})
b.Run("short_post", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = parse_message("Hey everyone, how's it going?")
}
})
b.Run("one_smily", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = parse_message("Hey everyone, how's it going? :)")
}
})
b.Run("five_smilies", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = parse_message("Hey everyone, how's it going? :):):):):)")
}
})
b.Run("ten_smilies", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = parse_message("Hey everyone, how's it going? :):):):):):):):):):)")
}
})
b.Run("twenty_smilies", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = parse_message("Hey everyone, how's it going? :):):):):):):):):):):):):):):):):):):):)")
}
})
}
func BenchmarkBBCodePluginWithRegexp(b *testing.B) {
b.ReportAllocs()
b.Run("empty_post", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = bbcode_parse("")
}
})
b.Run("short_post", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = bbcode_parse("Hey everyone, how's it going?")
}
})
b.Run("one_smily", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = bbcode_parse("Hey everyone, how's it going? :)")
}
})
b.Run("five_smilies", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = bbcode_parse("Hey everyone, how's it going? :):):):):)")
}
})
b.Run("ten_smilies", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = bbcode_parse("Hey everyone, how's it going? :):):):):):):):):):)")
}
})
b.Run("twenty_smilies", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = bbcode_parse("Hey everyone, how's it going? :):):):):):):):):):):):):):):):):):):):)")
}
})
b.Run("one_bold", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = bbcode_parse("[b]H[/b]ey everyone, how's it going?")
}
})
b.Run("five_bold", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = bbcode_parse("[b]H[/b][b]e[/b][b]y[/b] [b]e[/b][b]v[/b]eryone, how's it going?")
}
})
b.Run("ten_bold", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = bbcode_parse("[b]H[/b][b]e[/b][b]y[/b] [b]e[/b][b]v[/b][b]e[/b][b]r[/b][b]y[/b][b]o[/b][b]n[/b]e, how's it going?")
}
})
}
func BenchmarkBBCodePluginWithCustomParser(b *testing.B) {
b.ReportAllocs()
b.Run("empty_post", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = bbcode_parse2("")
}
})
b.Run("short_post", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = bbcode_parse2("Hey everyone, how's it going?")
}
})
b.Run("one_smily", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = bbcode_parse2("Hey everyone, how's it going? :)")
}
})
b.Run("five_smilies", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = bbcode_parse2("Hey everyone, how's it going? :):):):):)")
}
})
b.Run("ten_smilies", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = bbcode_parse2("Hey everyone, how's it going? :):):):):):):):):):)")
}
})
b.Run("twenty_smilies", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = bbcode_parse2("Hey everyone, how's it going? :):):):):):):):):):):):):):):):):):):):)")
}
})
b.Run("one_bold", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = bbcode_parse2("[b]H[/b]ey everyone, how's it going?")
}
})
b.Run("five_bold", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = bbcode_parse2("[b]H[/b][b]e[/b][b]y[/b] [b]e[/b][b]v[/b]eryone, how's it going?")
}
})
b.Run("ten_bold", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = bbcode_parse2("[b]H[/b][b]e[/b][b]y[/b] [b]e[/b][b]v[/b][b]e[/b][b]r[/b][b]y[/b][b]o[/b][b]n[/b]e, how's it going?")
}
})
}
/*func TestRoute(t *testing.T) {
}*/

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

BIN
images/bench_round4.PNG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

93
main.go
View File

@ -33,7 +33,6 @@ var forums map[int]Forum = make(map[int]Forum)
var static_files map[string]SFile = make(map[string]SFile)
var template_topic_handle func(TopicPage,io.Writer) = nil
var template_topic_origin_handle func(TopicPage,io.Writer) = nil
var template_topic_alt_handle func(TopicPage,io.Writer) = nil
var template_topics_handle func(TopicsPage,io.Writer) = nil
var template_forum_handle func(ForumPage,io.Writer) = nil
@ -75,7 +74,6 @@ func compile_templates() {
topicList = append(topicList, TopicUser{1,"Topic Title","The topic content.",1,false,false,"",1,"open","Admin","","",0,"","","",""})
topics_page := TopicsPage{"Topic List",user,noticeList,topicList,""}
topics_tmpl := c.compile_template("topics.html","templates/","TopicsPage", topics_page, varList)
//topics_tmpl := c.compile_template("topics.html","templates/","Page", pi, varList)
forum_page := ForumPage{"General Forum",user,noticeList,topicList,"There aren't any topics in this forum yet."}
forum_tmpl := c.compile_template("forum.html","templates/","ForumPage", forum_page, varList)
@ -90,17 +88,7 @@ func compile_templates() {
}
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()
write_file("./template_" + name + ".go", content)
}
func main(){
@ -137,84 +125,8 @@ func main(){
init_plugins()
// In a directory to stop it clashing with the other paths
/*http.HandleFunc("/static/", route_static)
fs_u := http.FileServer(http.Dir("./uploads"))
http.Handle("/uploads/", http.StripPrefix("/uploads/",fs_u))
http.HandleFunc("/overview/", route_overview)
http.HandleFunc("/topics/create/", route_topic_create)
http.HandleFunc("/topics/", route_topics)
http.HandleFunc("/forums/", route_forums)
http.HandleFunc("/forum/", route_forum)
http.HandleFunc("/topic/create/submit/", route_create_topic)
http.HandleFunc("/topic/", route_topic_id)
http.HandleFunc("/reply/create/", route_create_reply)
//http.HandleFunc("/reply/edit/", route_reply_edit)
//http.HandleFunc("/reply/delete/", route_reply_delete)
http.HandleFunc("/reply/edit/submit/", route_reply_edit_submit)
http.HandleFunc("/reply/delete/submit/", route_reply_delete_submit)
http.HandleFunc("/report/submit/", route_report_submit)
http.HandleFunc("/topic/edit/submit/", route_edit_topic)
http.HandleFunc("/topic/delete/submit/", route_delete_topic)
http.HandleFunc("/topic/stick/submit/", route_stick_topic)
http.HandleFunc("/topic/unstick/submit/", route_unstick_topic)
// Custom Pages
http.HandleFunc("/pages/", route_custom_page)
// Accounts
http.HandleFunc("/accounts/login/", route_login)
http.HandleFunc("/accounts/create/", route_register)
http.HandleFunc("/accounts/logout/", route_logout)
http.HandleFunc("/accounts/login/submit/", route_login_submit)
http.HandleFunc("/accounts/create/submit/", route_register_submit)
//http.HandleFunc("/accounts/list/", route_login) // Redirect /accounts/ and /user/ to here..
//http.HandleFunc("/accounts/create/full/", route_logout)
//http.HandleFunc("/user/edit/", route_logout)
http.HandleFunc("/user/edit/critical/", route_account_own_edit_critical) // Password & Email
http.HandleFunc("/user/edit/critical/submit/", route_account_own_edit_critical_submit)
http.HandleFunc("/user/edit/avatar/", route_account_own_edit_avatar)
http.HandleFunc("/user/edit/avatar/submit/", route_account_own_edit_avatar_submit)
http.HandleFunc("/user/edit/username/", route_account_own_edit_username)
http.HandleFunc("/user/edit/username/submit/", route_account_own_edit_username_submit)
http.HandleFunc("/user/edit/email/token/", route_account_own_edit_email_token_submit)
http.HandleFunc("/user/", route_profile)
http.HandleFunc("/profile/reply/create/", route_profile_reply_create)
http.HandleFunc("/profile/reply/edit/submit/", route_profile_reply_edit_submit)
http.HandleFunc("/profile/reply/delete/submit/", route_profile_reply_delete_submit)
//http.HandleFunc("/user/edit/submit/", route_logout)
http.HandleFunc("/users/ban/", route_ban)
http.HandleFunc("/users/ban/submit/", route_ban_submit)
http.HandleFunc("/users/unban/", route_unban)
http.HandleFunc("/users/activate/", route_activate)
// Admin
http.HandleFunc("/panel/", route_panel)
http.HandleFunc("/panel/forums/", route_panel_forums)
http.HandleFunc("/panel/forums/create/", route_panel_forums_create_submit)
http.HandleFunc("/panel/forums/delete/", route_panel_forums_delete)
http.HandleFunc("/panel/forums/delete/submit/", route_panel_forums_delete_submit)
http.HandleFunc("/panel/forums/edit/submit/", route_panel_forums_edit_submit)
http.HandleFunc("/panel/settings/", route_panel_settings)
http.HandleFunc("/panel/settings/edit/", route_panel_setting)
http.HandleFunc("/panel/settings/edit/submit/", route_panel_setting_edit)
http.HandleFunc("/panel/themes/", route_panel_themes)
http.HandleFunc("/panel/themes/default/", route_panel_themes_default)
http.HandleFunc("/panel/plugins/", route_panel_plugins)
http.HandleFunc("/panel/plugins/activate/", route_panel_plugins_activate)
http.HandleFunc("/panel/plugins/deactivate/", route_panel_plugins_deactivate)
http.HandleFunc("/panel/users/", route_panel_users)
http.HandleFunc("/panel/users/edit/", route_panel_users_edit)
http.HandleFunc("/panel/users/edit/submit/", route_panel_users_edit_submit)
http.HandleFunc("/panel/groups/", route_panel_groups)
http.HandleFunc("/", default_route)*/
router := NewRouter()
router.HandleFunc("/static/", route_static)
router.HandleFunc("/static/", route_static) // In a directory to stop it clashing with the other paths
fs_u := http.FileServer(http.Dir("./uploads"))
router.Handle("/uploads/", http.StripPrefix("/uploads/",fs_u))
@ -295,7 +207,6 @@ func main(){
if server_port == "" {
server_port = "80"
}
//http.ListenAndServe(":" + server_port, nil)
http.ListenAndServe(":" + server_port, router)
} else {
if server_port == "" {

View File

@ -1,6 +1,6 @@
package main
import "strings"
//import "regexp"
import "regexp"
type Page struct
{
@ -71,6 +71,13 @@ type AreYouSure struct
Message string
}
var urlpattern string = `(?s)([ {1}])((http|https|ftp|mailto)*)(:{??)\/\/([\.a-zA-Z\/]+)([ {1}])`
var url_reg *regexp.Regexp
func init() {
url_reg = regexp.MustCompile(urlpattern)
}
func shortcode_to_unicode(msg string) string {
//re := regexp.MustCompile(":(.):")
msg = strings.Replace(msg,":grinning:","😀",-1)
@ -126,6 +133,7 @@ func parse_message(msg string) string {
msg = strings.Replace(msg,":)","😀",-1)
msg = strings.Replace(msg,":D","😃",-1)
msg = strings.Replace(msg,":P","😛",-1)
msg = url_reg.ReplaceAllString(msg,"<a href=\"$2$3//$4\" rel=\"nofollow\">$2$3//$4</a>")
msg = strings.Replace(msg,"\n","<br>",-1)
if hooks["parse_assign"] != nil {
out := run_hook("parse_assign", msg)

110
plugin_bbcode.go Normal file
View File

@ -0,0 +1,110 @@
package main
//import "log"
//import "fmt"
import "regexp"
var bbcode_bold *regexp.Regexp
var bbcode_italic *regexp.Regexp
var bbcode_underline *regexp.Regexp
var bbcode_url *regexp.Regexp
var bbcode_url_label *regexp.Regexp
func init() {
plugins["bbcode"] = NewPlugin("bbcode","BBCode","Azareal","http://github.com/Azareal","","","",init_bbcode,nil,deactivate_bbcode)
}
func init_bbcode() {
plugins["bbcode"].AddHook("parse_assign", bbcode_parse2)
bbcode_bold = regexp.MustCompile(`(?s)\[b\](.*)\[/b\]`)
bbcode_italic = regexp.MustCompile(`(?s)\[i\](.*)\[/i\]`)
bbcode_underline = regexp.MustCompile(`(?s)\[u\](.*)\[/u\]`)
urlpattern := `(http|https|ftp|mailto*)(:??)\/\/([\.a-zA-Z\/]+)`
bbcode_url = regexp.MustCompile(`\[url\]` + urlpattern + `\[/url\]`)
bbcode_url_label = regexp.MustCompile(`(?s)\[url=` + urlpattern + `\](.*)\[/url\]`)
}
func deactivate_bbcode() {
plugins["bbcode"].RemoveHook("parse_assign", bbcode_parse2)
}
func bbcode_parse(data interface{}) interface{} {
msg := data.(string)
msg = bbcode_bold.ReplaceAllString(msg,"<b>$1</b>")
msg = bbcode_italic.ReplaceAllString(msg,"<i>$1</i>")
msg = bbcode_url.ReplaceAllString(msg,"<a href=\"$1$2//$3\" rel=\"nofollow\">$1$2//$3</i>")
msg = bbcode_url_label.ReplaceAllString(msg,"<a href=\"$1$2//$3\" rel=\"nofollow\">$4</i>")
return msg
}
func bbcode_parse2(data interface{}) interface{} {
msg := data.(string)
msgbytes := []byte(msg)
has_u := false
has_b := false
has_i := false
complex_bbc := false
for i := 0; i < len(msgbytes); i++ {
//log.Print(msgbytes[i])
//fmt.Println(string(msgbytes[i]))
//continue
if msgbytes[i] == '[' {
if msgbytes[i + 2] != ']' {
if msgbytes[i + 1] == '/' {
if msgbytes[i + 3] == ']' {
if msgbytes[i + 2] == 'u' {
msgbytes[i] = '<'
msgbytes[i + 3] = '>'
has_u = false
}
if msgbytes[i + 2] == 'b' {
msgbytes[i] = '<'
msgbytes[i + 3] = '>'
has_b = false
}
if msgbytes[i + 2] == 'i' {
msgbytes[i] = '<'
msgbytes[i + 3] = '>'
has_i = false
}
i += 3
} else {
complex_bbc = true
}
} else {
complex_bbc = true
}
} else {
if msgbytes[i + 1] == 'u' {
msgbytes[i] = '<'
msgbytes[i + 2] = '>'
has_u = true
}
if msgbytes[i + 1] == 'b' {
msgbytes[i] = '<'
msgbytes[i + 2] = '>'
has_b = true
}
if msgbytes[i + 1] == 'i' {
msgbytes[i] = '<'
msgbytes[i + 2] = '>'
has_i = true
}
i += 2
}
}
}
// There's an unclosed tag in there x.x
if has_i || has_u || has_b {
closer := []byte("</u></i></b>")
msgbytes = append(msgbytes, closer...)
}
msg = string(msgbytes)
//fmt.Println(msg)
if complex_bbc {
msg = bbcode_url.ReplaceAllString(msg,"<a href=\"$1$2//$3\" rel=\"nofollow\">$1$2//$3</i>")
msg = bbcode_url_label.ReplaceAllString(msg,"<a href=\"$1$2//$3\" rel=\"nofollow\">$4</i>")
}
return msg
}

View File

@ -2,16 +2,16 @@ 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"] = NewPlugin("helloworld","Hello World","Azareal","http://github.com/Azareal","","","",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
func init_helloworld() {
add_hook("rrow_assign", helloworld_reply)
plugins["helloworld"].AddHook("rrow_assign", helloworld_reply)
}
func deactivate_helloworld() {
remove_hook("rrow_assign")
plugins["helloworld"].RemoveHook("rrow_assign", helloworld_reply)
}
func helloworld_reply(data interface{}) interface{} {

View File

@ -1,30 +1,29 @@
package main
import "regexp"
var bold_italic *regexp.Regexp
var bold *regexp.Regexp
var italic *regexp.Regexp
var markdown_bold_italic *regexp.Regexp
var markdown_bold *regexp.Regexp
var markdown_italic *regexp.Regexp
func init() {
plugins["markdown"] = Plugin{"markdown","Markdown","Azareal","http://github.com/Azareal","",false,"","",init_markdown,nil,deactivate_markdown}
plugins["markdown"] = NewPlugin("markdown","Markdown","Azareal","http://github.com/Azareal","","","",init_markdown,nil,deactivate_markdown)
}
func init_markdown() {
add_hook("parse_assign", markdown_parse)
bold_italic = regexp.MustCompile(`\*\*\*(.*)\*\*\*`)
bold = regexp.MustCompile(`\*\*(.*)\*\*`)
italic = regexp.MustCompile(`\*(.*)\*`)
plugins["markdown"].AddHook("parse_assign", markdown_parse)
markdown_bold_italic = regexp.MustCompile(`\*\*\*(.*)\*\*\*`)
markdown_bold = regexp.MustCompile(`\*\*(.*)\*\*`)
markdown_italic = regexp.MustCompile(`\*(.*)\*`)
}
func deactivate_markdown() {
remove_hook("parse_assign")
plugins["markdown"].RemoveHook("parse_assign", markdown_parse)
}
func markdown_parse(data interface{}) interface{} {
msg := data.(string)
msg = bold_italic.ReplaceAllString(msg,"<i><b>$1</b></i>")
msg = bold.ReplaceAllString(msg,"<b>$1</b>")
msg = italic.ReplaceAllString(msg,"<i>$1</i>")
msg = markdown_bold_italic.ReplaceAllString(msg,"<i><b>$1</b></i>")
msg = markdown_bold.ReplaceAllString(msg,"<b>$1</b>")
msg = markdown_italic.ReplaceAllString(msg,"<i>$1</i>")
return msg
}

View File

@ -12,8 +12,6 @@ func init() {
The Settings field points to the route for managing the settings for this plugin. Coming soon.
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 "".
@ -24,7 +22,7 @@ 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"] = NewPlugin("skeleton","Skeleton","Azareal","","","","",init_skeleton, activate_skeleton, deactivate_skeleton)
}
func init_skeleton() {}

View File

@ -605,20 +605,9 @@ func route_create_reply(w http.ResponseWriter, r *http.Request) {
return
}
success := 1
tid, err := strconv.Atoi(r.PostFormValue("tid"))
if err != nil {
log.Print(err)
success = 0
errmsg := "Unable to create the reply"
pi := Page{"Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
errpage := b.String()
w.WriteHeader(500)
fmt.Fprintln(w,errpage)
LocalError("Failed to convert the TopicID", w, r, user)
return
}
@ -626,15 +615,15 @@ func route_create_reply(w http.ResponseWriter, r *http.Request) {
log.Print(content)
_, err = create_reply_stmt.Exec(tid,content,parse_message(content),user.ID)
if err != nil {
log.Print(err)
success = 0
InternalError(err,w,r,user)
return
}
var topic_name string
err = db.QueryRow("select title from topics where tid = ?", tid).Scan(&topic_name)
if err == sql.ErrNoRows {
log.Print(err)
success = 0
LocalError("Couldn't find the parent topic", w, r, user)
return
} else if err != nil {
InternalError(err,w,r,user)
return
@ -646,18 +635,7 @@ func route_create_reply(w http.ResponseWriter, r *http.Request) {
return
}
if success != 1 {
errmsg := "Unable to create the reply"
pi := Page{"Error","error",user,nList,tList,errmsg}
var b bytes.Buffer
templates.ExecuteTemplate(&b,"error.html", pi)
errpage := b.String()
w.WriteHeader(500)
fmt.Fprintln(w,errpage)
} else {
http.Redirect(w, r, "/topic/" + strconv.Itoa(tid), http.StatusSeeOther)
}
http.Redirect(w, r, "/topic/" + strconv.Itoa(tid), http.StatusSeeOther)
}
func route_profile_reply_create(w http.ResponseWriter, r *http.Request) {

View File

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

View File

@ -130,19 +130,19 @@ w.Write([]byte(`
<div class="the_name" style="margin-top: 3px;text-align: center;color: #505050;">` + item.CreatedByName + `</div>
</div>
<div class="content_container" style="background: white;margin-left: 137px;min-height: 128px;margin-bottom: 0;margin-right: 3px;box-shadow:0 1px 2px rgba(0,0,0,.1);">
<div class="editable_block user_content" style="padding: 5px;margin-top: 3px;margin-bottom: 0;background: white;min-height: 133px;padding-bottom: 0;width: 100%;">` + string(item.ContentHtml) + `</div>
<div class="button_container" style="border-top: solid 1px #eaeaea;border-spacing: 0px;border-collapse: collapse;padding: 0;margin: 0;display: block;">
<div class="editable_block user_content">` + string(item.ContentHtml) + `</div>
<div class="button_container">
`))
if tmpl_topic_alt_vars.CurrentUser.Perms.EditReply {
w.Write([]byte(`<a href="/reply/edit/submit/` + strconv.Itoa(item.ID) + `" style="border-right: solid 1px #eaeaea;color: #505050;font-size: 13px;padding-left: 5px;padding-right: 5px;">Edit</a>`))
w.Write([]byte(`<a href="/reply/edit/submit/` + strconv.Itoa(item.ID) + `" class="action_button">Edit</a>`))
}
w.Write([]byte(`
`))
if tmpl_topic_alt_vars.CurrentUser.Perms.DeleteReply {
w.Write([]byte(`<a href="/reply/delete/submit/` + strconv.Itoa(item.ID) + `" style="border-right: solid 1px #eaeaea;color: #505050;font-size: 13px;padding-left: 0;padding-right: 5px;">Delete</a>`))
w.Write([]byte(`<a href="/reply/delete/submit/` + strconv.Itoa(item.ID) + `" class="action_button">Delete</a>`))
}
w.Write([]byte(`
<a href="/report/submit/` + strconv.Itoa(item.ID) + `?session=` + tmpl_topic_alt_vars.CurrentUser.Session + `&type=reply" style="border: none;border-right: solid 1px #eaeaea;padding-right: 6px;color: #505050;font-size: 13px;">Report</a>
<a href="/report/submit/` + strconv.Itoa(item.ID) + `?session=` + tmpl_topic_alt_vars.CurrentUser.Session + `&type=reply" class="action_button">Report</a>
</div>
</div>
</div>

View File

@ -1,6 +1,6 @@
{{template "header.html" . }}
<div class="rowblock">
<div class="rowitem"><a>{{ .Title }}</a></div>
<div class="rowitem"><a>{{.Title}}</a></div>
</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;{{else if .Is_Closed}}background-color: #eaeaea;{{end}}">

View File

@ -1,9 +1 @@
<!doctype html>
<html lang="en">
<head>
{{template "header.html" . }}
</head>
<body>
</body>
</html>
{{template "header.html" . }}{{template "$page_name" . }}{{template "footer.html" . }}

View File

@ -40,11 +40,11 @@
<div class="the_name" style="margin-top: 3px;text-align: center;color: #505050;">{{.CreatedByName}}</div>
</div>
<div class="content_container" style="background: white;margin-left: 137px;min-height: 128px;margin-bottom: 0;margin-right: 3px;box-shadow:0 1px 2px rgba(0,0,0,.1);">
<div class="editable_block user_content" style="padding: 5px;margin-top: 3px;margin-bottom: 0;background: white;min-height: 133px;padding-bottom: 0;width: 100%;">{{.ContentHtml}}</div>
<div class="button_container" style="border-top: solid 1px #eaeaea;border-spacing: 0px;border-collapse: collapse;padding: 0;margin: 0;display: block;">
{{if $.CurrentUser.Perms.EditReply}}<a href="/reply/edit/submit/{{.ID}}" style="border-right: solid 1px #eaeaea;color: #505050;font-size: 13px;padding-left: 5px;padding-right: 5px;">Edit</a>{{end}}
{{if $.CurrentUser.Perms.DeleteReply}}<a href="/reply/delete/submit/{{.ID}}" style="border-right: solid 1px #eaeaea;color: #505050;font-size: 13px;padding-left: 0;padding-right: 5px;">Delete</a>{{end}}
<a href="/report/submit/{{.ID}}?session={{$.CurrentUser.Session}}&type=reply" style="border: none;border-right: solid 1px #eaeaea;padding-right: 6px;color: #505050;font-size: 13px;">Report</a>
<div class="editable_block user_content">{{.ContentHtml}}</div>
<div class="button_container">
{{if $.CurrentUser.Perms.EditReply}}<a href="/reply/edit/submit/{{.ID}}" class="action_button">Edit</a>{{end}}
{{if $.CurrentUser.Perms.DeleteReply}}<a href="/reply/delete/submit/{{.ID}}" class="action_button">Delete</a>{{end}}
<a href="/report/submit/{{.ID}}?session={{$.CurrentUser.Session}}&type=reply" class="action_button">Report</a>
</div>
</div>
</div>

View File

@ -9,22 +9,11 @@ body
font-family: arial;
}
@font-face {
font-family: 'EmojiFont';
src: url('https://github.com/Ranks/emojione/raw/master/assets/fonts/emojione-svg.woff2') format('woff2'),
url('https://github.com/Ranks/emojione/raw/master/assets/fonts/emojione-svg.woff') format('woff'), local("arial");
}
/* Patch for Edge */
@supports (-ms-ime-align:auto) {
.user_content
{
font-family: EmojiFont, arial;
}
}
@-moz-document url-prefix() {
.user_content
{
font-family: EmojiFont, arial;
font-family: Segoe UI Emoji, arial;
}
}
@ -330,6 +319,41 @@ button.username
background-color: #FEB7CC;
}
/* Tempra Conflux */
.user_content {
padding: 5px;
margin-top: 3px;
margin-bottom: 0;
background: white;
min-height: 129px;
padding-bottom: 0;
width: 100%;
}
.button_container {
border-top: solid 1px #eaeaea;
border-spacing: 0px;
border-collapse: collapse;
padding: 0;
margin: 0;
margin-top: 3px;
display: block;
height: 20px;
}
.action_button {
display: block;
float: left;
border-right: solid 1px #eaeaea;
color: #505050;
font-size: 13px;
padding-top: 2px;
padding-bottom: 2px;
padding-left: 5px;
padding-right: 5px;
}
/* Media Queries from Simple. Probably useless in Conflux */
@media (max-width: 880px) {
li
{

View File

@ -9,22 +9,11 @@ body
font-family: arial;
}
@font-face {
font-family: 'EmojiFont';
src: url('https://github.com/Ranks/emojione/raw/master/assets/fonts/emojione-svg.woff2') format('woff2'),
url('https://github.com/Ranks/emojione/raw/master/assets/fonts/emojione-svg.woff') format('woff'), local("arial");
}
/* Patch for Edge */
@supports (-ms-ime-align:auto) {
.user_content
{
font-family: EmojiFont, arial;
}
}
@-moz-document url-prefix() {
.user_content
{
font-family: EmojiFont, arial;
font-family: Segoe UI Emoji, arial;
}
}

View File

@ -154,7 +154,7 @@ func SimpleSessionCheck(w http.ResponseWriter, r *http.Request) (user User, succ
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)
err = get_session_stmt.QueryRow(user.ID,user.Session).Scan(&user.ID, &user.Name, &user.Group, &user.Is_Super_Admin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName)
if err == sql.ErrNoRows {
user.ID = 0
user.Session = ""

View File

@ -1,6 +1,8 @@
package main
import "log"
import "fmt"
import "time"
import "os"
import "encoding/base64"
import "crypto/rand"
import "net/smtp"
@ -87,3 +89,17 @@ func SendEmail(email string, subject string, msg string) bool {
}
return true
}
func write_file(name string, content string) {
f, err := os.Create(name)
if err != nil {
log.Fatal(err)
}
_, err = f.WriteString(content)
if err != nil {
log.Fatal(err)
}
f.Sync()
f.Close()
}