The moderation logs can now be localised.

Error pages which call CustomError should now stick on the theme the user chose rather than the global fallback theme.
Move the theme fetching logic out of userCheck and panelUserCheck and into it's own function.
Split prepResources out of userCheck, so that errors can make use of it.

Fixed a bug where no scripts or stylesheets would run on error pages.
Fixed a bug where unknown topics would point to /user/ rather than /topic/

Added the panel_logs_moderation_action_topic_stick phrase.
Added the panel_logs_moderation_action_topic_unstick phrase.
Added the panel_logs_moderation_action_topic_lock phrase.
Added the panel_logs_moderation_action_topic_unlock phrase.
Added the panel_logs_moderation_action_topic_delete phrase.
Added the panel_logs_moderation_action_topic_move phrase.
Added the panel_logs_moderation_action_topic_move_dest phrase.
Added the panel_logs_moderation_action_topic_unknown phrase.
Added the panel_logs_moderation_action_reply_delete phrase.
Added the panel_logs_moderation_action_user_ban phrase.
Added the panel_logs_moderation_action_user_unban phrase.
Added the panel_logs_moderation_action_user_activate phrase.
Added the panel_logs_moderation_action_unknown phrase.
Added the user_unknown phrase.
This commit is contained in:
Azareal 2019-04-18 11:00:39 +10:00
parent 2d366ce6a0
commit 9179eb9711
5 changed files with 59 additions and 45 deletions

View File

