diff --git a/common/page_store.go b/common/page_store.go
index 74017d76..4c0288bd 100644
--- a/common/page_store.go
+++ b/common/page_store.go
@@ -38,12 +38,12 @@ func BlankCustomPage() *CustomPage {
return new(CustomPage)
}
-func (page *CustomPage) AddAllowedGroup(gid int) {
- page.AllowedGroups = append(page.AllowedGroups, gid)
+func (p *CustomPage) AddAllowedGroup(gid int) {
+ p.AllowedGroups = append(p.AllowedGroups, gid)
}
-func (page *CustomPage) getRawAllowedGroups() (rawAllowedGroups string) {
- for _, group := range page.AllowedGroups {
+func (p *CustomPage) getRawAllowedGroups() (rawAllowedGroups string) {
+ for _, group := range p.AllowedGroups {
rawAllowedGroups += strconv.Itoa(group) + ","
}
if len(rawAllowedGroups) > 0 {
@@ -52,18 +52,17 @@ func (page *CustomPage) getRawAllowedGroups() (rawAllowedGroups string) {
return rawAllowedGroups
}
-func (page *CustomPage) Commit() error {
- _, err := customPageStmts.update.Exec(page.Name, page.Title, page.Body, page.getRawAllowedGroups(), page.MenuID, page.ID)
- Pages.Reload(page.ID)
+func (p *CustomPage) Commit() error {
+ _, err := customPageStmts.update.Exec(p.Name, p.Title, p.Body, p.getRawAllowedGroups(), p.MenuID, p.ID)
+ Pages.Reload(p.ID)
return err
}
-func (page *CustomPage) Create() (int, error) {
- res, err := customPageStmts.create.Exec(page.Name, page.Title, page.Body, page.getRawAllowedGroups(), page.MenuID)
+func (p *CustomPage) Create() (int, error) {
+ res, err := customPageStmts.create.Exec(p.Name, p.Title, p.Body, p.getRawAllowedGroups(), p.MenuID)
if err != nil {
return 0, err
}
-
pid64, err := res.LastInsertId()
return int(pid64), err
}
diff --git a/common/word_filters.go b/common/word_filters.go
index 55b1deb7..798b74c3 100644
--- a/common/word_filters.go
+++ b/common/word_filters.go
@@ -4,7 +4,7 @@ import (
"database/sql"
"sync/atomic"
- "github.com/Azareal/Gosora/query_gen"
+ qgen "github.com/Azareal/Gosora/query_gen"
)
// TODO: Move some features into methods on this?
@@ -19,7 +19,8 @@ var WordFilters WordFilterStore
type WordFilterStore interface {
ReloadAll() error
GetAll() (filters map[int]*WordFilter, err error)
- Create(find string, replacement string) error
+ Get(id int) (*WordFilter, error)
+ Create(find string, replacement string) (int, error)
Delete(id int) error
Update(id int, find string, replacement string) error
Length() int
@@ -31,6 +32,7 @@ type DefaultWordFilterStore struct {
box atomic.Value // An atomic value holding a WordFilterMap
getAll *sql.Stmt
+ get *sql.Stmt
create *sql.Stmt
delete *sql.Stmt
update *sql.Stmt
@@ -41,6 +43,7 @@ func NewDefaultWordFilterStore(acc *qgen.Accumulator) (*DefaultWordFilterStore,
wf := "word_filters"
store := &DefaultWordFilterStore{
getAll: acc.Select(wf).Columns("wfid,find,replacement").Prepare(),
+ get: acc.Select(wf).Columns("wfid,find,replacement").Where("wfid = ?").Prepare(),
create: acc.Insert(wf).Columns("find,replacement").Fields("?,?").Prepare(),
delete: acc.Delete(wf).Where("wfid = ?").Prepare(),
update: acc.Update(wf).Set("find = ?, replacement = ?").Where("wfid = ?").Prepare(),
@@ -93,13 +96,23 @@ func (s *DefaultWordFilterStore) GetAll() (filters map[int]*WordFilter, err erro
return s.box.Load().(map[int]*WordFilter), nil
}
+func (s *DefaultWordFilterStore) Get(id int) (*WordFilter, error) {
+ wf := &WordFilter{ID: id}
+ err := s.get.QueryRow(id).Scan(&wf.Find, &wf.Replacement)
+ return wf, err
+}
+
// Create adds a new word filter to the database and refreshes the memory cache
-func (s *DefaultWordFilterStore) Create(find string, replace string) error {
- _, err := s.create.Exec(find, replace)
+func (s *DefaultWordFilterStore) Create(find string, replace string) (int, error) {
+ res, err := s.create.Exec(find, replace)
if err != nil {
- return err
+ return 0, err
}
- return s.ReloadAll()
+ id64, err := res.LastInsertId()
+ if err != nil {
+ return 0, err
+ }
+ return int(id64), s.ReloadAll()
}
// Delete removes a word filter from the database and refreshes the memory cache
diff --git a/langs/english.json b/langs/english.json
index 6ae0b5a4..cd4b2ed6 100644
--- a/langs/english.json
+++ b/langs/english.json
@@ -1021,6 +1021,8 @@
"topic_unknown":"Unknown",
"group_unknown":"Unknown",
"forum_unknown":"Unknown",
+ "page_unknown":"Unknown",
+ "setting_unknown":"unknown",
"panel_logs_administration_head":"Admin Action Logs",
"panel_logs_administration_action_user_edit":"User %s was modified by %s",
@@ -1032,6 +1034,14 @@
"panel_logs_administration_action_forum_create":"Forum %s was created by %s",
"panel_logs_administration_action_forum_delete":"Forum %s was deleted by %s",
"panel_logs_administration_action_forum_edit":"Forum %s was modified by %s",
+ "panel_logs_administration_action_page_create":"Page %s was created by %s",
+ "panel_logs_administration_action_page_delete":"Page %s was deleted by %s",
+ "panel_logs_administration_action_page_edit":"Page %s was modified by %s",
+ "panel_logs_administration_action_setting_edit":"Setting %s was modified by %s",
+ "panel_logs_administration_action_word_filter_create":"Word Filter %d was created by %s",
+ "panel_logs_administration_action_word_filter_delete":"Word Filter %d was deleted by %s",
+ "panel_logs_administration_action_word_filter_edit":"Word Filter %d was modified by %s",
+ "panel_logs_administration_action_backup_download":"A backup was downloaded by %s",
"panel_logs_administration_action_unknown":"Unknown action '%s' on elementType '%s' by %s",
"panel_logs_administration_no_logs":"There aren't any events logged.",
diff --git a/routes/panel/backups.go b/routes/panel/backups.go
index 6affcdbc..f3946ce9 100644
--- a/routes/panel/backups.go
+++ b/routes/panel/backups.go
@@ -28,19 +28,24 @@ func Backups(w http.ResponseWriter, r *http.Request, user c.User, backupURL stri
if err != nil {
return c.NotFound(w, r, basePage.Header)
}
- w.Header().Set("Content-Length", strconv.FormatInt(info.Size(), 10))
+ h := w.Header()
+ h.Set("Content-Length", strconv.FormatInt(info.Size(), 10))
if ext == ".sql" {
- // TODO: Change the served filename to gosora_backup_%timestamp%.sql, the time the file was generated, not when it was modified aka what the name of it should be
- w.Header().Set("Content-Disposition", "attachment; filename=gosora_backup.sql")
- w.Header().Set("Content-Type", "application/sql")
+ // TODO: Change the served filename to gosora_backup_%timestamp%.sql, the time the file was generated, not when it was modified aka what the name of it should be
+ h.Set("Content-Disposition", "attachment; filename=gosora_backup.sql")
+ h.Set("Content-Type", "application/sql")
} else {
- // TODO: Change the served filename to gosora_backup_%timestamp%.zip, the time the file was generated, not when it was modified aka what the name of it should be
- w.Header().Set("Content-Disposition", "attachment; filename=gosora_backup.zip")
- w.Header().Set("Content-Type", "application/zip")
+ // TODO: Change the served filename to gosora_backup_%timestamp%.zip, the time the file was generated, not when it was modified aka what the name of it should be
+ h.Set("Content-Disposition", "attachment; filename=gosora_backup.zip")
+ h.Set("Content-Type", "application/zip")
}
// TODO: Fix the problem where non-existent files aren't greeted with custom 404s on ServeFile()'s side
http.ServeFile(w, r, "./backups/"+backupURL)
+ err = c.AdminLogs.Create("download", 0, "backup", user.LastIP, user.ID)
+ if err != nil {
+ return c.InternalError(err, w, r)
+ }
return nil
}
diff --git a/routes/panel/logs.go b/routes/panel/logs.go
index bf1c7333..3479a45e 100644
--- a/routes/panel/logs.go
+++ b/routes/panel/logs.go
@@ -124,6 +124,26 @@ func adminlogsElementType(action string, elementType string, elementID int, acto
} else {
out = p.GetTmplPhrasef("panel_logs_administration_action_forum_"+action, "/panel/forums/edit/"+strconv.Itoa(f.ID), f.Name, actor.Link, actor.Name)
}
+ case "page":
+ pp, err := c.Pages.Get(elementID)
+ if err != nil {
+ pp = &c.CustomPage{Name: p.GetTmplPhrase("page_unknown")}
+ }
+ out = p.GetTmplPhrasef("panel_logs_administration_action_page_"+action, "/panel/pages/edit/"+strconv.Itoa(pp.ID), pp.Name, actor.Link, actor.Name)
+ case "setting":
+ s, err := c.SettingBox.Load().(c.SettingMap).BypassGet(action)
+ if err != nil {
+ s = &c.Setting{Name: p.GetTmplPhrase("setting_unknown")}
+ }
+ out = p.GetTmplPhrasef("panel_logs_administration_action_setting_edit", "/panel/settings/edit/"+s.Name, s.Name, actor.Link, actor.Name)
+ case "word_filter":
+ wf, err := c.WordFilters.Get(elementID)
+ if err != nil {
+ wf = &c.WordFilter{}
+ }
+ out = p.GetTmplPhrasef("panel_logs_administration_action_word_filter_"+action, "/panel/settings/word-filters/", wf.ID, actor.Link, actor.Name)
+ case "backup":
+ out = p.GetTmplPhrasef("panel_logs_administration_action_backup_"+action, actor.Link, actor.Name)
}
if out == "" {
out = p.GetTmplPhrasef("panel_logs_administration_action_unknown", action, elementType, actor.Link, actor.Name)
diff --git a/routes/panel/pages.go b/routes/panel/pages.go
index a5577fb6..454999b4 100644
--- a/routes/panel/pages.go
+++ b/routes/panel/pages.go
@@ -42,24 +42,28 @@ func PagesCreateSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.Ro
return ferr
}
- pname := r.PostFormValue("name")
- if pname == "" {
+ name := c.SanitiseSingleLine(r.PostFormValue("name"))
+ if name == "" {
return c.LocalError("No name was provided for this page", w, r, user)
}
- ptitle := r.PostFormValue("title")
- if ptitle == "" {
+ title := c.SanitiseSingleLine(r.PostFormValue("title"))
+ if title == "" {
return c.LocalError("No title was provided for this page", w, r, user)
}
- pbody := r.PostFormValue("body")
- if pbody == "" {
+ body := r.PostFormValue("body")
+ if body == "" {
return c.LocalError("No body was provided for this page", w, r, user)
}
page := c.BlankCustomPage()
- page.Name = pname
- page.Title = ptitle
- page.Body = pbody
- _, err := page.Create()
+ page.Name = name
+ page.Title = title
+ page.Body = body
+ pid, err := page.Create()
+ if err != nil {
+ return c.InternalError(err, w, r)
+ }
+ err = c.AdminLogs.Create("create", pid, "page", user.LastIP, user.ID)
if err != nil {
return c.InternalError(err, w, r)
}
@@ -102,16 +106,16 @@ func PagesEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, spid s
if err != nil {
return c.LocalError("Page ID needs to be an integer", w, r, user)
}
- pname := r.PostFormValue("name")
- if pname == "" {
+ name := c.SanitiseSingleLine(r.PostFormValue("name"))
+ if name == "" {
return c.LocalError("No name was provided for this page", w, r, user)
}
- ptitle := r.PostFormValue("title")
- if ptitle == "" {
+ title := c.SanitiseSingleLine(r.PostFormValue("title"))
+ if title == "" {
return c.LocalError("No title was provided for this page", w, r, user)
}
- pbody := r.PostFormValue("body")
- if pbody == "" {
+ body := r.PostFormValue("body")
+ if body == "" {
return c.LocalError("No body was provided for this page", w, r, user)
}
@@ -119,13 +123,17 @@ func PagesEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, spid s
if err != nil {
return c.NotFound(w, r, nil)
}
- page.Name = pname
- page.Title = ptitle
- page.Body = pbody
+ page.Name = name
+ page.Title = title
+ page.Body = body
err = page.Commit()
if err != nil {
return c.InternalError(err, w, r)
}
+ err = c.AdminLogs.Create("edit", pid, "page", user.LastIP, user.ID)
+ if err != nil {
+ return c.InternalError(err, w, r)
+ }
http.Redirect(w, r, "/panel/pages/?updated=1", http.StatusSeeOther)
return nil
@@ -145,6 +153,10 @@ func PagesDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.User, spid
if err != nil {
return c.InternalError(err, w, r)
}
+ err = c.AdminLogs.Create("delete", pid, "page", user.LastIP, user.ID)
+ if err != nil {
+ return c.InternalError(err, w, r)
+ }
http.Redirect(w, r, "/panel/pages/?deleted=1", http.StatusSeeOther)
return nil
diff --git a/routes/panel/settings.go b/routes/panel/settings.go
index 280f87c6..ac1fbd3f 100644
--- a/routes/panel/settings.go
+++ b/routes/panel/settings.go
@@ -77,7 +77,6 @@ func SettingEdit(w http.ResponseWriter, r *http.Request, user c.User, sname stri
if err != nil {
return c.LocalError("The value of this setting couldn't be converted to an integer", w, r, user)
}
-
for index, label := range strings.Split(llist, ",") {
itemList = append(itemList, c.OptionLabel{
Label: label,
@@ -94,7 +93,7 @@ func SettingEdit(w http.ResponseWriter, r *http.Request, user c.User, sname stri
return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "", "", "panel_setting", &pi})
}
-func SettingEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, sname string) c.RouteError {
+func SettingEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, name string) c.RouteError {
headerLite, ferr := c.SimplePanelUserCheck(w, r, &user)
if ferr != nil {
return ferr
@@ -103,11 +102,17 @@ func SettingEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, snam
return c.NoPermissions(w, r, user)
}
- scontent := c.SanitiseBody(r.PostFormValue("value"))
- rerr := headerLite.Settings.Update(sname, scontent)
+ name = c.SanitiseSingleLine(name)
+ content := c.SanitiseBody(r.PostFormValue("value"))
+ rerr := headerLite.Settings.Update(name, content)
if rerr != nil {
return rerr
}
+ // TODO: Avoid this hack
+ err := c.AdminLogs.Create(name, 0, "setting", user.LastIP, user.ID)
+ if err != nil {
+ return c.InternalError(err, w, r)
+ }
http.Redirect(w, r, "/panel/settings/", http.StatusSeeOther)
return nil
diff --git a/routes/panel/word_filters.go b/routes/panel/word_filters.go
index 6be12bc7..c022ee06 100644
--- a/routes/panel/word_filters.go
+++ b/routes/panel/word_filters.go
@@ -47,10 +47,14 @@ func WordFiltersCreateSubmit(w http.ResponseWriter, r *http.Request, user c.User
// Unlike with find, it's okay if we leave this blank, as this means that the admin wants to remove the word entirely with no replacement
replace := strings.TrimSpace(r.PostFormValue("replace"))
- err := c.WordFilters.Create(find, replace)
+ wfid, err := c.WordFilters.Create(find, replace)
if err != nil {
return c.InternalErrorJSQ(err, w, r, js)
}
+ err = c.AdminLogs.Create("create", wfid, "word_filter", user.LastIP, user.ID)
+ if err != nil {
+ return c.InternalError(err, w, r)
+ }
return successRedirect("/panel/settings/word-filters/", w, r, js)
}
@@ -70,7 +74,7 @@ func WordFiltersEdit(w http.ResponseWriter, r *http.Request, user c.User, wfid s
return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "", "", "panel_word_filters_edit", &pi})
}
-func WordFiltersEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, wfid string) c.RouteError {
+func WordFiltersEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, swfid string) c.RouteError {
_, ferr := c.SimplePanelUserCheck(w, r, &user)
if ferr != nil {
return ferr
@@ -80,11 +84,10 @@ func WordFiltersEditSubmit(w http.ResponseWriter, r *http.Request, user c.User,
return c.NoPermissionsJSQ(w, r, user, js)
}
- id, err := strconv.Atoi(wfid)
+ wfid, err := strconv.Atoi(swfid)
if err != nil {
return c.LocalErrorJSQ("The word filter ID must be an integer.", w, r, user, js)
}
-
find := strings.TrimSpace(r.PostFormValue("find"))
if find == "" {
return c.LocalErrorJSQ("You need to specify what word you want to match", w, r, user, js)
@@ -92,35 +95,41 @@ func WordFiltersEditSubmit(w http.ResponseWriter, r *http.Request, user c.User,
// Unlike with find, it's okay if we leave this blank, as this means that the admin wants to remove the word entirely with no replacement
replace := strings.TrimSpace(r.PostFormValue("replace"))
- err = c.WordFilters.Update(id, find, replace)
+ err = c.WordFilters.Update(wfid, find, replace)
if err != nil {
return c.InternalErrorJSQ(err, w, r, js)
}
+ err = c.AdminLogs.Create("edit", wfid, "word_filter", user.LastIP, user.ID)
+ if err != nil {
+ return c.InternalError(err, w, r)
+ }
http.Redirect(w, r, "/panel/settings/word-filters/", http.StatusSeeOther)
return nil
}
-func WordFiltersDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.User, wfid string) c.RouteError {
+func WordFiltersDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.User, swfid string) c.RouteError {
_, ferr := c.SimplePanelUserCheck(w, r, &user)
if ferr != nil {
return ferr
}
-
js := (r.PostFormValue("js") == "1")
if !user.Perms.EditSettings {
return c.NoPermissionsJSQ(w, r, user, js)
}
- id, err := strconv.Atoi(wfid)
+ wfid, err := strconv.Atoi(swfid)
if err != nil {
return c.LocalErrorJSQ("The word filter ID must be an integer.", w, r, user, js)
}
-
- err = c.WordFilters.Delete(id)
+ err = c.WordFilters.Delete(wfid)
if err == sql.ErrNoRows {
return c.LocalErrorJSQ("This word filter doesn't exist", w, r, user, js)
}
+ err = c.AdminLogs.Create("delete", wfid, "word_filter", user.LastIP, user.ID)
+ if err != nil {
+ return c.InternalError(err, w, r)
+ }
http.Redirect(w, r, "/panel/settings/word-filters/", http.StatusSeeOther)
return nil