diff --git a/common/errors.go b/common/errors.go index 6d095eac..f0485dff 100644 --- a/common/errors.go +++ b/common/errors.go @@ -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" diff --git a/common/routes_common.go b/common/routes_common.go index 8c7ee2c8..c235d903 100644 --- a/common/routes_common.go +++ b/common/routes_common.go @@ -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) { diff --git a/langs/english.json b/langs/english.json index 572857b9..252ced77 100644 --- a/langs/english.json +++ b/langs/english.json @@ -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":"%s was pinned by %s", + "panel_logs_moderation_action_topic_unstick":"%s was unpinned by %s", + "panel_logs_moderation_action_topic_lock":"%s was locked by %s", + "panel_logs_moderation_action_topic_unlock":"%s was reopened by %s", + "panel_logs_moderation_action_topic_delete":"Topic #%d was deleted by %s", + "panel_logs_moderation_action_topic_move":"%s was moved by %s", + "panel_logs_moderation_action_topic_move_dest":"%s was moved to %s by %s", + "panel_logs_moderation_action_topic_unknown":"Unknown action '%s' on elementType '%s' by %s", + "panel_logs_moderation_action_reply_delete":"A reply in %s was deleted by %s", + "panel_logs_moderation_action_user_ban":"%s was banned by %s", + "panel_logs_moderation_action_user_unban":"%s was unbanned by %s", + "panel_logs_moderation_action_user_activate":"%s was activated by %s", + "panel_logs_moderation_action_unknown":"Unknown action '%s' on elementType '%s' by %s", + + "user_unknown":"Unknown", + "panel_logs_administration_head":"Admin Action Logs", "panel_plugins_head":"Plugins", diff --git a/routes/panel/logs.go b/routes/panel/logs.go index 6e6c6e55..699d0c58 100644 --- a/routes/panel/logs.go +++ b/routes/panel/logs.go @@ -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 %s", 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 = "%s was locked by %s" - case "unlock": - out = "%s was reopened by %s" - case "stick": - out = "%s was pinned by %s" - case "unstick": - out = "%s was unpinned by %s" + 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("%s was moved to %s by %s", 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 = "%s was moved by %s" // 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 %s", 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 = "%s was banned by %s" - case "unban": - out = "%s was unbanned by %s" - case "activate": - out = "%s was activated by %s" - } - 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 %s was deleted by %s", 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 %s", action, elementType, actor.Link, actor.Name) + out = phrases.GetTmplPhrasef("panel_logs_moderation_action_unknown", action, elementType, actor.Link, actor.Name) } return out } diff --git a/routes/topic.go b/routes/topic.go index d42dbdba..234e0910 100644 --- a/routes/topic.go +++ b/routes/topic.go @@ -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) }