@ -129,12 +129,14 @@ func errorHeader(w http.ResponseWriter, user User, title string) *Header {
header := DefaultHeader(w, user)
header.Title = title
header.Zone = "error"
prepResources(&user, header, header.Theme)
return header
}
// TODO: Dump the request?
// 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
// ? - Add a user parameter?
// ! Do not call CustomError here or we might get an error loop
func InternalError(err error, w http.ResponseWriter, r *http.Request) RouteError {
w.WriteHeader(500)
pi := ErrorPage{errorHeader(w, GuestUser, phrases.GetErrorPhrase("internal_error_title")), phrases.GetErrorPhrase("internal_error_body")}
@ -188,6 +190,7 @@ func SilentInternalErrorXML(err error, w http.ResponseWriter, r *http.Request) R
return HandledRouteError()
}
// ! Do not call CustomError here otherwise we might get an error loop
func PreError(errmsg string, w http.ResponseWriter, r *http.Request) RouteError {
w.WriteHeader(500)
pi := ErrorPage{errorHeader(w, GuestUser, phrases.GetErrorPhrase("error_title")), errmsg}
@ -342,9 +345,12 @@ func NotFoundJSQ(w http.ResponseWriter, r *http.Request, header *Header, js bool
}
// CustomError lets us make custom error types which aren't covered by the generic functions above
func CustomError(errmsg string, errcode int, errtitle string, w http.ResponseWriter, r *http.Request, header *Header, user User) RouteError {
func CustomError(errmsg string, errcode int, errtitle string, w http.ResponseWriter, r *http.Request, header *Header, user User) (rerr RouteError) {
if header == nil {
header = DefaultHeader(w, user)
header, rerr = UserCheck(w, r, &user)
if rerr != nil {
header = errorHeader(w, user, errtitle)
}
}
header.Title = errtitle
header.Zone = "error"

View File

@ -95,18 +95,7 @@ func cascadeForumPerms(fperms *ForumPerms, user *User) {
// Even if they have the right permissions, the control panel is only open to supermods+. There are many areas without subpermissions which assume that the current user is a supermod+ and admins are extremely unlikely to give these permissions to someone who isn't at-least a supermod to begin with
// TODO: Do a panel specific theme?
func panelUserCheck(w http.ResponseWriter, r *http.Request, user *User) (header *Header, stats PanelStats, rerr RouteError) {
var theme = &Theme{Name: ""}
cookie, err := r.Cookie("current_theme")
if err == nil {
inTheme, ok := Themes[html.EscapeString(cookie.Value)]
if ok && !theme.HideFromThemes {
theme = inTheme
}
}
if theme.Name == "" {
theme = Themes[DefaultThemeBox.Load().(string)]
}
theme := getTheme(r)
header = &Header{
Site: Site,
Settings: SettingBox.Load().(SettingMap),
@ -186,8 +175,7 @@ func simpleUserCheck(w http.ResponseWriter, r *http.Request, user *User) (header
}, nil
}
// TODO: Add the ability for admins to restrict certain themes to certain groups?
func userCheck(w http.ResponseWriter, r *http.Request, user *User) (header *Header, rerr RouteError) {
func getTheme(r *http.Request) *Theme {
var theme = &Theme{Name: ""}
cookie, err := r.Cookie("current_theme")
@ -201,6 +189,13 @@ func userCheck(w http.ResponseWriter, r *http.Request, user *User) (header *Head
theme = Themes[DefaultThemeBox.Load().(string)]
}
return theme
}
// TODO: Add the ability for admins to restrict certain themes to certain groups?
// ! Be careful about firing errors off here as CustomError uses this
func userCheck(w http.ResponseWriter, r *http.Request, user *User) (header *Header, rerr RouteError) {
theme := getTheme(r)
header = &Header{
Site: Site,
Settings: SettingBox.Load().(SettingMap),
@ -220,13 +215,20 @@ func userCheck(w http.ResponseWriter, r *http.Request, user *User) (header *Head
if user.Loggedin && !user.Active {
header.AddNotice("account_inactive")
}
// An optimisation so we don't populate StartedAt for users who shouldn't see the stat anyway
// ? - Should we only show this in debug mode? It might be useful for detecting issues in production, if we show it there as-well
if user.IsAdmin {
header.StartedAt = time.Now()
}
prepResources(user,header,theme)
return header, nil
}
func prepResources(user *User, header *Header, theme *Theme) {
header.AddSheet(theme.Name + "/main.css")
if len(theme.Resources) > 0 {
rlist := theme.Resources
for _, resource := range rlist {
@ -269,8 +271,6 @@ func userCheck(w http.ResponseWriter, r *http.Request, user *User) (header *Head
addPreScript("topic_c_edit_post")
addPreScript("topic_c_attach_item")
}
return header, nil
}
func preRoute(w http.ResponseWriter, r *http.Request) (User, bool) {

View File

@ -903,7 +903,24 @@
"panel_logs_registration_attempt":"Attempt",
"panel_logs_registration_email":"email",
"panel_logs_registration_reason":"reason",
"panel_logs_moderation_head":"Mod Action Logs",
"panel_logs_moderation_action_topic_stick":"<a href='%s'>%s</a> was pinned by <a href='%s'>%s</a>",
"panel_logs_moderation_action_topic_unstick":"<a href='%s'>%s</a> was unpinned by <a href='%s'>%s</a>",
"panel_logs_moderation_action_topic_lock":"<a href='%s'>%s</a> was locked by <a href='%s'>%s</a>",
"panel_logs_moderation_action_topic_unlock":"<a href='%s'>%s</a> was reopened by <a href='%s'>%s</a>",
"panel_logs_moderation_action_topic_delete":"Topic #%d was deleted by <a href='%s'>%s</a>",
"panel_logs_moderation_action_topic_move":"<a href='%s'>%s</a> was moved by <a href='%s'>%s</a>",
"panel_logs_moderation_action_topic_move_dest":"<a href='%s'>%s</a> was moved to <a href='%s'>%s</a> by <a href='%s'>%s</a>",
"panel_logs_moderation_action_topic_unknown":"Unknown action '%s' on elementType '%s' by <a href='%s'>%s</a>",
"panel_logs_moderation_action_reply_delete":"A reply in <a href='%s'>%s</a> was deleted by <a href='%s'>%s</a>",
"panel_logs_moderation_action_user_ban":"<a href='%s'>%s</a> was banned by <a href='%s'>%s</a>",
"panel_logs_moderation_action_user_unban":"<a href='%s'>%s</a> was unbanned by <a href='%s'>%s</a>",
"panel_logs_moderation_action_user_activate":"<a href='%s'>%s</a> was activated by <a href='%s'>%s</a>",
"panel_logs_moderation_action_unknown":"Unknown action '%s' on elementType '%s' by <a href='%s'>%s</a>",
"user_unknown":"Unknown",
"panel_logs_administration_head":"Admin Action Logs",
"panel_plugins_head":"Plugins",

View File

@ -8,6 +8,7 @@ import (
"strings"
"github.com/Azareal/Gosora/common"
"github.com/Azareal/Gosora/common/phrases"
)
// TODO: Link the usernames for successful registrations to the profiles
@ -37,46 +38,44 @@ func LogsRegs(w http.ResponseWriter, r *http.Request, user common.User) common.R
}
// TODO: Log errors when something really screwy is going on?
// TODO: Base the slugs on the localised usernames?
func handleUnknownUser(user *common.User, err error) *common.User {
if err != nil {
return &common.User{Name: "Unknown", Link: common.BuildProfileURL("unknown", 0)}
return &common.User{Name: phrases.GetTmplPhrase("user_unknown"), Link: common.BuildProfileURL("unknown", 0)}
}
return user
}
func handleUnknownTopic(topic *common.Topic, err error) *common.Topic {
if err != nil {
return &common.Topic{Title: "Unknown", Link: common.BuildProfileURL("unknown", 0)}
return &common.Topic{Title: phrases.GetTmplPhrase("user_unknown"), Link: common.BuildTopicURL("unknown", 0)}
}
return topic
}
// TODO: Move the log building logic into /common/ and it's own abstraction
// TODO: Localise this
func topicElementTypeAction(action string, elementType string, elementID int, actor *common.User, topic *common.Topic) (out string) {
if action == "delete" {
return fmt.Sprintf("Topic #%d was deleted by <a href='%s'>%s</a>", elementID, actor.Link, actor.Name)
return phrases.GetTmplPhrasef("panel_logs_moderation_action_topic_delete", elementID, actor.Link, actor.Name)
}
var tbit string
aarr := strings.Split(action, "-")
switch aarr[0] {
case "lock":
out = "<a href='%s'>%s</a> was locked by <a href='%s'>%s</a>"
case "unlock":
out = "<a href='%s'>%s</a> was reopened by <a href='%s'>%s</a>"
case "stick":
out = "<a href='%s'>%s</a> was pinned by <a href='%s'>%s</a>"
case "unstick":
out = "<a href='%s'>%s</a> was unpinned by <a href='%s'>%s</a>"
case "lock","unlock","stick","unstick":
tbit = aarr[0]
case "move":
if len(aarr) == 2 {
fid, _ := strconv.Atoi(aarr[1])
forum, err := common.Forums.Get(fid)
if err == nil {
return fmt.Sprintf("<a href='%s'>%s</a> was moved to <a href='%s'>%s</a> by <a href='%s'>%s</a>", topic.Link, topic.Title, forum.Link, forum.Name, actor.Link, actor.Name)
return phrases.GetTmplPhrasef("panel_logs_moderation_action_topic_move_dest", topic.Link, topic.Title, forum.Link, forum.Name, actor.Link, actor.Name)
}
}
out = "<a href='%s'>%s</a> was moved by <a href='%s'>%s</a>" // TODO: Add where it was moved to, we'll have to change the source data for that, most likely? Investigate that and try to work this in
tbit = "move"
default:
return fmt.Sprintf("Unknown action '%s' on elementType '%s' by <a href='%s'>%s</a>", action, elementType, actor.Link, actor.Name)
return phrases.GetTmplPhrasef("panel_logs_moderation_action_topic_unknown", action, elementType, actor.Link, actor.Name)
}
if tbit != "" {
return phrases.GetTmplPhrasef("panel_logs_moderation_action_topic_"+tbit, topic.Link, topic.Title, actor.Link, actor.Name)
}
return fmt.Sprintf(out, topic.Link, topic.Title, actor.Link, actor.Name)
}
@ -88,24 +87,16 @@ func modlogsElementType(action string, elementType string, elementID int, actor
out = topicElementTypeAction(action, elementType, elementID, actor, topic)
case "user":
targetUser := handleUnknownUser(common.Users.Get(elementID))
switch action {
case "ban":
out = "<a href='%s'>%s</a> was banned by <a href='%s'>%s</a>"
case "unban":
out = "<a href='%s'>%s</a> was unbanned by <a href='%s'>%s</a>"
case "activate":
out = "<a href='%s'>%s</a> was activated by <a href='%s'>%s</a>"
}
out = fmt.Sprintf(out, targetUser.Link, targetUser.Name, actor.Link, actor.Name)
out = phrases.GetTmplPhrasef("panel_logs_moderation_action_user_"+action, targetUser.Link, targetUser.Name, actor.Link, actor.Name)
case "reply":
if action == "delete" {
topic := handleUnknownTopic(common.TopicByReplyID(elementID))
out = fmt.Sprintf("A reply in <a href='%s'>%s</a> was deleted by <a href='%s'>%s</a>", topic.Link, topic.Title, actor.Link, actor.Name)
out = phrases.GetTmplPhrasef("panel_logs_moderation_action_reply_delete", topic.Link, topic.Title, actor.Link, actor.Name)
}
}
if out == "" {
out = fmt.Sprintf("Unknown action '%s' on elementType '%s' by <a href='%s'>%s</a>", action, elementType, actor.Link, actor.Name)
out = phrases.GetTmplPhrasef("panel_logs_moderation_action_unknown", action, elementType, actor.Link, actor.Name)
}
return out
}

View File

@ -51,7 +51,7 @@ func ViewTopic(w http.ResponseWriter, r *http.Request, user common.User, header
// Get the topic...
topic, err := common.GetTopicUser(&user, tid)
if err == sql.ErrNoRows {
return common.NotFound(w, r, nil) // TODO: Can we add a simplified invocation of headerVars here? This is likely to be an extremely common NotFound
return common.NotFound(w, r, nil) // TODO: Can we add a simplified invocation of header here? This is likely to be an extremely common NotFound
} else if err != nil {
return common.InternalError(err, w, r)
}