Added a custom router which is twice as fast as the old one.
Added support for SSL. Added the email system. Not fully tested. Added Email Verification. Added the Emails Page in the Account Manager. Email Activation is now fully supported. Fixed CustomErrorJSQ() and added CustomError(). Added commented out tests for Vestigo. Added tests for the new (possibly temporary) custom router. Swapped some of the custom error blocks for the Account Manager with LocalError calls. Moved the account menu into it's own template.
This commit is contained in:
parent
1b18ab523c
commit
33c2f4ccb0
38
README.md
38
README.md
|
@ -8,13 +8,13 @@ Discord Server: https://discord.gg/eyYvtTf
|
|||
|
||||
|
||||
# Features
|
||||
Basic Forum Functionality
|
||||
Basic Forum Functionality. All of the little things you would expect of any forum software. E.g. Moderation, Custom Themes, Avatars, and so on.
|
||||
|
||||
Custom Pages. Under development.
|
||||
Custom Pages. Under development. Mainly the Control Panel portion to come, but you can create them by hand today.
|
||||
|
||||
Emojis
|
||||
Emojis. Allow your users to express themselves without resorting to serving tons upon tons of image files.
|
||||
|
||||
In-memory static file, forum and group caches.
|
||||
In-memory static file, forum and group caches. We're pondering over extending this solution over to topics, users, etc. to some extent.
|
||||
|
||||
A profile system including profile comments and moderation tools for the profile owner.
|
||||
|
||||
|
@ -22,7 +22,7 @@ A template engine which compiles templates down into machine code. Over ten time
|
|||
|
||||
A plugin system. Under development.
|
||||
|
||||
A responsive design. Looks good on mobile phones, tablets, laptops, desktops and more!
|
||||
A responsive design. Looks great on mobile phones, tablets, laptops, desktops and more!
|
||||
|
||||
|
||||
# Dependencies
|
||||
|
@ -38,19 +38,15 @@ Instructions on how to do so on Linux: https://downloads.mariadb.org/mariadb/rep
|
|||
|
||||
**Run the following commands:**
|
||||
|
||||
go get github.com/go-sql-driver/mysql
|
||||
go get -u github.com/go-sql-driver/mysql
|
||||
|
||||
go install github.com/go-sql-driver/mysql
|
||||
|
||||
go get golang.org/x/crypto/bcrypt
|
||||
|
||||
go install golang.org/x/crypto/bcrypt
|
||||
go get -u golang.org/x/crypto/bcrypt
|
||||
|
||||
Tweak the config.go file and put your database details in there. Import data.sql into the same database. Comment out the first line (put /* and */ around it), if you've already made a database, and don't want the script to generate it for you.
|
||||
|
||||
Set the password column of your user account in the database to what you want your password to be. The system will encrypt your password when you login for the first time.
|
||||
|
||||
Add -u after go get to update those libraries, if you've already got them installed.
|
||||
You can run these commands again at any time to update these dependencies to their latest versions.
|
||||
|
||||
# Run the program
|
||||
|
||||
|
@ -67,7 +63,7 @@ go build
|
|||
|
||||
Open up cmd.exe
|
||||
|
||||
cd to the directory / folder the code is in. E.g. cd /Users/Blah/Documents/gosora
|
||||
cd to the directory / folder the code is in. E.g. `cd /Users/Blah/Documents/gosora`
|
||||
|
||||
go build
|
||||
|
||||
|
@ -101,9 +97,11 @@ We're looking for ways to clean-up the plugin system so that all of them (except
|
|||
Oh my, you caught me right at the start of this project. There's nothing to see here yet, asides from the absolute basics. You might want to look again later!
|
||||
|
||||
|
||||
More moderation features.
|
||||
The various little features which somehow got stuck in the net. Don't worry, I'll get to them!
|
||||
|
||||
Add a simple anti-spam measure.
|
||||
More moderation features. E.g. Move, Approval Queue (Posts made by users in certain usergroups will need to be approved by a moderator before they're publically visible), etc.
|
||||
|
||||
Add a simple anti-spam measure. I have quite a few ideas in mind, but it'll take a while to implement the more advanced ones, so I'd like to put off some of those to a later date and focus on the basics. E.g. CAPTCHAs, hidden fields, etc.
|
||||
|
||||
Add an alert system.
|
||||
|
||||
|
@ -111,12 +109,18 @@ Add per-forum permissions to finish up the foundations of the permissions system
|
|||
|
||||
Add a *better* plugin system. E.g. Allow for plugins written in Javascript and ones written in Go. Also, we need to add many, many, many more plugin hooks.
|
||||
|
||||
Implement a faster router.
|
||||
I will need to ponder over implementing an even faster router. We don't need one immediately, although it would be nice if we could get one in the near future. It really depends. Ideally, it would be one which can easily integrate with the current structure without much work, although I'm not beyond making some alterations to faciliate it, assuming that we don't get too tightly bound to that specific router.
|
||||
|
||||
Allow themes to define their own templates.
|
||||
|
||||
Add a friend system.
|
||||
|
||||
Add more administration features.
|
||||
|
||||
Add more features for improving user engagement.
|
||||
Add more features for improving user engagement. I have quite a few of these in mind, but I'm mostly occupied with implementing the essentials right now.
|
||||
|
||||
Add a widget system.
|
||||
|
||||
Add support for multi-factor authentication.
|
||||
|
||||
Add support for secondary emails for users.
|
||||
|
|
19
config.go
19
config.go
|
@ -12,16 +12,23 @@ var max_request_size = 5 * megabyte
|
|||
|
||||
// Misc
|
||||
var default_route = route_topics
|
||||
var default_group = 3
|
||||
var activation_group = 5
|
||||
var default_group = 3 // Should be a setting
|
||||
var activation_group = 5 // Should be a setting
|
||||
var staff_css = " background-color: #ffeaff;"
|
||||
var uncategorised_forum_visible = true
|
||||
var enable_emails = false
|
||||
var site_email = ""
|
||||
var site_name = "Test Install" // Should be a setting
|
||||
var site_email = "" // Should be a setting
|
||||
var smtp_server = ""
|
||||
var siteurl = "localhost:8080"
|
||||
var noavatar = "https://api.adorable.io/avatars/285/{id}@" + siteurl + ".png"
|
||||
var items_per_page = 50
|
||||
//var noavatar = "https://api.adorable.io/avatars/{width}/{id}@{site_url}.png"
|
||||
var noavatar = "https://api.adorable.io/avatars/285/{id}@" + site_url + ".png"
|
||||
var items_per_page = 40 // Should be a setting
|
||||
|
||||
var site_url = "localhost:8080"
|
||||
var server_port = "8080"
|
||||
var enable_ssl = false
|
||||
var ssl_privkey = ""
|
||||
var ssl_fullchain = ""
|
||||
|
||||
// Developer flag
|
||||
var debug = false
|
8
data.sql
8
data.sql
|
@ -32,6 +32,13 @@ CREATE TABLE `users_groups`(
|
|||
primary key(`gid`)
|
||||
) CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;
|
||||
|
||||
CREATE TABLE `emails`(
|
||||
`email` varchar(200) not null,
|
||||
`uid` int not null,
|
||||
`validated` tinyint DEFAULT 0 not null,
|
||||
`token` varchar(200) DEFAULT '' not null
|
||||
);
|
||||
|
||||
CREATE TABLE `forums`(
|
||||
`fid` int not null AUTO_INCREMENT,
|
||||
`name` varchar(100) not null,
|
||||
|
@ -111,6 +118,7 @@ INSERT INTO themes(`uname`,`default`) VALUES ('tempra-simple',1);
|
|||
|
||||
INSERT INTO users(`name`,`email`,`group`,`is_super_admin`,`createdAt`,`lastActiveAt`,`message`)
|
||||
VALUES ('Admin','admin@localhost',1,1,NOW(),NOW(),'');
|
||||
INSERT INTO emails(`email`,`uid`,`validated`) VALUES ('admin@localhost',1,1);
|
||||
|
||||
/*
|
||||
The Permissions:
|
||||
|
|
13
errors.go
13
errors.go
|
@ -140,15 +140,24 @@ func NotFound(w http.ResponseWriter, r *http.Request, user User) {
|
|||
fmt.Fprintln(w,errpage)
|
||||
}
|
||||
|
||||
func CustomError(errmsg string, errcode int, errtitle string, w http.ResponseWriter, r *http.Request, user User) {
|
||||
pi := Page{errtitle,"error",user,nList,tList,errmsg}
|
||||
var b bytes.Buffer
|
||||
templates.ExecuteTemplate(&b,"error.html", pi)
|
||||
errpage := b.String()
|
||||
w.WriteHeader(errcode)
|
||||
fmt.Fprintln(w,errpage)
|
||||
}
|
||||
|
||||
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,nList,tList,errmsg}
|
||||
var b bytes.Buffer
|
||||
templates.ExecuteTemplate(&b,"error.html", pi)
|
||||
errpage := b.String()
|
||||
w.WriteHeader(500)
|
||||
w.WriteHeader(errcode)
|
||||
fmt.Fprintln(w,errpage)
|
||||
} else {
|
||||
http.Error(w,"{'errmsg': '" + errmsg + "'}",500)
|
||||
http.Error(w,"{'errmsg': '" + errmsg + "'}",errcode)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"dbhost": "127.0.0.1",
|
||||
"dbuser": "root",
|
||||
"dbpassword": "password",
|
||||
"dbname": "gosora",
|
||||
"dbport": "3306",
|
||||
|
||||
"default_group": 3,
|
||||
"activation_group": 5,
|
||||
"staff_css": " background-color: #ffeaff;",
|
||||
"uncategorised_forum_visible": true,
|
||||
"enable_emails": false,
|
||||
"smtp_server": "",
|
||||
"items_per_page": 40,
|
||||
|
||||
"site_url": "localhost:8080",
|
||||
"server_port": "8080",
|
||||
"enable_ssl": false,
|
||||
"ssl_privkey": "",
|
||||
"ssl_fullchain": "",
|
||||
|
||||
"debug": false
|
||||
}
|
335
general_test.go
335
general_test.go
|
@ -1,5 +1,4 @@
|
|||
package main
|
||||
//import "fmt"
|
||||
import "log"
|
||||
import "bytes"
|
||||
import "math/rand"
|
||||
|
@ -8,6 +7,7 @@ import "net/http"
|
|||
import "net/http/httptest"
|
||||
import "io/ioutil"
|
||||
import "html/template"
|
||||
//import "github.com/husobee/vestigo"
|
||||
|
||||
func BenchmarkTopicTemplate(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
@ -107,7 +107,7 @@ func BenchmarkRoute(b *testing.B) {
|
|||
b.ReportAllocs()
|
||||
|
||||
admin_uid_cookie := http.Cookie{Name: "uid",Value: "1",Path: "/",MaxAge: year}
|
||||
// TO-DO: Stop hard-coding this value
|
||||
// TO-DO: Stop hard-coding this value. Seriously.
|
||||
admin_session_cookie := http.Cookie{Name: "session",Value: "TKBh5Z-qEQhWDBnV6_XVmOhKAowMYPhHeRlrQjjbNc0QRrRiglvWOYFDc1AaMXQIywvEsyA2AOBRYUrZ5kvnGhThY1GhOW6FSJADnRWm_bI=",Path: "/",MaxAge: year}
|
||||
|
||||
topic_w := httptest.NewRecorder()
|
||||
|
@ -231,7 +231,7 @@ func addEmptyRoutesToMux(routes []string, serveMux *http.ServeMux) {
|
|||
}
|
||||
}
|
||||
|
||||
func BenchmarkRouter(b *testing.B) {
|
||||
func BenchmarkDefaultGoRouter(b *testing.B) {
|
||||
w := httptest.NewRecorder()
|
||||
req := httptest.NewRequest("get","/topics/",bytes.NewReader(nil))
|
||||
routes := make([]string, 0)
|
||||
|
@ -388,5 +388,332 @@ func BenchmarkRouter(b *testing.B) {
|
|||
})
|
||||
}
|
||||
|
||||
/*func TestRoute(t *testing.T) {
|
||||
/*func addEmptyRoutesToVestigo(routes []string, router *vestigo.Router) {
|
||||
for _, route := range routes {
|
||||
router.HandleFunc(route, func(_ http.ResponseWriter,_ *http.Request){})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkVestigoRouter(b *testing.B) {
|
||||
w := httptest.NewRecorder()
|
||||
req := httptest.NewRequest("get","/topics/",bytes.NewReader(nil))
|
||||
routes := make([]string, 0)
|
||||
|
||||
routes = append(routes,"/test/")
|
||||
router := vestigo.NewRouter()
|
||||
router.HandleFunc("/test/", func(_ http.ResponseWriter,_ *http.Request){})
|
||||
b.Run("one-route", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
req = httptest.NewRequest("get",routes[rand.Intn(len(routes))],bytes.NewReader(nil))
|
||||
router.ServeHTTP(w,req)
|
||||
}
|
||||
})
|
||||
|
||||
routes = append(routes,"/topic/")
|
||||
routes = append(routes,"/forums/")
|
||||
routes = append(routes,"/forum/")
|
||||
routes = append(routes,"/panel/")
|
||||
router = vestigo.NewRouter()
|
||||
addEmptyRoutesToVestigo(routes, router)
|
||||
b.Run("five-routes", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
req = httptest.NewRequest("get",routes[rand.Intn(len(routes))],bytes.NewReader(nil))
|
||||
router.ServeHTTP(w,req)
|
||||
}
|
||||
})
|
||||
|
||||
router = vestigo.NewRouter()
|
||||
routes = append(routes,"/panel/plugins/")
|
||||
routes = append(routes,"/panel/groups/")
|
||||
routes = append(routes,"/panel/settings/")
|
||||
routes = append(routes,"/panel/users/")
|
||||
routes = append(routes,"/panel/forums/")
|
||||
addEmptyRoutesToVestigo(routes, router)
|
||||
b.Run("ten-routes", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
req = httptest.NewRequest("get",routes[rand.Intn(len(routes))],bytes.NewReader(nil))
|
||||
router.ServeHTTP(w,req)
|
||||
}
|
||||
})
|
||||
|
||||
router = vestigo.NewRouter()
|
||||
routes = append(routes,"/panel/forums/create/submit/")
|
||||
routes = append(routes,"/panel/forums/delete/")
|
||||
routes = append(routes,"/users/ban/")
|
||||
routes = append(routes,"/panel/users/edit/")
|
||||
routes = append(routes,"/panel/forums/create/")
|
||||
routes = append(routes,"/users/unban/")
|
||||
routes = append(routes,"/pages/")
|
||||
routes = append(routes,"/users/activate/")
|
||||
routes = append(routes,"/panel/forums/edit/submit/")
|
||||
routes = append(routes,"/panel/plugins/activate/")
|
||||
addEmptyRoutesToVestigo(routes, router)
|
||||
b.Run("twenty-routes", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
req = httptest.NewRequest("get",routes[rand.Intn(len(routes))],bytes.NewReader(nil))
|
||||
router.ServeHTTP(w,req)
|
||||
}
|
||||
})
|
||||
|
||||
router = vestigo.NewRouter()
|
||||
routes = append(routes,"/panel/plugins/deactivate/")
|
||||
routes = append(routes,"/panel/plugins/install/")
|
||||
routes = append(routes,"/panel/plugins/uninstall/")
|
||||
routes = append(routes,"/panel/templates/")
|
||||
routes = append(routes,"/panel/templates/edit/")
|
||||
routes = append(routes,"/panel/templates/create/")
|
||||
routes = append(routes,"/panel/templates/delete/")
|
||||
routes = append(routes,"/panel/templates/edit/submit/")
|
||||
routes = append(routes,"/panel/themes/")
|
||||
routes = append(routes,"/panel/themes/edit/")
|
||||
addEmptyRoutesToVestigo(routes, router)
|
||||
b.Run("thirty-routes", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
req = httptest.NewRequest("get",routes[rand.Intn(len(routes))],bytes.NewReader(nil))
|
||||
router.ServeHTTP(w,req)
|
||||
}
|
||||
})
|
||||
|
||||
router = vestigo.NewRouter()
|
||||
routes = append(routes,"/panel/themes/create/")
|
||||
routes = append(routes,"/panel/themes/delete/")
|
||||
routes = append(routes,"/panel/themes/delete/submit/")
|
||||
routes = append(routes,"/panel/templates/create/submit/")
|
||||
routes = append(routes,"/panel/templates/delete/submit/")
|
||||
routes = append(routes,"/panel/widgets/")
|
||||
routes = append(routes,"/panel/widgets/edit/")
|
||||
routes = append(routes,"/panel/widgets/activate/")
|
||||
routes = append(routes,"/panel/widgets/deactivate/")
|
||||
routes = append(routes,"/panel/magical/wombat/path")
|
||||
addEmptyRoutesToVestigo(routes, router)
|
||||
b.Run("forty-routes", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
req = httptest.NewRequest("get",routes[rand.Intn(len(routes))],bytes.NewReader(nil))
|
||||
router.ServeHTTP(w,req)
|
||||
}
|
||||
})
|
||||
|
||||
router = vestigo.NewRouter()
|
||||
routes = append(routes,"/report/")
|
||||
routes = append(routes,"/report/submit/")
|
||||
routes = append(routes,"/topic/create/submit/")
|
||||
routes = append(routes,"/topics/create/")
|
||||
routes = append(routes,"/overview/")
|
||||
routes = append(routes,"/uploads/")
|
||||
routes = append(routes,"/static/")
|
||||
routes = append(routes,"/reply/edit/submit/")
|
||||
routes = append(routes,"/reply/delete/submit/")
|
||||
routes = append(routes,"/topic/edit/submit/")
|
||||
addEmptyRoutesToVestigo(routes, router)
|
||||
b.Run("fifty-routes", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
req = httptest.NewRequest("get",routes[rand.Intn(len(routes))],bytes.NewReader(nil))
|
||||
router.ServeHTTP(w,req)
|
||||
}
|
||||
})
|
||||
|
||||
router = vestigo.NewRouter()
|
||||
routes = append(routes,"/topic/delete/submit/")
|
||||
routes = append(routes,"/topic/stick/submit/")
|
||||
routes = append(routes,"/topic/unstick/submit/")
|
||||
routes = append(routes,"/accounts/login/")
|
||||
routes = append(routes,"/accounts/create/")
|
||||
routes = append(routes,"/accounts/logout/")
|
||||
routes = append(routes,"/accounts/login/submit/")
|
||||
routes = append(routes,"/accounts/create/submit/")
|
||||
routes = append(routes,"/user/edit/critical/")
|
||||
routes = append(routes,"/user/edit/critical/submit/")
|
||||
addEmptyRoutesToVestigo(routes, router)
|
||||
b.Run("sixty-routes", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
req = httptest.NewRequest("get",routes[rand.Intn(len(routes))],bytes.NewReader(nil))
|
||||
router.ServeHTTP(w,req)
|
||||
}
|
||||
})
|
||||
|
||||
router = vestigo.NewRouter()
|
||||
routes = append(routes,"/user/edit/avatar/")
|
||||
routes = append(routes,"/user/edit/avatar/submit/")
|
||||
routes = append(routes,"/user/edit/username/")
|
||||
routes = append(routes,"/user/edit/username/submit/")
|
||||
routes = append(routes,"/profile/reply/create/")
|
||||
routes = append(routes,"/profile/reply/edit/submit/")
|
||||
routes = append(routes,"/profile/reply/delete/submit/")
|
||||
routes = append(routes,"/arcane/tower/")
|
||||
routes = append(routes,"/magical/kingdom/")
|
||||
routes = append(routes,"/insert/name/here/")
|
||||
addEmptyRoutesToVestigo(routes, router)
|
||||
b.Run("seventy-routes", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
req = httptest.NewRequest("get",routes[rand.Intn(len(routes))],bytes.NewReader(nil))
|
||||
router.ServeHTTP(w,req)
|
||||
}
|
||||
})
|
||||
}*/
|
||||
|
||||
func addEmptyRoutesToCustom(routes []string, router *Router) {
|
||||
for _, route := range routes {
|
||||
router.HandleFunc(route, func(_ http.ResponseWriter,_ *http.Request){})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCustomRouter(b *testing.B) {
|
||||
w := httptest.NewRecorder()
|
||||
req := httptest.NewRequest("get","/topics/",bytes.NewReader(nil))
|
||||
routes := make([]string, 0)
|
||||
|
||||
routes = append(routes,"/test/")
|
||||
router := NewRouter()
|
||||
router.HandleFunc("/test/", func(_ http.ResponseWriter,_ *http.Request){})
|
||||
b.Run("one-route", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
req = httptest.NewRequest("get",routes[rand.Intn(len(routes))],bytes.NewReader(nil))
|
||||
router.ServeHTTP(w,req)
|
||||
}
|
||||
})
|
||||
|
||||
routes = append(routes,"/topic/")
|
||||
routes = append(routes,"/forums/")
|
||||
routes = append(routes,"/forum/")
|
||||
routes = append(routes,"/panel/")
|
||||
router = NewRouter()
|
||||
addEmptyRoutesToCustom(routes, router)
|
||||
b.Run("five-routes", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
req = httptest.NewRequest("get",routes[rand.Intn(len(routes))],bytes.NewReader(nil))
|
||||
router.ServeHTTP(w,req)
|
||||
}
|
||||
})
|
||||
|
||||
router = NewRouter()
|
||||
routes = append(routes,"/panel/plugins/")
|
||||
routes = append(routes,"/panel/groups/")
|
||||
routes = append(routes,"/panel/settings/")
|
||||
routes = append(routes,"/panel/users/")
|
||||
routes = append(routes,"/panel/forums/")
|
||||
addEmptyRoutesToCustom(routes, router)
|
||||
b.Run("ten-routes", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
req = httptest.NewRequest("get",routes[rand.Intn(len(routes))],bytes.NewReader(nil))
|
||||
router.ServeHTTP(w,req)
|
||||
}
|
||||
})
|
||||
|
||||
router = NewRouter()
|
||||
routes = append(routes,"/panel/forums/create/submit/")
|
||||
routes = append(routes,"/panel/forums/delete/")
|
||||
routes = append(routes,"/users/ban/")
|
||||
routes = append(routes,"/panel/users/edit/")
|
||||
routes = append(routes,"/panel/forums/create/")
|
||||
routes = append(routes,"/users/unban/")
|
||||
routes = append(routes,"/pages/")
|
||||
routes = append(routes,"/users/activate/")
|
||||
routes = append(routes,"/panel/forums/edit/submit/")
|
||||
routes = append(routes,"/panel/plugins/activate/")
|
||||
addEmptyRoutesToCustom(routes, router)
|
||||
b.Run("twenty-routes", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
req = httptest.NewRequest("get",routes[rand.Intn(len(routes))],bytes.NewReader(nil))
|
||||
router.ServeHTTP(w,req)
|
||||
}
|
||||
})
|
||||
|
||||
router = NewRouter()
|
||||
routes = append(routes,"/panel/plugins/deactivate/")
|
||||
routes = append(routes,"/panel/plugins/install/")
|
||||
routes = append(routes,"/panel/plugins/uninstall/")
|
||||
routes = append(routes,"/panel/templates/")
|
||||
routes = append(routes,"/panel/templates/edit/")
|
||||
routes = append(routes,"/panel/templates/create/")
|
||||
routes = append(routes,"/panel/templates/delete/")
|
||||
routes = append(routes,"/panel/templates/edit/submit/")
|
||||
routes = append(routes,"/panel/themes/")
|
||||
routes = append(routes,"/panel/themes/edit/")
|
||||
addEmptyRoutesToCustom(routes, router)
|
||||
b.Run("thirty-routes", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
req = httptest.NewRequest("get",routes[rand.Intn(len(routes))],bytes.NewReader(nil))
|
||||
router.ServeHTTP(w,req)
|
||||
}
|
||||
})
|
||||
|
||||
router = NewRouter()
|
||||
routes = append(routes,"/panel/themes/create/")
|
||||
routes = append(routes,"/panel/themes/delete/")
|
||||
routes = append(routes,"/panel/themes/delete/submit/")
|
||||
routes = append(routes,"/panel/templates/create/submit/")
|
||||
routes = append(routes,"/panel/templates/delete/submit/")
|
||||
routes = append(routes,"/panel/widgets/")
|
||||
routes = append(routes,"/panel/widgets/edit/")
|
||||
routes = append(routes,"/panel/widgets/activate/")
|
||||
routes = append(routes,"/panel/widgets/deactivate/")
|
||||
routes = append(routes,"/panel/magical/wombat/path")
|
||||
addEmptyRoutesToCustom(routes, router)
|
||||
b.Run("forty-routes", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
req = httptest.NewRequest("get",routes[rand.Intn(len(routes))],bytes.NewReader(nil))
|
||||
router.ServeHTTP(w,req)
|
||||
}
|
||||
})
|
||||
|
||||
router = NewRouter()
|
||||
routes = append(routes,"/report/")
|
||||
routes = append(routes,"/report/submit/")
|
||||
routes = append(routes,"/topic/create/submit/")
|
||||
routes = append(routes,"/topics/create/")
|
||||
routes = append(routes,"/overview/")
|
||||
routes = append(routes,"/uploads/")
|
||||
routes = append(routes,"/static/")
|
||||
routes = append(routes,"/reply/edit/submit/")
|
||||
routes = append(routes,"/reply/delete/submit/")
|
||||
routes = append(routes,"/topic/edit/submit/")
|
||||
addEmptyRoutesToCustom(routes, router)
|
||||
b.Run("fifty-routes", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
req = httptest.NewRequest("get",routes[rand.Intn(len(routes))],bytes.NewReader(nil))
|
||||
router.ServeHTTP(w,req)
|
||||
}
|
||||
})
|
||||
|
||||
router = NewRouter()
|
||||
routes = append(routes,"/topic/delete/submit/")
|
||||
routes = append(routes,"/topic/stick/submit/")
|
||||
routes = append(routes,"/topic/unstick/submit/")
|
||||
routes = append(routes,"/accounts/login/")
|
||||
routes = append(routes,"/accounts/create/")
|
||||
routes = append(routes,"/accounts/logout/")
|
||||
routes = append(routes,"/accounts/login/submit/")
|
||||
routes = append(routes,"/accounts/create/submit/")
|
||||
routes = append(routes,"/user/edit/critical/")
|
||||
routes = append(routes,"/user/edit/critical/submit/")
|
||||
addEmptyRoutesToCustom(routes, router)
|
||||
b.Run("sixty-routes", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
req = httptest.NewRequest("get",routes[rand.Intn(len(routes))],bytes.NewReader(nil))
|
||||
router.ServeHTTP(w,req)
|
||||
}
|
||||
})
|
||||
|
||||
router = NewRouter()
|
||||
routes = append(routes,"/user/edit/avatar/")
|
||||
routes = append(routes,"/user/edit/avatar/submit/")
|
||||
routes = append(routes,"/user/edit/username/")
|
||||
routes = append(routes,"/user/edit/username/submit/")
|
||||
routes = append(routes,"/profile/reply/create/")
|
||||
routes = append(routes,"/profile/reply/edit/submit/")
|
||||
routes = append(routes,"/profile/reply/delete/submit/")
|
||||
routes = append(routes,"/arcane/tower/")
|
||||
routes = append(routes,"/magical/kingdom/")
|
||||
routes = append(routes,"/insert/name/here/")
|
||||
addEmptyRoutesToCustom(routes, router)
|
||||
b.Run("seventy-routes", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
req = httptest.NewRequest("get",routes[rand.Intn(len(routes))],bytes.NewReader(nil))
|
||||
router.ServeHTTP(w,req)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/*func TestRoute(t *testing.T) {
|
||||
|
||||
}*/
|
BIN
gosora.exe
BIN
gosora.exe
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
Binary file not shown.
After Width: | Height: | Size: 116 KiB |
95
main.go
95
main.go
|
@ -138,7 +138,7 @@ func main(){
|
|||
init_plugins()
|
||||
|
||||
// In a directory to stop it clashing with the other paths
|
||||
http.HandleFunc("/static/", route_static)
|
||||
/*http.HandleFunc("/static/", route_static)
|
||||
|
||||
fs_u := http.FileServer(http.Dir("./uploads"))
|
||||
http.Handle("/uploads/", http.StripPrefix("/uploads/",fs_u))
|
||||
|
@ -180,6 +180,7 @@ func main(){
|
|||
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)
|
||||
|
@ -210,8 +211,96 @@ func main(){
|
|||
http.HandleFunc("/panel/users/edit/submit/", route_panel_users_edit_submit)
|
||||
http.HandleFunc("/panel/groups/", route_panel_groups)
|
||||
|
||||
http.HandleFunc("/", default_route)
|
||||
http.HandleFunc("/", default_route)*/
|
||||
|
||||
router := NewRouter()
|
||||
router.HandleFunc("/static/", route_static)
|
||||
|
||||
fs_u := http.FileServer(http.Dir("./uploads"))
|
||||
router.Handle("/uploads/", http.StripPrefix("/uploads/",fs_u))
|
||||
|
||||
router.HandleFunc("/overview/", route_overview)
|
||||
router.HandleFunc("/topics/create/", route_topic_create)
|
||||
router.HandleFunc("/topics/", route_topics)
|
||||
router.HandleFunc("/forums/", route_forums)
|
||||
router.HandleFunc("/forum/", route_forum)
|
||||
router.HandleFunc("/topic/create/submit/", route_create_topic)
|
||||
router.HandleFunc("/topic/", route_topic_id)
|
||||
router.HandleFunc("/reply/create/", route_create_reply)
|
||||
//router.HandleFunc("/reply/edit/", route_reply_edit)
|
||||
//router.HandleFunc("/reply/delete/", route_reply_delete)
|
||||
router.HandleFunc("/reply/edit/submit/", route_reply_edit_submit)
|
||||
router.HandleFunc("/reply/delete/submit/", route_reply_delete_submit)
|
||||
router.HandleFunc("/report/submit/", route_report_submit)
|
||||
router.HandleFunc("/topic/edit/submit/", route_edit_topic)
|
||||
router.HandleFunc("/topic/delete/submit/", route_delete_topic)
|
||||
router.HandleFunc("/topic/stick/submit/", route_stick_topic)
|
||||
router.HandleFunc("/topic/unstick/submit/", route_unstick_topic)
|
||||
|
||||
// Custom Pages
|
||||
router.HandleFunc("/pages/", route_custom_page)
|
||||
|
||||
// Accounts
|
||||
router.HandleFunc("/accounts/login/", route_login)
|
||||
router.HandleFunc("/accounts/create/", route_register)
|
||||
router.HandleFunc("/accounts/logout/", route_logout)
|
||||
router.HandleFunc("/accounts/login/submit/", route_login_submit)
|
||||
router.HandleFunc("/accounts/create/submit/", route_register_submit)
|
||||
|
||||
//router.HandleFunc("/accounts/list/", route_login) // Redirect /accounts/ and /user/ to here.. // Get a list of all of the accounts on the forum
|
||||
//router.HandleFunc("/accounts/create/full/", route_logout) // Advanced account creator for admins?
|
||||
//router.HandleFunc("/user/edit/", route_logout)
|
||||
router.HandleFunc("/user/edit/critical/", route_account_own_edit_critical) // Password & Email
|
||||
router.HandleFunc("/user/edit/critical/submit/", route_account_own_edit_critical_submit)
|
||||
router.HandleFunc("/user/edit/avatar/", route_account_own_edit_avatar)
|
||||
router.HandleFunc("/user/edit/avatar/submit/", route_account_own_edit_avatar_submit)
|
||||
router.HandleFunc("/user/edit/username/", route_account_own_edit_username)
|
||||
router.HandleFunc("/user/edit/username/submit/", route_account_own_edit_username_submit)
|
||||
router.HandleFunc("/user/edit/email/", route_account_own_edit_email)
|
||||
router.HandleFunc("/user/edit/email/token/", route_account_own_edit_email_token_submit)
|
||||
router.HandleFunc("/user/", route_profile)
|
||||
router.HandleFunc("/profile/reply/create/", route_profile_reply_create)
|
||||
router.HandleFunc("/profile/reply/edit/submit/", route_profile_reply_edit_submit)
|
||||
router.HandleFunc("/profile/reply/delete/submit/", route_profile_reply_delete_submit)
|
||||
//router.HandleFunc("/user/edit/submit/", route_logout)
|
||||
router.HandleFunc("/users/ban/", route_ban)
|
||||
router.HandleFunc("/users/ban/submit/", route_ban_submit)
|
||||
router.HandleFunc("/users/unban/", route_unban)
|
||||
router.HandleFunc("/users/activate/", route_activate)
|
||||
|
||||
// Admin
|
||||
router.HandleFunc("/panel/", route_panel)
|
||||
router.HandleFunc("/panel/forums/", route_panel_forums)
|
||||
router.HandleFunc("/panel/forums/create/", route_panel_forums_create_submit)
|
||||
router.HandleFunc("/panel/forums/delete/", route_panel_forums_delete)
|
||||
router.HandleFunc("/panel/forums/delete/submit/", route_panel_forums_delete_submit)
|
||||
router.HandleFunc("/panel/forums/edit/submit/", route_panel_forums_edit_submit)
|
||||
router.HandleFunc("/panel/settings/", route_panel_settings)
|
||||
router.HandleFunc("/panel/settings/edit/", route_panel_setting)
|
||||
router.HandleFunc("/panel/settings/edit/submit/", route_panel_setting_edit)
|
||||
router.HandleFunc("/panel/themes/", route_panel_themes)
|
||||
router.HandleFunc("/panel/themes/default/", route_panel_themes_default)
|
||||
router.HandleFunc("/panel/plugins/", route_panel_plugins)
|
||||
router.HandleFunc("/panel/plugins/activate/", route_panel_plugins_activate)
|
||||
router.HandleFunc("/panel/plugins/deactivate/", route_panel_plugins_deactivate)
|
||||
router.HandleFunc("/panel/users/", route_panel_users)
|
||||
router.HandleFunc("/panel/users/edit/", route_panel_users_edit)
|
||||
router.HandleFunc("/panel/users/edit/submit/", route_panel_users_edit_submit)
|
||||
router.HandleFunc("/panel/groups/", route_panel_groups)
|
||||
|
||||
router.HandleFunc("/", default_route)
|
||||
|
||||
defer db.Close()
|
||||
http.ListenAndServe(":8080", nil)
|
||||
if !enable_ssl {
|
||||
if server_port == "" {
|
||||
server_port = "80"
|
||||
}
|
||||
//http.ListenAndServe(":" + server_port, nil)
|
||||
http.ListenAndServe(":" + server_port, router)
|
||||
} else {
|
||||
if server_port == "" {
|
||||
server_port = "443"
|
||||
}
|
||||
http.ListenAndServeTLS(":" + server_port, ssl_fullchain, ssl_privkey, router)
|
||||
}
|
||||
}
|
|
@ -488,7 +488,6 @@ func route_activate(w http.ResponseWriter, r *http.Request) {
|
|||
NoPermissions(w,r,user)
|
||||
return
|
||||
}
|
||||
|
||||
if r.FormValue("session") != user.Session {
|
||||
SecurityError(w,r,user)
|
||||
return
|
||||
|
@ -515,7 +514,6 @@ func route_activate(w http.ResponseWriter, r *http.Request) {
|
|||
LocalError("The account you're trying to activate has already been activated.",w,r,user)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = activate_user_stmt.Exec(uid)
|
||||
if err != nil {
|
||||
InternalError(err,w,r,user)
|
||||
|
|
26
mysql.go
26
mysql.go
|
@ -27,6 +27,9 @@ var set_password_stmt *sql.Stmt
|
|||
var get_password_stmt *sql.Stmt
|
||||
var set_avatar_stmt *sql.Stmt
|
||||
var set_username_stmt *sql.Stmt
|
||||
var add_email_stmt *sql.Stmt
|
||||
var update_email_stmt *sql.Stmt
|
||||
var verify_email_stmt *sql.Stmt
|
||||
var register_stmt *sql.Stmt
|
||||
var username_exists_stmt *sql.Stmt
|
||||
var change_group_stmt *sql.Stmt
|
||||
|
@ -61,7 +64,7 @@ func init_database(err error) {
|
|||
}
|
||||
|
||||
log.Print("Preparing get_session statement.")
|
||||
get_session_stmt, err = db.Prepare("select `uid`, `name`, `group`, `is_super_admin`, `session`, `avatar`, `message`, `url_prefix`, `url_name` FROM `users` WHERE `uid` = ? AND `session` = ? AND `session` <> ''")
|
||||
get_session_stmt, err = db.Prepare("select `uid`, `name`, `group`, `is_super_admin`, `session`, `email`, `avatar`, `message`, `url_prefix`, `url_name` FROM `users` WHERE `uid` = ? AND `session` = ? AND `session` <> ''")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -195,6 +198,24 @@ func init_database(err error) {
|
|||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Print("Preparing add_email statement.")
|
||||
add_email_stmt, err = db.Prepare("INSERT INTO emails(`email`,`uid`,`validated`,`token`) VALUES(?,?,?,?)")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Print("Preparing update_email statement.")
|
||||
update_email_stmt, err = db.Prepare("UPDATE emails SET email = ?, uid = ?, validated = ?, token = ? WHERE email = ?")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Print("Preparing verify_email statement.")
|
||||
verify_email_stmt, err = db.Prepare("UPDATE emails SET validated = 1, token = '' WHERE email = ?")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Print("Preparing activate_user statement.")
|
||||
activate_user_stmt, err = db.Prepare("UPDATE users SET active = 1 WHERE uid = ?")
|
||||
if err != nil {
|
||||
|
@ -291,7 +312,6 @@ func init_database(err error) {
|
|||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if !nogrouplog {
|
||||
fmt.Println(group.Name + ": ")
|
||||
fmt.Printf("%+v\n", group.Perms)
|
||||
|
@ -328,7 +348,6 @@ func init_database(err error) {
|
|||
forum.LastTopic = "None"
|
||||
forum.LastTopicTime = ""
|
||||
}
|
||||
|
||||
forums[forum.ID] = forum
|
||||
}
|
||||
err = rows.Err()
|
||||
|
@ -387,7 +406,6 @@ func init_database(err error) {
|
|||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
plugin.Active = active
|
||||
plugins[uname] = plugin
|
||||
}
|
||||
|
|
67
router.go
67
router.go
|
@ -1,31 +1,66 @@
|
|||
package main
|
||||
/*import "sync"
|
||||
//import "fmt"
|
||||
import "strings"
|
||||
import "sync"
|
||||
import "net/http"
|
||||
|
||||
type Router struct {
|
||||
mu sync.RWMutex
|
||||
routes map[string]http.Handler
|
||||
routes map[string]func(http.ResponseWriter, *http.Request)
|
||||
}
|
||||
|
||||
func (route *Router) ServeHTTP() {
|
||||
route.mu.RLock()
|
||||
defer route.mu.RUnlock()
|
||||
func NewRouter() *Router {
|
||||
return &Router{
|
||||
routes: make(map[string]func(http.ResponseWriter, *http.Request)),
|
||||
}
|
||||
}
|
||||
|
||||
if path[0] != "/" {
|
||||
return route.routes["/"]
|
||||
func (router *Router) Handle(pattern string, handle http.Handler) {
|
||||
router.routes[pattern] = handle.ServeHTTP
|
||||
}
|
||||
|
||||
func (router *Router) HandleFunc(pattern string, handle func(http.ResponseWriter, *http.Request)) {
|
||||
router.routes[pattern] = handle
|
||||
}
|
||||
|
||||
func (router *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
router.mu.RLock()
|
||||
defer router.mu.RUnlock()
|
||||
|
||||
if req.URL.Path[0] != '/' {
|
||||
w.WriteHeader(405)
|
||||
w.Write([]byte(""))
|
||||
return
|
||||
}
|
||||
|
||||
// Do something on the path to turn slashes facing the wrong way "\" into "/" slashes. If it's bytes, then alter the bytes in place for the maximum speed
|
||||
|
||||
handle := route.routes[path]
|
||||
if !ok {
|
||||
if path[-1] != "/" {
|
||||
handle = route.routes[path + "/"]
|
||||
if !ok {
|
||||
return route.routes["/"]
|
||||
handle, ok := router.routes[req.URL.Path]
|
||||
if ok {
|
||||
handle(w,req)
|
||||
return
|
||||
}
|
||||
return handle
|
||||
|
||||
if req.URL.Path[len(req.URL.Path) - 1] == '/' {
|
||||
w.WriteHeader(404)
|
||||
w.Write([]byte(""))
|
||||
return
|
||||
}
|
||||
|
||||
handle, ok = router.routes[req.URL.Path[:strings.LastIndexByte(req.URL.Path,'/') + 1]]
|
||||
if ok {
|
||||
handle(w,req)
|
||||
return
|
||||
}
|
||||
return handle
|
||||
}*/
|
||||
//fmt.Println(req.URL.Path[:strings.LastIndexByte(req.URL.Path,'/')])
|
||||
|
||||
handle, ok = router.routes[req.URL.Path + "/"]
|
||||
if ok {
|
||||
handle(w,req)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(404)
|
||||
w.Write([]byte(""))
|
||||
return
|
||||
}
|
221
routes.go
221
routes.go
|
@ -877,19 +877,10 @@ func route_account_own_edit_critical(w http.ResponseWriter, r *http.Request) {
|
|||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if !user.Loggedin {
|
||||
errmsg := "You need to login to edit your own account."
|
||||
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("You need to login to edit your account.",w,r,user)
|
||||
return
|
||||
}
|
||||
|
||||
pi := Page{"Edit Password","account-own-edit",user,noticeList,tList,0}
|
||||
templates.ExecuteTemplate(w,"account-own-edit.html", pi)
|
||||
}
|
||||
|
@ -899,16 +890,8 @@ func route_account_own_edit_critical_submit(w http.ResponseWriter, r *http.Reque
|
|||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if !user.Loggedin {
|
||||
errmsg := "You need to login to edit your own account."
|
||||
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("You need to login to edit your account.",w,r,user)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -973,8 +956,9 @@ func route_account_own_edit_critical_submit(w http.ResponseWriter, r *http.Reque
|
|||
return
|
||||
}
|
||||
|
||||
pi := Page{"Edit Password","account-own-edit-success",user,noticeList,tList,0}
|
||||
templates.ExecuteTemplate(w,"account-own-edit-success.html", pi)
|
||||
noticeList[len(noticeList)] = "Your password was successfully updated"
|
||||
pi := Page{"Edit Password","account-own-edit",user,noticeList,tList,0}
|
||||
templates.ExecuteTemplate(w,"account-own-edit.html", pi)
|
||||
}
|
||||
|
||||
func route_account_own_edit_avatar(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -982,19 +966,10 @@ func route_account_own_edit_avatar(w http.ResponseWriter, r *http.Request) {
|
|||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if !user.Loggedin {
|
||||
errmsg := "You need to login to edit your own account."
|
||||
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("You need to login to edit your account.",w,r,user)
|
||||
return
|
||||
}
|
||||
|
||||
pi := Page{"Edit Avatar","account-own-edit-avatar",user,noticeList,tList,0}
|
||||
templates.ExecuteTemplate(w,"account-own-edit-avatar.html", pi)
|
||||
}
|
||||
|
@ -1011,14 +986,7 @@ func route_account_own_edit_avatar_submit(w http.ResponseWriter, r *http.Request
|
|||
return
|
||||
}
|
||||
if !user.Loggedin {
|
||||
errmsg := "You need to login to edit your own account."
|
||||
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("You need to login to edit your account.",w,r,user)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -1028,7 +996,7 @@ func route_account_own_edit_avatar_submit(w http.ResponseWriter, r *http.Request
|
|||
return
|
||||
}
|
||||
|
||||
var filename string = ""
|
||||
var filename string
|
||||
var ext string
|
||||
for _, fheaders := range r.MultipartForm.File {
|
||||
for _, hdr := range fheaders {
|
||||
|
@ -1087,7 +1055,6 @@ func route_account_own_edit_avatar_submit(w http.ResponseWriter, r *http.Request
|
|||
InternalError(err,w,r,user)
|
||||
return
|
||||
}
|
||||
|
||||
user.Avatar = "/uploads/avatar_" + strconv.Itoa(user.ID) + "." + ext
|
||||
noticeList[len(noticeList)] = "Your avatar was successfully updated"
|
||||
|
||||
|
@ -1100,16 +1067,8 @@ func route_account_own_edit_username(w http.ResponseWriter, r *http.Request) {
|
|||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if !user.Loggedin {
|
||||
errmsg := "You need to login to edit your own account."
|
||||
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("You need to login to edit your account.",w,r,user)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -1122,19 +1081,10 @@ func route_account_own_edit_username_submit(w http.ResponseWriter, r *http.Reque
|
|||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if !user.Loggedin {
|
||||
errmsg := "You need to login to edit your own account."
|
||||
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("You need to login to edit your account.",w,r,user)
|
||||
return
|
||||
}
|
||||
|
||||
err := r.ParseForm()
|
||||
if err != nil {
|
||||
LocalError("Bad Form", w, r, user)
|
||||
|
@ -1149,10 +1099,131 @@ 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,noticeList,tList,user.Name}
|
||||
noticeList[len(noticeList)] = "Your username was successfully updated"
|
||||
pi := Page{"Edit Username","account-own-edit-username",user,noticeList,tList,0}
|
||||
templates.ExecuteTemplate(w,"account-own-edit-username.html", pi)
|
||||
}
|
||||
|
||||
func route_account_own_edit_email(w http.ResponseWriter, r *http.Request) {
|
||||
user, noticeList, ok := SessionCheck(w,r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if !user.Loggedin {
|
||||
LocalError("You need to login to edit your account.",w,r,user)
|
||||
return
|
||||
}
|
||||
|
||||
email := Email{UserID: user.ID}
|
||||
var emailList []interface{}
|
||||
rows, err := db.Query("SELECT email, validated FROM emails WHERE uid = ?", user.ID)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
err := rows.Scan(&email.Email, &email.Validated)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if email.Email == user.Email {
|
||||
email.Primary = true
|
||||
}
|
||||
emailList = append(emailList, email)
|
||||
}
|
||||
err = rows.Err()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Was this site migrated from another forum software? Most of them don't have multiple emails for a single user. This also applies when the admin switches enable_emails on after having it off for a while
|
||||
if len(emailList) == 0 {
|
||||
email.Email = user.Email
|
||||
email.Validated = false
|
||||
email.Primary = true
|
||||
emailList = append(emailList, email)
|
||||
}
|
||||
|
||||
if !enable_emails {
|
||||
noticeList[len(noticeList)] = "The email system has been turned off. All features involving sending emails have been disabled."
|
||||
}
|
||||
pi := Page{"Email Manager","account-own-edit-email",user,noticeList,emailList,0}
|
||||
templates.ExecuteTemplate(w,"account-own-edit-email.html", pi)
|
||||
}
|
||||
|
||||
func route_account_own_edit_email_token_submit(w http.ResponseWriter, r *http.Request) {
|
||||
user, noticeList, ok := SessionCheck(w,r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if !user.Loggedin {
|
||||
LocalError("You need to login to edit your account.",w,r,user)
|
||||
return
|
||||
}
|
||||
token := r.URL.Path[len("/user/edit/email/token/"):]
|
||||
|
||||
email := Email{UserID: user.ID}
|
||||
targetEmail := Email{UserID: user.ID}
|
||||
var emailList []interface{}
|
||||
rows, err := db.Query("SELECT email, validated, token FROM emails WHERE uid = ?", user.ID)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
err := rows.Scan(&email.Email, &email.Validated, &email.Token)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if email.Email == user.Email {
|
||||
email.Primary = true
|
||||
}
|
||||
if email.Token == token {
|
||||
targetEmail = email
|
||||
}
|
||||
emailList = append(emailList, email)
|
||||
}
|
||||
err = rows.Err()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if len(emailList) == 0 {
|
||||
LocalError("A verification email was never sent for you!",w,r,user)
|
||||
return
|
||||
}
|
||||
if targetEmail.Token == "" {
|
||||
LocalError("That's not a valid token!",w,r,user)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = verify_email_stmt.Exec(user.Email)
|
||||
if err != nil {
|
||||
InternalError(err,w,r,user)
|
||||
return
|
||||
}
|
||||
|
||||
// If Email Activation is on, then activate the account while we're here
|
||||
if settings["activation_type"] == 2 {
|
||||
_, err = activate_user_stmt.Exec(user.ID)
|
||||
if err != nil {
|
||||
InternalError(err,w,r,user)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if !enable_emails {
|
||||
noticeList[len(noticeList)] = "The email system has been turned off. All features involving sending emails have been disabled."
|
||||
}
|
||||
noticeList[len(noticeList)] = "Your email was successfully verified"
|
||||
pi := Page{"Email Manager","account-own-edit-email",user,noticeList,emailList,0}
|
||||
templates.ExecuteTemplate(w,"account-own-edit-email.html", pi)
|
||||
}
|
||||
|
||||
func route_logout(w http.ResponseWriter, r *http.Request) {
|
||||
user, ok := SimpleSessionCheck(w,r)
|
||||
if !ok {
|
||||
|
@ -1312,7 +1383,6 @@ func route_register(w http.ResponseWriter, r *http.Request) {
|
|||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if user.Loggedin {
|
||||
errmsg := "You're already logged in."
|
||||
pi := Page{"Error","error",user,nList,tList,errmsg}
|
||||
|
@ -1346,12 +1416,12 @@ func route_register_submit(w http.ResponseWriter, r *http.Request) {
|
|||
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)
|
||||
|
@ -1416,11 +1486,11 @@ func route_register_submit(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
var active int
|
||||
var group int
|
||||
if settings["activation_type"] == 1 {
|
||||
switch settings["activation_type"] {
|
||||
case 1: // Activate All
|
||||
active = 1
|
||||
group = default_group
|
||||
} else {
|
||||
active = 0
|
||||
default: // Anything else. E.g. Admin Activation or Email Activation.
|
||||
group = activation_group
|
||||
}
|
||||
|
||||
|
@ -1436,6 +1506,25 @@ func route_register_submit(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
// Check if this user actually owns this email, if email activation is on, automatically flip their account to active when the email is validated. Validation is also useful for determining whether this user should receive any alerts, etc. via email
|
||||
if enable_emails {
|
||||
token, err := GenerateSafeString(80)
|
||||
if err != nil {
|
||||
InternalError(err,w,r,user)
|
||||
return
|
||||
}
|
||||
_, err = add_email_stmt.Exec(email, lastId, 0, token)
|
||||
if err != nil {
|
||||
InternalError(err,w,r,user)
|
||||
return
|
||||
}
|
||||
|
||||
if !SendValidationEmail(username, email, token) {
|
||||
LocalError("We were unable to send the email for you to confirm that this email address belongs to you. You may not have access to some functionality until you do so. Please ask an administrator for assistance.",w,r,user)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
cookie := http.Cookie{Name: "uid",Value: strconv.FormatInt(lastId, 10),Path: "/",MaxAge: year}
|
||||
http.SetCookie(w,&cookie)
|
||||
cookie = http.Cookie{Name: "session",Value: session,Path: "/",MaxAge: year}
|
||||
|
|
|
@ -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 "io"
|
||||
import "strconv"
|
||||
import "io"
|
||||
|
||||
func init() {
|
||||
template_forum_handle = template_forum
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/* 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 "html/template"
|
||||
import "io"
|
||||
import "strconv"
|
||||
import "html/template"
|
||||
|
||||
func init() {
|
||||
template_topic_alt_handle = template_topic_alt
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
<div class="colblock_left">
|
||||
<div class="rowitem"><a>My Account</a></div>
|
||||
<div class="rowitem passive"><a href="/user/edit/avatar/">Change Avatar</a></div>
|
||||
<div class="rowitem passive"><a href="/user/edit/username/">Change Username</a></div>
|
||||
<div class="rowitem passive"><a href="/user/edit/critical/">Change Password</a></div>
|
||||
<div class="rowitem passive"><a href="/user/edit/email/">Change Email</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>
|
|
@ -1,13 +1,5 @@
|
|||
{{template "header.html" . }}
|
||||
<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>
|
||||
{{template "account-menu.html" . }}
|
||||
<div class="colblock_right">
|
||||
<div class="rowitem"><a>Edit Avatar</a></div>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
{{template "header.html" . }}
|
||||
{{template "account-menu.html" . }}
|
||||
<div class="colblock_right">
|
||||
<div class="rowitem"><a>Emails</a></div>
|
||||
</div>
|
||||
<div class="colblock_right">
|
||||
{{range .ItemList}}
|
||||
<div class="rowitem" style="font-weight: normal;">
|
||||
<a style="text-transform: none;">{{.Email}}</a>
|
||||
<span style="float: right">
|
||||
<span class="username">{{if .Primary}}Primary{{else}}Secondary{{end}}</span>
|
||||
{{if .Validated}}<span class="username" style="color: green;">Verified</span>{{else}}<a class="username" style="color: crimson;">Resend Verification Email</a>{{end}}
|
||||
</span>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{template "footer.html" . }}
|
|
@ -1,34 +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 Password</a></div>
|
||||
</div>
|
||||
<div class="colblock_right">
|
||||
<form action="/user/edit/critical/submit/" method="post">
|
||||
<div class="formrow">
|
||||
<div class="formitem"><a>Current Password</a></div>
|
||||
<div class="formitem"><input name="account-current-password" type="password" placeholder="*****" /></div>
|
||||
</div>
|
||||
<div class="formrow">
|
||||
<div class="formitem"><a>New Password</a></div>
|
||||
<div class="formitem"><input name="account-new-password" type="password" placeholder="*****" /></div>
|
||||
</div>
|
||||
<div class="formrow">
|
||||
<div class="formitem"><a>Confirm Password</a></div>
|
||||
<div class="formitem"><input name="account-confirm-password" type="password" placeholder="*****" /></div>
|
||||
</div>
|
||||
<div class="formrow">
|
||||
<div class="formitem"><button name="account-button" class="formbutton">Update</div></div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{{template "footer.html" . }}
|
|
@ -1,13 +1,5 @@
|
|||
{{template "header.html" . }}
|
||||
<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>
|
||||
{{template "account-menu.html" . }}
|
||||
<div class="colblock_right">
|
||||
<div class="rowitem"><a>Edit Username</a></div>
|
||||
</div>
|
||||
|
@ -15,7 +7,7 @@
|
|||
<form action="/user/edit/username/submit/" method="post">
|
||||
<div class="formrow">
|
||||
<div class="formitem"><a>Current Username</a></div>
|
||||
<div class="formitem">{{.Something}}</div>
|
||||
<div class="formitem">{{.CurrentUser.Name}}</div>
|
||||
</div>
|
||||
<div class="formrow">
|
||||
<div class="formitem"><a>New Username</a></div>
|
||||
|
|
|
@ -1,13 +1,5 @@
|
|||
{{template "header.html" . }}
|
||||
<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>
|
||||
{{template "account-menu.html" . }}
|
||||
<div class="colblock_right">
|
||||
<div class="rowitem"><a>Edit Password</a></div>
|
||||
</div>
|
||||
|
|
23
user.go
23
user.go
|
@ -28,6 +28,15 @@ type User struct
|
|||
Tag string
|
||||
}
|
||||
|
||||
type Email struct
|
||||
{
|
||||
UserID int
|
||||
Email string
|
||||
Validated bool
|
||||
Primary bool
|
||||
Token string
|
||||
}
|
||||
|
||||
func SetPassword(uid int, password string) (error) {
|
||||
salt, err := GenerateSafeString(saltLength)
|
||||
if err != nil {
|
||||
|
@ -47,6 +56,18 @@ func SetPassword(uid int, password string) (error) {
|
|||
return nil
|
||||
}
|
||||
|
||||
func SendValidationEmail(username string, email string, token string) bool {
|
||||
var schema string
|
||||
if enable_ssl {
|
||||
schema = "s"
|
||||
}
|
||||
|
||||
subject := "Validate Your Email @ " + site_name
|
||||
msg := "Dear " + username + ", following your registration on our forums, we ask you to validate your email, so that we can confirm that this email actually belongs to you.\nClick on the following link to do so. http" + schema + "://" + site_url + "/user/edit/token/" + token + "\nIf you haven't created an account here, then please feel free to ignore this email.\nWe're sorry for the inconvenience this may have caused."
|
||||
|
||||
return SendEmail(email, subject, msg)
|
||||
}
|
||||
|
||||
func SessionCheck(w http.ResponseWriter, r *http.Request) (user User, noticeList map[int]string, success bool) {
|
||||
noticeList = make(map[int]string)
|
||||
|
||||
|
@ -71,7 +92,7 @@ func SessionCheck(w http.ResponseWriter, r *http.Request) (user User, noticeList
|
|||
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 = ""
|
||||
|
|
42
utils.go
42
utils.go
|
@ -3,6 +3,7 @@ import "fmt"
|
|||
import "time"
|
||||
import "encoding/base64"
|
||||
import "crypto/rand"
|
||||
import "net/smtp"
|
||||
|
||||
// Generate a cryptographically secure set of random bytes..
|
||||
func GenerateSafeString(length int) (string, error) {
|
||||
|
@ -45,3 +46,44 @@ func relative_time(in string) (string, error) {
|
|||
return fmt.Sprintf("%d hours ago", int(seconds / 60 / 60)), err
|
||||
}
|
||||
}
|
||||
|
||||
func SendEmail(email string, subject string, msg string) bool {
|
||||
// This hook is useful for plugin_sendmail or for testing tools. Possibly to hook it into some sort of mail server?
|
||||
if vhooks["email_send_intercept"] != nil {
|
||||
return vhooks["email_send_intercept"](email, subject, msg).(bool)
|
||||
}
|
||||
body := "Subject: " + subject + "\n\n" + msg + "\n"
|
||||
|
||||
con, err := smtp.Dial(smtp_server)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
err = con.Mail(site_email)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
err = con.Rcpt(email)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
email_data, err := con.Data()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
_, err = fmt.Fprintf(email_data, body)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
err = email_data.Close()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
err = con.Quit()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue