2017-11-10 03:33:11 +00:00
package common
Added the Social Groups plugin. This is still under construction.
Made a few improvements to the ForumStore, including bringing it's API closer in line with the other datastores, adding stubs for future subforum functionality, and improving efficiency in a few places.
The auth interface now handles all the authentication stuff.
Renamed the debug config variable to debug_mode.
Added the PluginPerms API.
Internal Errors will now dump the stack trace in the console.
Added support for installable plugins.
Refactored the routing logic so that the router now handles the common PreRoute logic(exc. /static/)
Added the CreateTable method to the query generator. It might need some tweaking to better support other database systems.
Added the same CreateTable method to the query builder.
Began work on PostgreSQL support.
Added the string-string hook type
Added the pre_render hook type.
Added the ParentID and ParentType fields to forums.
Added the get_forum_url_prefix function.
Added a more generic build_slug function.
Added the get_topic_url_prefix function.
Added the override_perms and override_forum_perms functions for bulk setting and unsetting permissions.
Added more ExtData fields in a few structs and removed them on the Perms struct as the PluginPerms API supersedes them there.
Plugins can now see the router instance.
The plugin initialisation handlers can now throw errors.
Plugins are now initialised after all the forum's subsystems are.
Refactored the unit test logic. For instance, we now use the proper .Log method rather than fmt.Println in many cases.
Sorry, we'll have to break Github's generated file detection, as the build instructions aren't working, unless I put them at the top, and they're far, far more important than getting Github to recognise the generated code as generated code.
Fixed an issue with mysql.go's _init_database() overwriting the dbpassword variable. Not a huge issue, but it is a "gotcha" for those not expecting a ':' at the start.
Fixed an issue with forum creation where the forum permissions didn't get cached.
Fixed a bug in plugin_bbcode where negative numbers in rand would crash Gosora.
Made the outputs of plugin_markdown and plugin_bbcode more compliant with the tests.
Revamped the phrase system to make it easier for us to add language pack related features in the future.
Added the WidgetMenu widget type.
Revamped the theme again. I'm experimenting to see which approach I like most.
- Excuse the little W3C rage. Some things about CSS drive me crazy :p
Tests:
Added 22 bbcode_full_parse tests.
Added 19 bbcode_regex_parse tests.
Added 27 markdown_parse tests.
Added four UserStore tests. More to come when the test database functionality is added.
Added 18 name_to_slug tests.
Hooks:
Added the pre_render hook.
Added the pre_render_forum_list hook.
Added the pre_render_view_forum hook.
Added the pre_render_topic_list hook.
Added the pre_render_view_topic hook.
Added the pre_render_profile hook.
Added the pre_render_custom_page hook.
Added the pre_render_overview hook.
Added the pre_render_create_topic hook.
Added the pre_render_account_own_edit_critical hook.
Added the pre_render_account_own_edit_avatar hook.
Added the pre_render_account_own_edit_username hook.
Added the pre_render_account_own_edit_email hook.
Added the pre_render_login hook.
Added the pre_render_register hook.
Added the pre_render_ban hook.
Added the pre_render_panel_dashboard hook.
Added the pre_render_panel_forums hook.
Added the pre_render_panel_delete_forum hook.
Added the pre_render_panel_edit_forum hook.
Added the pre_render_panel_settings hook.
Added the pre_render_panel_setting hook.
Added the pre_render_panel_plugins hook.
Added the pre_render_panel_users hook.
Added the pre_render_panel_edit_user hook.
Added the pre_render_panel_groups hook.
Added the pre_render_panel_edit_group hook.
Added the pre_render_panel_edit_group_perms hook.
Added the pre_render_panel_themes hook.
Added the pre_render_panel_mod_log hook.
Added the pre_render_error hook.
Added the pre_render_security_error hook.
Added the create_group_preappend hook.
Added the intercept_build_widgets hook.
Added the simple_forum_check_pre_perms hook.
Added the forum_check_pre_perms hook.
2017-07-09 12:06:04 +00:00
2018-02-10 15:07:21 +00:00
import (
"log"
"net/http"
"runtime/debug"
2018-06-17 07:28:18 +00:00
"strings"
2018-02-10 15:07:21 +00:00
"sync"
2018-11-01 06:43:56 +00:00
"github.com/Azareal/Gosora/common/phrases"
2018-02-10 15:07:21 +00:00
)
2016-12-02 07:38:54 +00:00
2018-05-31 06:51:31 +00:00
type ErrorItem struct {
error
Stack [ ] byte
}
// ! The errorBuffer uses o(n) memory, we should probably do something about that
// TODO: Use the errorBuffer variable to construct the system log in the Control Panel. Should we log errors caused by users too? Or just collect statistics on those or do nothing? Intercept recover()? Could we intercept the logger instead here? We might get too much information, if we intercept the logger, maybe make it part of the Debug page?
2018-04-22 12:33:56 +00:00
// ? - Should we pass Header / HeaderLite rather than forcing the errors to pull the global Header instance?
2017-09-03 04:50:31 +00:00
var errorBufferMutex sync . RWMutex
2018-05-31 06:51:31 +00:00
var errorBuffer [ ] ErrorItem
2017-09-03 04:50:31 +00:00
2017-09-18 17:03:52 +00:00
//var notfoundCountPerSecond int
//var nopermsCountPerSecond int
2017-01-17 07:55:46 +00:00
2017-11-10 03:33:11 +00:00
// A blank list to fill out that parameter in Page for routes which don't use it
var tList [ ] interface { }
2017-10-30 09:57:08 +00:00
// WIP, a new system to propagate errors up from routes
type RouteError interface {
Type ( ) string
Error ( ) string
2018-11-13 06:51:34 +00:00
Cause ( ) string
2017-11-11 04:06:16 +00:00
JSON ( ) bool
2017-10-30 09:57:08 +00:00
Handled ( ) bool
2018-11-13 06:51:34 +00:00
Wrap ( string )
2017-10-30 09:57:08 +00:00
}
type RouteErrorImpl struct {
2018-11-13 06:51:34 +00:00
userText string
sysText string
system bool
json bool
handled bool
2017-10-30 09:57:08 +00:00
}
func ( err * RouteErrorImpl ) Type ( ) string {
// System errors may contain sensitive information we don't want the user to see
if err . system {
return "system"
}
2017-11-02 13:35:19 +00:00
return "user"
2017-10-30 09:57:08 +00:00
}
func ( err * RouteErrorImpl ) Error ( ) string {
2018-11-13 06:51:34 +00:00
return err . userText
}
func ( err * RouteErrorImpl ) Cause ( ) string {
if err . sysText == "" {
return err . Error ( )
}
return err . sysText
2017-10-30 09:57:08 +00:00
}
// Respond with JSON?
2017-11-11 04:06:16 +00:00
func ( err * RouteErrorImpl ) JSON ( ) bool {
2017-10-30 09:57:08 +00:00
return err . json
}
// Has this error been dealt with elsewhere?
func ( err * RouteErrorImpl ) Handled ( ) bool {
return err . handled
}
2018-11-13 06:51:34 +00:00
// Move the current error into the system error slot and add a new one to the user error slot to show the user
func ( err * RouteErrorImpl ) Wrap ( userErr string ) {
err . sysText = err . userText
err . userText = userErr
}
2017-10-30 09:57:08 +00:00
func HandledRouteError ( ) RouteError {
2018-11-13 06:51:34 +00:00
return & RouteErrorImpl { "" , "" , false , false , true }
}
func Error ( errmsg string ) RouteError {
return & RouteErrorImpl { errmsg , "" , false , false , false }
}
func FromError ( err error ) RouteError {
return & RouteErrorImpl { err . Error ( ) , "" , false , false , false }
}
func ErrorJSQ ( errmsg string , isJs bool ) RouteError {
return & RouteErrorImpl { errmsg , "" , false , isJs , false }
}
func SysError ( errmsg string ) RouteError {
return & RouteErrorImpl { errmsg , errmsg , true , false , false }
2017-10-30 09:57:08 +00:00
}
2017-10-21 00:27:47 +00:00
// LogError logs internal handler errors which can't be handled with InternalError() as a wrapper for log.Fatal(), we might do more with it in the future.
2018-07-13 11:27:58 +00:00
// TODO: Clean-up extra as a way of passing additional context
func LogError ( err error , extra ... string ) {
LogWarning ( err , extra ... )
2017-10-21 00:27:47 +00:00
log . Fatal ( "" )
}
2018-07-13 11:27:58 +00:00
func LogWarning ( err error , extra ... string ) {
2018-06-06 00:21:22 +00:00
var errmsg string
2018-07-13 11:27:58 +00:00
for _ , extraBit := range extra {
errmsg += extraBit + "\n"
}
2018-06-06 00:21:22 +00:00
if err == nil {
2018-07-13 11:27:58 +00:00
errmsg += "Unknown error"
2018-06-06 00:21:22 +00:00
} else {
2018-07-13 11:27:58 +00:00
errmsg += err . Error ( )
2018-06-06 00:21:22 +00:00
}
2018-05-31 06:51:31 +00:00
stack := debug . Stack ( )
2018-06-06 00:21:22 +00:00
log . Print ( errmsg + "\n" , string ( stack ) )
2017-09-03 04:50:31 +00:00
errorBufferMutex . Lock ( )
defer errorBufferMutex . Unlock ( )
2018-05-31 06:51:31 +00:00
errorBuffer = append ( errorBuffer , ErrorItem { err , stack } )
2017-06-25 09:56:39 +00:00
}
2018-06-06 00:21:22 +00:00
func errorHeader ( w http . ResponseWriter , user User , title string ) * Header {
header := DefaultHeader ( w , user )
header . Title = title
return header
}
2017-10-30 09:57:08 +00:00
// TODO: Dump the request?
2017-09-03 04:50:31 +00:00
// InternalError is the main function for handling internal errors, while simultaneously printing out a page for the end-user to let them know that *something* has gone wrong
2017-09-22 02:21:17 +00:00
// ? - Add a user parameter?
2017-10-30 09:57:08 +00:00
func InternalError ( err error , w http . ResponseWriter , r * http . Request ) RouteError {
2018-09-28 07:19:51 +00:00
w . WriteHeader ( 500 )
2018-11-01 06:43:56 +00:00
pi := ErrorPage { errorHeader ( w , GuestUser , phrases . GetErrorPhrase ( "internal_error_title" ) ) , phrases . GetErrorPhrase ( "internal_error_body" ) }
2017-12-01 02:04:29 +00:00
handleErrorTemplate ( w , r , pi )
LogError ( err )
2017-10-30 09:57:08 +00:00
return HandledRouteError ( )
2016-12-02 07:38:54 +00:00
}
2017-09-03 04:50:31 +00:00
// InternalErrorJSQ is the JSON "maybe" version of InternalError which can handle both JSON and normal requests
2017-09-22 02:21:17 +00:00
// ? - Add a user parameter?
2017-10-30 09:57:08 +00:00
func InternalErrorJSQ ( err error , w http . ResponseWriter , r * http . Request , isJs bool ) RouteError {
2017-09-03 04:50:31 +00:00
if ! isJs {
2017-10-30 09:57:08 +00:00
return InternalError ( err , w , r )
2016-12-02 07:38:54 +00:00
}
2017-11-02 13:35:19 +00:00
return InternalErrorJS ( err , w , r )
2016-12-02 07:38:54 +00:00
}
2017-09-03 04:50:31 +00:00
// InternalErrorJS is the JSON version of InternalError on routes we know will only be requested via JSON. E.g. An API.
2017-09-22 02:21:17 +00:00
// ? - Add a user parameter?
2017-10-30 09:57:08 +00:00
func InternalErrorJS ( err error , w http . ResponseWriter , r * http . Request ) RouteError {
2017-02-28 09:27:28 +00:00
w . WriteHeader ( 500 )
2018-11-01 06:43:56 +00:00
writeJsonError ( phrases . GetErrorPhrase ( "internal_error_body" ) , w )
2017-12-01 02:04:29 +00:00
LogError ( err )
2017-10-30 09:57:08 +00:00
return HandledRouteError ( )
2017-02-28 09:27:28 +00:00
}
2018-07-15 10:29:31 +00:00
// When the task system detects if the database is down, some database errors might lip by this
func DatabaseError ( w http . ResponseWriter , r * http . Request ) RouteError {
2018-09-28 07:19:51 +00:00
w . WriteHeader ( 500 )
2018-11-01 06:43:56 +00:00
pi := ErrorPage { errorHeader ( w , GuestUser , phrases . GetErrorPhrase ( "internal_error_title" ) ) , phrases . GetErrorPhrase ( "internal_error_body" ) }
2018-07-15 10:29:31 +00:00
handleErrorTemplate ( w , r , pi )
return HandledRouteError ( )
}
2017-12-26 07:17:26 +00:00
func InternalErrorXML ( err error , w http . ResponseWriter , r * http . Request ) RouteError {
w . Header ( ) . Set ( "Content-Type" , "application/xml" )
w . WriteHeader ( 500 )
2018-09-28 07:19:51 +00:00
w . Write ( [ ] byte ( ` < ? xml version = "1.0" encoding = "UTF-8" ? >
2018-11-01 06:43:56 +00:00
< error > ` + phrases.GetErrorPhrase("internal_error_body") + ` < / error > ` ) )
2017-12-26 07:17:26 +00:00
LogError ( err )
return HandledRouteError ( )
}
// TODO: Stop killing the instance upon hitting an error with InternalError* and deprecate this
func SilentInternalErrorXML ( err error , w http . ResponseWriter , r * http . Request ) RouteError {
w . Header ( ) . Set ( "Content-Type" , "application/xml" )
w . WriteHeader ( 500 )
2018-09-28 07:19:51 +00:00
w . Write ( [ ] byte ( ` < ? xml version = "1.0" encoding = "UTF-8" ? >
2018-11-01 06:43:56 +00:00
< error > ` + phrases.GetErrorPhrase("internal_error_body") + ` < / error > ` ) )
2017-12-26 07:17:26 +00:00
log . Print ( "InternalError: " , err )
return HandledRouteError ( )
}
2017-10-30 09:57:08 +00:00
func PreError ( errmsg string , w http . ResponseWriter , r * http . Request ) RouteError {
2017-01-17 07:55:46 +00:00
w . WriteHeader ( 500 )
2018-11-01 06:43:56 +00:00
pi := ErrorPage { errorHeader ( w , GuestUser , phrases . GetErrorPhrase ( "error_title" ) ) , errmsg }
2017-12-01 02:04:29 +00:00
handleErrorTemplate ( w , r , pi )
2017-10-30 09:57:08 +00:00
return HandledRouteError ( )
2016-12-02 07:38:54 +00:00
}
2017-10-30 09:57:08 +00:00
func PreErrorJS ( errmsg string , w http . ResponseWriter , r * http . Request ) RouteError {
2017-08-18 12:16:56 +00:00
w . WriteHeader ( 500 )
2018-06-17 07:28:18 +00:00
writeJsonError ( errmsg , w )
2017-10-30 09:57:08 +00:00
return HandledRouteError ( )
2017-08-18 12:16:56 +00:00
}
2017-10-30 09:57:08 +00:00
func PreErrorJSQ ( errmsg string , w http . ResponseWriter , r * http . Request , isJs bool ) RouteError {
2017-09-03 04:50:31 +00:00
if ! isJs {
2017-10-30 09:57:08 +00:00
return PreError ( errmsg , w , r )
2017-02-05 16:36:54 +00:00
}
2017-11-02 13:35:19 +00:00
return PreErrorJS ( errmsg , w , r )
2017-02-05 16:36:54 +00:00
}
2017-09-18 17:03:52 +00:00
// LocalError is an error shown to the end-user when something goes wrong and it's not the software's fault
2018-06-06 00:21:22 +00:00
// TODO: Pass header in for this and similar errors instead of having to pass in both user and w? Would also allow for more stateful things, although this could be a problem
2017-10-30 09:57:08 +00:00
func LocalError ( errmsg string , w http . ResponseWriter , r * http . Request , user User ) RouteError {
2017-09-18 17:03:52 +00:00
w . WriteHeader ( 500 )
2018-11-01 06:43:56 +00:00
pi := ErrorPage { errorHeader ( w , user , phrases . GetErrorPhrase ( "local_error_title" ) ) , errmsg }
2017-12-01 02:04:29 +00:00
handleErrorTemplate ( w , r , pi )
2017-10-30 09:57:08 +00:00
return HandledRouteError ( )
2017-09-18 17:03:52 +00:00
}
2017-10-30 09:57:08 +00:00
func LocalErrorJSQ ( errmsg string , w http . ResponseWriter , r * http . Request , user User , isJs bool ) RouteError {
2017-09-03 04:50:31 +00:00
if ! isJs {
2017-10-30 09:57:08 +00:00
return LocalError ( errmsg , w , r , user )
2016-12-02 07:38:54 +00:00
}
2017-11-02 13:35:19 +00:00
return LocalErrorJS ( errmsg , w , r )
2016-12-02 07:38:54 +00:00
}
2017-10-30 09:57:08 +00:00
func LocalErrorJS ( errmsg string , w http . ResponseWriter , r * http . Request ) RouteError {
2017-02-28 09:27:28 +00:00
w . WriteHeader ( 500 )
2018-06-17 07:28:18 +00:00
writeJsonError ( errmsg , w )
2017-10-30 09:57:08 +00:00
return HandledRouteError ( )
2017-02-28 09:27:28 +00:00
}
2017-10-30 09:57:08 +00:00
// TODO: We might want to centralise the error logic in the future and just return what the error handler needs to construct the response rather than handling it here
2017-09-18 17:03:52 +00:00
// NoPermissions is an error shown to the end-user when they try to access an area which they aren't authorised to access
2017-10-30 09:57:08 +00:00
func NoPermissions ( w http . ResponseWriter , r * http . Request , user User ) RouteError {
2017-01-17 07:55:46 +00:00
w . WriteHeader ( 403 )
2018-11-01 06:43:56 +00:00
pi := ErrorPage { errorHeader ( w , user , phrases . GetErrorPhrase ( "no_permissions_title" ) ) , phrases . GetErrorPhrase ( "no_permissions_body" ) }
2017-12-01 02:04:29 +00:00
handleErrorTemplate ( w , r , pi )
2017-10-30 09:57:08 +00:00
return HandledRouteError ( )
2016-12-03 10:25:39 +00:00
}
2017-10-30 09:57:08 +00:00
func NoPermissionsJSQ ( w http . ResponseWriter , r * http . Request , user User , isJs bool ) RouteError {
2017-09-03 04:50:31 +00:00
if ! isJs {
2017-10-30 09:57:08 +00:00
return NoPermissions ( w , r , user )
2016-12-04 10:44:28 +00:00
}
2017-11-02 13:35:19 +00:00
return NoPermissionsJS ( w , r , user )
2016-12-04 10:44:28 +00:00
}
2017-10-30 09:57:08 +00:00
func NoPermissionsJS ( w http . ResponseWriter , r * http . Request , user User ) RouteError {
2017-09-22 02:21:17 +00:00
w . WriteHeader ( 403 )
2018-11-01 06:43:56 +00:00
writeJsonError ( phrases . GetErrorPhrase ( "no_permissions_body" ) , w )
2017-10-30 09:57:08 +00:00
return HandledRouteError ( )
2017-09-22 02:21:17 +00:00
}
2017-09-18 17:03:52 +00:00
// ? - Is this actually used? Should it be used? A ban in Gosora should be more of a permission revocation to stop them posting rather than something which spits up an error page, right?
2017-10-30 09:57:08 +00:00
func Banned ( w http . ResponseWriter , r * http . Request , user User ) RouteError {
2017-01-17 07:55:46 +00:00
w . WriteHeader ( 403 )
2018-11-01 06:43:56 +00:00
pi := ErrorPage { errorHeader ( w , user , phrases . GetErrorPhrase ( "banned_title" ) ) , phrases . GetErrorPhrase ( "banned_body" ) }
2017-12-01 02:04:29 +00:00
handleErrorTemplate ( w , r , pi )
2017-10-30 09:57:08 +00:00
return HandledRouteError ( )
2016-12-04 10:44:28 +00:00
}
2017-09-03 04:50:31 +00:00
// nolint
2017-09-18 17:03:52 +00:00
// BannedJSQ is the version of the banned error page which handles both JavaScript requests and normal page loads
2017-10-30 09:57:08 +00:00
func BannedJSQ ( w http . ResponseWriter , r * http . Request , user User , isJs bool ) RouteError {
2017-09-03 04:50:31 +00:00
if ! isJs {
2017-10-30 09:57:08 +00:00
return Banned ( w , r , user )
2016-12-02 07:38:54 +00:00
}
2017-11-02 13:35:19 +00:00
return BannedJS ( w , r , user )
2016-12-02 07:38:54 +00:00
}
2017-10-30 09:57:08 +00:00
func BannedJS ( w http . ResponseWriter , r * http . Request , user User ) RouteError {
2017-09-22 02:21:17 +00:00
w . WriteHeader ( 403 )
2018-11-01 06:43:56 +00:00
writeJsonError ( phrases . GetErrorPhrase ( "banned_body" ) , w )
2017-10-30 09:57:08 +00:00
return HandledRouteError ( )
2017-09-22 02:21:17 +00:00
}
2017-09-03 04:50:31 +00:00
// nolint
2017-10-30 09:57:08 +00:00
func LoginRequiredJSQ ( w http . ResponseWriter , r * http . Request , user User , isJs bool ) RouteError {
2017-09-03 04:50:31 +00:00
if ! isJs {
2017-11-11 04:06:16 +00:00
return LoginRequired ( w , r , user )
}
return LoginRequiredJS ( w , r , user )
}
// ? - Where is this used? Should we use it more?
// LoginRequired is an error shown to the end-user when they try to access an area which requires them to login
func LoginRequired ( w http . ResponseWriter , r * http . Request , user User ) RouteError {
w . WriteHeader ( 401 )
2018-11-01 06:43:56 +00:00
pi := ErrorPage { errorHeader ( w , user , phrases . GetErrorPhrase ( "no_permissions_title" ) ) , phrases . GetErrorPhrase ( "login_required_body" ) }
2017-12-01 02:04:29 +00:00
handleErrorTemplate ( w , r , pi )
2017-11-11 04:06:16 +00:00
return HandledRouteError ( )
}
// nolint
func LoginRequiredJS ( w http . ResponseWriter , r * http . Request , user User ) RouteError {
w . WriteHeader ( 401 )
2018-11-01 06:43:56 +00:00
writeJsonError ( phrases . GetErrorPhrase ( "login_required_body" ) , w )
2017-10-30 09:57:08 +00:00
return HandledRouteError ( )
2016-12-02 07:38:54 +00:00
}
2017-09-22 02:21:17 +00:00
// SecurityError is used whenever a session mismatch is found
// ? - Should we add JS and JSQ versions of this?
2017-10-30 09:57:08 +00:00
func SecurityError ( w http . ResponseWriter , r * http . Request , user User ) RouteError {
2017-01-17 07:55:46 +00:00
w . WriteHeader ( 403 )
2018-11-01 06:43:56 +00:00
pi := ErrorPage { errorHeader ( w , user , phrases . GetErrorPhrase ( "security_error_title" ) ) , phrases . GetErrorPhrase ( "security_error_body" ) }
2018-02-19 04:26:01 +00:00
if RunPreRenderHook ( "pre_render_security_error" , w , r , & user , & pi ) {
return nil
Added the Social Groups plugin. This is still under construction.
Made a few improvements to the ForumStore, including bringing it's API closer in line with the other datastores, adding stubs for future subforum functionality, and improving efficiency in a few places.
The auth interface now handles all the authentication stuff.
Renamed the debug config variable to debug_mode.
Added the PluginPerms API.
Internal Errors will now dump the stack trace in the console.
Added support for installable plugins.
Refactored the routing logic so that the router now handles the common PreRoute logic(exc. /static/)
Added the CreateTable method to the query generator. It might need some tweaking to better support other database systems.
Added the same CreateTable method to the query builder.
Began work on PostgreSQL support.
Added the string-string hook type
Added the pre_render hook type.
Added the ParentID and ParentType fields to forums.
Added the get_forum_url_prefix function.
Added a more generic build_slug function.
Added the get_topic_url_prefix function.
Added the override_perms and override_forum_perms functions for bulk setting and unsetting permissions.
Added more ExtData fields in a few structs and removed them on the Perms struct as the PluginPerms API supersedes them there.
Plugins can now see the router instance.
The plugin initialisation handlers can now throw errors.
Plugins are now initialised after all the forum's subsystems are.
Refactored the unit test logic. For instance, we now use the proper .Log method rather than fmt.Println in many cases.
Sorry, we'll have to break Github's generated file detection, as the build instructions aren't working, unless I put them at the top, and they're far, far more important than getting Github to recognise the generated code as generated code.
Fixed an issue with mysql.go's _init_database() overwriting the dbpassword variable. Not a huge issue, but it is a "gotcha" for those not expecting a ':' at the start.
Fixed an issue with forum creation where the forum permissions didn't get cached.
Fixed a bug in plugin_bbcode where negative numbers in rand would crash Gosora.
Made the outputs of plugin_markdown and plugin_bbcode more compliant with the tests.
Revamped the phrase system to make it easier for us to add language pack related features in the future.
Added the WidgetMenu widget type.
Revamped the theme again. I'm experimenting to see which approach I like most.
- Excuse the little W3C rage. Some things about CSS drive me crazy :p
Tests:
Added 22 bbcode_full_parse tests.
Added 19 bbcode_regex_parse tests.
Added 27 markdown_parse tests.
Added four UserStore tests. More to come when the test database functionality is added.
Added 18 name_to_slug tests.
Hooks:
Added the pre_render hook.
Added the pre_render_forum_list hook.
Added the pre_render_view_forum hook.
Added the pre_render_topic_list hook.
Added the pre_render_view_topic hook.
Added the pre_render_profile hook.
Added the pre_render_custom_page hook.
Added the pre_render_overview hook.
Added the pre_render_create_topic hook.
Added the pre_render_account_own_edit_critical hook.
Added the pre_render_account_own_edit_avatar hook.
Added the pre_render_account_own_edit_username hook.
Added the pre_render_account_own_edit_email hook.
Added the pre_render_login hook.
Added the pre_render_register hook.
Added the pre_render_ban hook.
Added the pre_render_panel_dashboard hook.
Added the pre_render_panel_forums hook.
Added the pre_render_panel_delete_forum hook.
Added the pre_render_panel_edit_forum hook.
Added the pre_render_panel_settings hook.
Added the pre_render_panel_setting hook.
Added the pre_render_panel_plugins hook.
Added the pre_render_panel_users hook.
Added the pre_render_panel_edit_user hook.
Added the pre_render_panel_groups hook.
Added the pre_render_panel_edit_group hook.
Added the pre_render_panel_edit_group_perms hook.
Added the pre_render_panel_themes hook.
Added the pre_render_panel_mod_log hook.
Added the pre_render_error hook.
Added the pre_render_security_error hook.
Added the create_group_preappend hook.
Added the intercept_build_widgets hook.
Added the simple_forum_check_pre_perms hook.
Added the forum_check_pre_perms hook.
2017-07-09 12:06:04 +00:00
}
2017-11-11 04:06:16 +00:00
err := Templates . ExecuteTemplate ( w , "error.html" , pi )
2017-09-03 04:50:31 +00:00
if err != nil {
LogError ( err )
}
2017-10-30 09:57:08 +00:00
return HandledRouteError ( )
2016-12-06 10:26:48 +00:00
}
Added Quick Topic.
Added Attachments.
Added Attachment Media Embeds.
Renamed a load of *Store and *Cache methods to reduce the amount of unneccesary typing.
Added petabytes as a unit and cleaned up a few of the friendly units.
Refactored the username change logic to make it easier to maintain.
Refactored the avatar change logic to make it easier to maintain.
Shadow now uses CSS Variables for most of it's colours. We have plans to transpile this to support older browsers later on!
Snuck some CSS Variables into Tempra Conflux.
Added the GroupCache interface to MemoryGroupStore.
Added the Length method to MemoryGroupStore.
Added support for a site short name.
Added the UploadFiles permission.
Renamed more functions.
Fixed the background for the left gutter on the postbit for Tempra Simple and Shadow.
Added support for if statements operating on int8, int16, int32, int32, int64, uint, uint8, uint16, uint32, uint64, float32, and float64 for the template compiler.
Added support for if statements operating on slices and maps for the template compiler.
Fixed a security exploit in reply editing.
Fixed a bug in the URL detector in the parser where it couldn't find URLs with non-standard ports.
Fixed buttons having blue outlines on focus on Shadow.
Refactored the topic creation logic to make it easier to maintain.
Made a few responsive fixes, but there's still more to do in the following commits!
2017-10-05 10:20:28 +00:00
// NotFound is used when the requested page doesn't exist
2018-12-27 05:42:41 +00:00
// ? - Add a JSQ version of this?
2017-09-22 02:21:17 +00:00
// ? - Add a user parameter?
2018-04-22 12:33:56 +00:00
func NotFound ( w http . ResponseWriter , r * http . Request , header * Header ) RouteError {
2018-11-01 06:43:56 +00:00
return CustomError ( phrases . GetErrorPhrase ( "not_found_body" ) , 404 , phrases . GetErrorPhrase ( "not_found_title" ) , w , r , header , GuestUser )
2016-12-06 10:26:48 +00:00
}
2018-12-27 05:42:41 +00:00
// ? - Add a user parameter?
func NotFoundJS ( w http . ResponseWriter , r * http . Request ) RouteError {
w . WriteHeader ( 401 )
writeJsonError ( phrases . GetErrorPhrase ( "not_found_body" ) , w )
return HandledRouteError ( )
}
func NotFoundJSQ ( w http . ResponseWriter , r * http . Request , header * Header , js bool ) RouteError {
if js {
return NotFoundJS ( w , r )
}
if header == nil {
header = DefaultHeader ( w , GuestUser )
}
return NotFound ( w , r , header )
}
Added Quick Topic.
Added Attachments.
Added Attachment Media Embeds.
Renamed a load of *Store and *Cache methods to reduce the amount of unneccesary typing.
Added petabytes as a unit and cleaned up a few of the friendly units.
Refactored the username change logic to make it easier to maintain.
Refactored the avatar change logic to make it easier to maintain.
Shadow now uses CSS Variables for most of it's colours. We have plans to transpile this to support older browsers later on!
Snuck some CSS Variables into Tempra Conflux.
Added the GroupCache interface to MemoryGroupStore.
Added the Length method to MemoryGroupStore.
Added support for a site short name.
Added the UploadFiles permission.
Renamed more functions.
Fixed the background for the left gutter on the postbit for Tempra Simple and Shadow.
Added support for if statements operating on int8, int16, int32, int32, int64, uint, uint8, uint16, uint32, uint64, float32, and float64 for the template compiler.
Added support for if statements operating on slices and maps for the template compiler.
Fixed a security exploit in reply editing.
Fixed a bug in the URL detector in the parser where it couldn't find URLs with non-standard ports.
Fixed buttons having blue outlines on focus on Shadow.
Refactored the topic creation logic to make it easier to maintain.
Made a few responsive fixes, but there's still more to do in the following commits!
2017-10-05 10:20:28 +00:00
// CustomError lets us make custom error types which aren't covered by the generic functions above
2018-04-22 12:33:56 +00:00
func CustomError ( errmsg string , errcode int , errtitle string , w http . ResponseWriter , r * http . Request , header * Header , user User ) RouteError {
if header == nil {
2018-06-06 00:21:22 +00:00
header = DefaultHeader ( w , user )
2018-02-19 04:26:01 +00:00
}
2018-09-28 07:19:51 +00:00
header . Title = errtitle
2017-01-17 07:55:46 +00:00
w . WriteHeader ( errcode )
2018-06-06 00:21:22 +00:00
pi := ErrorPage { header , errmsg }
2017-12-01 02:04:29 +00:00
handleErrorTemplate ( w , r , pi )
2017-10-30 09:57:08 +00:00
return HandledRouteError ( )
2017-01-03 07:47:31 +00:00
}
Added Quick Topic.
Added Attachments.
Added Attachment Media Embeds.
Renamed a load of *Store and *Cache methods to reduce the amount of unneccesary typing.
Added petabytes as a unit and cleaned up a few of the friendly units.
Refactored the username change logic to make it easier to maintain.
Refactored the avatar change logic to make it easier to maintain.
Shadow now uses CSS Variables for most of it's colours. We have plans to transpile this to support older browsers later on!
Snuck some CSS Variables into Tempra Conflux.
Added the GroupCache interface to MemoryGroupStore.
Added the Length method to MemoryGroupStore.
Added support for a site short name.
Added the UploadFiles permission.
Renamed more functions.
Fixed the background for the left gutter on the postbit for Tempra Simple and Shadow.
Added support for if statements operating on int8, int16, int32, int32, int64, uint, uint8, uint16, uint32, uint64, float32, and float64 for the template compiler.
Added support for if statements operating on slices and maps for the template compiler.
Fixed a security exploit in reply editing.
Fixed a bug in the URL detector in the parser where it couldn't find URLs with non-standard ports.
Fixed buttons having blue outlines on focus on Shadow.
Refactored the topic creation logic to make it easier to maintain.
Made a few responsive fixes, but there's still more to do in the following commits!
2017-10-05 10:20:28 +00:00
// CustomErrorJSQ is a version of CustomError which lets us handle both JSON and regular pages depending on how it's being accessed
2018-04-22 12:33:56 +00:00
func CustomErrorJSQ ( errmsg string , errcode int , errtitle string , w http . ResponseWriter , r * http . Request , header * Header , user User , isJs bool ) RouteError {
2017-09-03 04:50:31 +00:00
if ! isJs {
2018-04-22 12:33:56 +00:00
return CustomError ( errmsg , errcode , errtitle , w , r , header , user )
2016-12-02 07:38:54 +00:00
}
2017-12-01 02:04:29 +00:00
return CustomErrorJS ( errmsg , errcode , w , r , user )
2016-12-02 07:38:54 +00:00
}
2017-09-22 02:21:17 +00:00
Added Quick Topic.
Added Attachments.
Added Attachment Media Embeds.
Renamed a load of *Store and *Cache methods to reduce the amount of unneccesary typing.
Added petabytes as a unit and cleaned up a few of the friendly units.
Refactored the username change logic to make it easier to maintain.
Refactored the avatar change logic to make it easier to maintain.
Shadow now uses CSS Variables for most of it's colours. We have plans to transpile this to support older browsers later on!
Snuck some CSS Variables into Tempra Conflux.
Added the GroupCache interface to MemoryGroupStore.
Added the Length method to MemoryGroupStore.
Added support for a site short name.
Added the UploadFiles permission.
Renamed more functions.
Fixed the background for the left gutter on the postbit for Tempra Simple and Shadow.
Added support for if statements operating on int8, int16, int32, int32, int64, uint, uint8, uint16, uint32, uint64, float32, and float64 for the template compiler.
Added support for if statements operating on slices and maps for the template compiler.
Fixed a security exploit in reply editing.
Fixed a bug in the URL detector in the parser where it couldn't find URLs with non-standard ports.
Fixed buttons having blue outlines on focus on Shadow.
Refactored the topic creation logic to make it easier to maintain.
Made a few responsive fixes, but there's still more to do in the following commits!
2017-10-05 10:20:28 +00:00
// CustomErrorJS is the pure JSON version of CustomError
2017-12-01 02:04:29 +00:00
func CustomErrorJS ( errmsg string , errcode int , w http . ResponseWriter , r * http . Request , user User ) RouteError {
2017-09-22 02:21:17 +00:00
w . WriteHeader ( errcode )
2018-06-17 07:28:18 +00:00
writeJsonError ( errmsg , w )
2017-10-30 09:57:08 +00:00
return HandledRouteError ( )
2017-09-22 02:21:17 +00:00
}
2017-12-01 02:04:29 +00:00
2018-06-17 07:28:18 +00:00
// TODO: Should we optimise this by caching these json strings?
func writeJsonError ( errmsg string , w http . ResponseWriter ) {
_ , _ = w . Write ( [ ] byte ( ` { "errmsg":" ` + strings . Replace ( errmsg , "\"" , "" , - 1 ) + ` "} ` ) )
}
2018-06-06 00:21:22 +00:00
func handleErrorTemplate ( w http . ResponseWriter , r * http . Request , pi ErrorPage ) {
2017-12-01 02:04:29 +00:00
// TODO: What to do about this hook?
2018-04-22 12:33:56 +00:00
if RunPreRenderHook ( "pre_render_error" , w , r , & pi . Header . CurrentUser , & pi ) {
2018-02-19 04:26:01 +00:00
return
2017-12-01 02:04:29 +00:00
}
2018-12-08 00:45:27 +00:00
err := pi . Header . Theme . RunTmpl ( "error" , pi , w )
2017-12-01 02:04:29 +00:00
if err != nil {
LogError ( err )
}
}