Users can now delete their own posts.

Merge GlobalPerms and LocalPerms phrase spaces into Perms.
Shorten more things and eliminate boilerplate.
This commit is contained in:
Azareal 2019-10-06 21:32:00 +10:00
parent 45a3065db1
commit a5f77c376b
15 changed files with 98 additions and 141 deletions

View File

@ -25,12 +25,12 @@ func main() {
}() }()
log.Println("Running the query generator") log.Println("Running the query generator")
for _, adapter := range qgen.Registry { for _, a := range qgen.Registry {
log.Printf("Building the queries for the %s adapter", adapter.GetName()) log.Printf("Building the queries for the %s adapter", a.GetName())
qgen.Install.SetAdapterInstance(adapter) qgen.Install.SetAdapterInstance(a)
qgen.Install.AddPlugins(NewPrimaryKeySpitter()) // TODO: Do we really need to fill the spitter for every adapter? qgen.Install.AddPlugins(NewPrimaryKeySpitter()) // TODO: Do we really need to fill the spitter for every adapter?
err := writeStatements(adapter) err := writeStatements(a)
if err != nil { if err != nil {
log.Print(err) log.Print(err)
} }
@ -38,7 +38,7 @@ func main() {
if err != nil { if err != nil {
log.Print(err) log.Print(err)
} }
err = adapter.Write() err = a.Write()
if err != nil { if err != nil {
log.Print(err) log.Print(err)
} }
@ -46,73 +46,31 @@ func main() {
} }
// nolint // nolint
func writeStatements(adapter qgen.Adapter) error { func writeStatements(a qgen.Adapter) (err error) {
err := createTables(adapter) e := func(f func(qgen.Adapter) error) {
if err != nil { if err != nil {
return err return
}
err = f(a)
} }
e(createTables)
err = seedTables(adapter) e(seedTables)
if err != nil { e(writeSelects)
return err e(writeLeftJoins)
} e(writeInnerJoins)
e(writeInserts)
err = writeSelects(adapter) e(writeUpdates)
if err != nil { e(writeDeletes)
return err e(writeSimpleCounts)
} e(writeInsertSelects)
e(writeInsertLeftJoins)
err = writeLeftJoins(adapter) e(writeInsertInnerJoins)
if err != nil { return err
return err
}
err = writeInnerJoins(adapter)
if err != nil {
return err
}
err = writeInserts(adapter)
if err != nil {
return err
}
err = writeUpdates(adapter)
if err != nil {
return err
}
err = writeDeletes(adapter)
if err != nil {
return err
}
err = writeSimpleCounts(adapter)
if err != nil {
return err
}
err = writeInsertSelects(adapter)
if err != nil {
return err
}
err = writeInsertLeftJoins(adapter)
if err != nil {
return err
}
err = writeInsertInnerJoins(adapter)
if err != nil {
return err
}
return nil
} }
type si = map[string]interface{} type si = map[string]interface{}
func seedTables(adapter qgen.Adapter) error { func seedTables(a qgen.Adapter) error {
qgen.Install.AddIndex("topics", "parentID", "parentID") qgen.Install.AddIndex("topics", "parentID", "parentID")
qgen.Install.AddIndex("replies", "tid", "tid") qgen.Install.AddIndex("replies", "tid", "tid")
qgen.Install.AddIndex("polls", "parentID", "parentID") qgen.Install.AddIndex("polls", "parentID", "parentID")

View File

@ -43,8 +43,7 @@ type LanguagePack struct {
// Should we use a sync map or a struct for these? It would be nice, if we could keep all the phrases consistent. // Should we use a sync map or a struct for these? It would be nice, if we could keep all the phrases consistent.
Levels LevelPhrases Levels LevelPhrases
GlobalPerms map[string]string Perms map[string]string
LocalPerms map[string]string
SettingPhrases map[string]string SettingPhrases map[string]string
PermPresets map[string]string PermPresets map[string]string
Accounts map[string]string // TODO: Apply these phrases in the software proper Accounts map[string]string // TODO: Apply these phrases in the software proper
@ -184,16 +183,8 @@ func GetLevelPhrase(level int) string {
return strings.Replace(levelPhrases.Level, "{0}", strconv.Itoa(level), -1) return strings.Replace(levelPhrases.Level, "{0}", strconv.Itoa(level), -1)
} }
// TODO: Merge these two maps? func GetPermPhrase(name string) string {
func GetGlobalPermPhrase(name string) string { res, ok := currentLangPack.Load().(*LanguagePack).Perms[name]
res, ok := currentLangPack.Load().(*LanguagePack).GlobalPerms[name]
if !ok {
return getPlaceholder("perms", name)
}
return res
}
func GetLocalPermPhrase(name string) string {
res, ok := currentLangPack.Load().(*LanguagePack).LocalPerms[name]
if !ok { if !ok {
return getPlaceholder("perms", name) return getPlaceholder("perms", name)
} }

View File

@ -12,7 +12,7 @@ import (
"html" "html"
"time" "time"
"github.com/Azareal/Gosora/query_gen" qgen "github.com/Azareal/Gosora/query_gen"
) )
type ReplyUser struct { type ReplyUser struct {
@ -45,6 +45,7 @@ type ReplyUser struct {
ActionIcon string ActionIcon string
Attachments []*MiniAttachment Attachments []*MiniAttachment
Deletable bool
} }
type Reply struct { type Reply struct {
@ -57,7 +58,7 @@ type Reply struct {
LastEdit int LastEdit int
LastEditBy int LastEditBy int
ContentLines int ContentLines int
IP string IP string
Liked bool Liked bool
LikeCount int LikeCount int
AttachCount int AttachCount int

View File

@ -238,7 +238,7 @@ func compileCommons(c *tmpl.CTemplateSet, header *Header, header2 *Header, forum
}, VoteCount: 7} }, VoteCount: 7}
avatar, microAvatar := BuildAvatar(62, "") avatar, microAvatar := BuildAvatar(62, "")
miniAttach := []*MiniAttachment{&MiniAttachment{Path: "/"}} miniAttach := []*MiniAttachment{&MiniAttachment{Path: "/"}}
topic := TopicUser{1, "blah", "Blah", "Hey there!", 0, false, false, now, now, 1, 1, 0, "", "127.0.0.1", 1, 0, 1, 0, "classname", poll.ID, "weird-data", BuildProfileURL("fake-user", 62), "Fake User", Config.DefaultGroup, avatar, microAvatar, 0, "", "", "", "", "", 58, false, miniAttach, nil} topic := TopicUser{1, "blah", "Blah", "Hey there!", 0, false, false, now, now, 1, 1, 0, "", "127.0.0.1", 1, 0, 1, 0, "classname", poll.ID, "weird-data", BuildProfileURL("fake-user", 62), "Fake User", Config.DefaultGroup, avatar, microAvatar, 0, "", "", "", "", "", 58, false, miniAttach, nil,false}
var replyList []*ReplyUser var replyList []*ReplyUser
reply := Reply{1, 1, "Yo!", 1, Config.DefaultGroup, now, 0, 0, 1, "::1", true, 1, 1, ""} reply := Reply{1, 1, "Yo!", 1, Config.DefaultGroup, now, 0, 0, 1, "::1", true, 1, 1, ""}
@ -520,7 +520,7 @@ func compileJSTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName stri
}, VoteCount: 7} }, VoteCount: 7}
avatar, microAvatar := BuildAvatar(62, "") avatar, microAvatar := BuildAvatar(62, "")
miniAttach := []*MiniAttachment{&MiniAttachment{Path: "/"}} miniAttach := []*MiniAttachment{&MiniAttachment{Path: "/"}}
topic := TopicUser{1, "blah", "Blah", "Hey there!", 62, false, false, now, now, 1, 1, 0, "", "127.0.0.1", 1, 0, 1, 0, "classname", poll.ID, "weird-data", BuildProfileURL("fake-user", 62), "Fake User", Config.DefaultGroup, avatar, microAvatar, 0, "", "", "", "", "", 58, false, miniAttach, nil} topic := TopicUser{1, "blah", "Blah", "Hey there!", 62, false, false, now, now, 1, 1, 0, "", "127.0.0.1", 1, 0, 1, 0, "classname", poll.ID, "weird-data", BuildProfileURL("fake-user", 62), "Fake User", Config.DefaultGroup, avatar, microAvatar, 0, "", "", "", "", "", 58, false, miniAttach, nil,false}
var replyList []*ReplyUser var replyList []*ReplyUser
// TODO: Do we really want the UID here to be zero? // TODO: Do we really want the UID here to be zero?
avatar, microAvatar = BuildAvatar(0, "") avatar, microAvatar = BuildAvatar(0, "")

View File

@ -10,13 +10,14 @@ import (
"database/sql" "database/sql"
"html" "html"
"html/template" "html/template"
//"log" //"log"
"strconv" "strconv"
"strings" "strings"
"time" "time"
p "github.com/Azareal/Gosora/common/phrases" p "github.com/Azareal/Gosora/common/phrases"
"github.com/Azareal/Gosora/query_gen" qgen "github.com/Azareal/Gosora/query_gen"
) )
// This is also in reply.go // This is also in reply.go
@ -38,7 +39,7 @@ type Topic struct {
LastReplyID int LastReplyID int
ParentID int ParentID int
Status string // Deprecated. Marked for removal. Status string // Deprecated. Marked for removal.
IP string IP string
ViewCount int64 ViewCount int64
PostCount int PostCount int
LikeCount int LikeCount int
@ -64,7 +65,7 @@ type TopicUser struct {
LastReplyID int LastReplyID int
ParentID int ParentID int
Status string // Deprecated. Marked for removal. Status string // Deprecated. Marked for removal.
IP string IP string
ViewCount int64 ViewCount int64
PostCount int PostCount int
LikeCount int LikeCount int
@ -89,6 +90,7 @@ type TopicUser struct {
Attachments []*MiniAttachment Attachments []*MiniAttachment
Rids []int Rids []int
Deletable bool
} }
// TODO: Embed TopicUser to simplify this structure and it's related logic? // TODO: Embed TopicUser to simplify this structure and it's related logic?
@ -106,7 +108,7 @@ type TopicsRow struct {
LastReplyID int LastReplyID int
ParentID int ParentID int
Status string // Deprecated. Marked for removal. -Is there anything we could use it for? Status string // Deprecated. Marked for removal. -Is there anything we could use it for?
IP string IP string
ViewCount int64 ViewCount int64
PostCount int PostCount int
LikeCount int LikeCount int
@ -423,10 +425,11 @@ func GetRidsForTopic(tid int, offset int) (rids []int, err error) {
} }
var aipost = ";&#xFE0E" var aipost = ";&#xFE0E"
var lockai = "&#x1F512"+aipost var lockai = "&#x1F512" + aipost
var unlockai = "&#x1F513" var unlockai = "&#x1F513"
var stickai = "&#x1F4CC" var stickai = "&#x1F4CC"
var unstickai = "&#x1F4CC"+aipost var unstickai = "&#x1F4CC" + aipost
func (ru *ReplyUser) Init() error { func (ru *ReplyUser) Init() error {
ru.UserLink = BuildProfileURL(NameToSlug(ru.CreatedByName), ru.CreatedBy) ru.UserLink = BuildProfileURL(NameToSlug(ru.CreatedByName), ru.CreatedBy)
ru.ContentLines = strings.Count(ru.Content, "\n") ru.ContentLines = strings.Count(ru.Content, "\n")
@ -545,6 +548,7 @@ func (t *TopicUser) Replies(offset int, pFrag int, user *User) (rlist []*ReplyUs
attachMap[reply.ID] = len(rlist) attachMap[reply.ID] = len(rlist)
attachQueryList = append(attachQueryList, reply.ID) attachQueryList = append(attachQueryList, reply.ID)
} }
reply.Deletable = user.Perms.DeleteReply || reply.CreatedBy == user.ID
hTbl.VhookNoRet("topic_reply_row_assign", &rlist, &reply) hTbl.VhookNoRet("topic_reply_row_assign", &rlist, &reply)
rlist = append(rlist, reply) rlist = append(rlist, reply)
@ -568,6 +572,7 @@ func (t *TopicUser) Replies(offset int, pFrag int, user *User) (rlist []*ReplyUs
} }
reply.ContentHtml = ParseMessage(reply.Content, t.ParentID, "forums") reply.ContentHtml = ParseMessage(reply.Content, t.ParentID, "forums")
// TODO: This doesn't work properly so pick the first one instead?
if reply.ID == pFrag { if reply.ID == pFrag {
ogdesc = reply.Content ogdesc = reply.Content
if len(ogdesc) > 200 { if len(ogdesc) > 200 {
@ -583,6 +588,7 @@ func (t *TopicUser) Replies(offset int, pFrag int, user *User) (rlist []*ReplyUs
attachMap[reply.ID] = len(rlist) attachMap[reply.ID] = len(rlist)
attachQueryList = append(attachQueryList, reply.ID) attachQueryList = append(attachQueryList, reply.ID)
} }
reply.Deletable = user.Perms.DeleteReply || reply.CreatedBy == user.ID
hTbl.VhookNoRet("topic_reply_row_assign", &rlist, &reply) hTbl.VhookNoRet("topic_reply_row_assign", &rlist, &reply)
// TODO: Use a pointer instead to make it easier to abstract this loop? What impact would this have on escape analysis? // TODO: Use a pointer instead to make it easier to abstract this loop? What impact would this have on escape analysis?

View File

@ -7,7 +7,7 @@
"LevelMax": "" "LevelMax": ""
}, },
"GlobalPerms": { "Perms": {
"BanUsers": "Can ban users", "BanUsers": "Can ban users",
"ActivateUsers": "Can activate users", "ActivateUsers": "Can activate users",
"EditUser": "Can edit users", "EditUser": "Can edit users",
@ -30,10 +30,8 @@
"UploadFiles": "Can upload files", "UploadFiles": "Can upload files",
"UploadAvatars": "Can upload avatars", "UploadAvatars": "Can upload avatars",
"UseConvos":"Can use conversations" "UseConvos":"Can use conversations",
},
"LocalPerms": {
"ViewTopic": "Can view topics", "ViewTopic": "Can view topics",
"LikeItem": "Can like items", "LikeItem": "Can like items",
"CreateTopic": "Can create topics", "CreateTopic": "Can create topics",

View File

@ -1242,14 +1242,13 @@ func TestPluginManager(t *testing.T) {
} }
func TestPhrases(t *testing.T) { func TestPhrases(t *testing.T) {
getPhrase := phrases.GetGlobalPermPhrase getPhrase := phrases.GetPermPhrase
tp := func(name string, expects string) { tp := func(name string, expects string) {
res := getPhrase(name) res := getPhrase(name)
expect(t, res == expects, "Not the expected phrase, got '"+res+"' instead") expect(t, res == expects, "Not the expected phrase, got '"+res+"' instead")
} }
tp("BanUsers", "Can ban users") tp("BanUsers", "Can ban users")
tp("NoSuchPerm", "{lang.perms[NoSuchPerm]}") tp("NoSuchPerm", "{lang.perms[NoSuchPerm]}")
getPhrase = phrases.GetLocalPermPhrase
tp("ViewTopic", "Can view topics") tp("ViewTopic", "Can view topics")
tp("NoSuchPerm", "{lang.perms[NoSuchPerm]}") tp("NoSuchPerm", "{lang.perms[NoSuchPerm]}")

View File

@ -8,7 +8,7 @@ import (
"strings" "strings"
c "github.com/Azareal/Gosora/common" c "github.com/Azareal/Gosora/common"
"github.com/Azareal/Gosora/common/phrases" p "github.com/Azareal/Gosora/common/phrases"
) )
func Forums(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { func Forums(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
@ -49,7 +49,7 @@ func Forums(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
} }
pi := c.PanelPage{basePage, forumList, nil} pi := c.PanelPage{basePage, forumList, nil}
return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage,"","","panel_forums",&pi}) return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "", "", "panel_forums", &pi})
} }
func ForumsCreateSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { func ForumsCreateSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
@ -98,7 +98,7 @@ func ForumsDelete(w http.ResponseWriter, r *http.Request, user c.User, sfid stri
return c.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
confirmMsg := phrases.GetTmplPhrasef("panel_forum_delete_are_you_sure", forum.Name) confirmMsg := p.GetTmplPhrasef("panel_forum_delete_are_you_sure", forum.Name)
yousure := c.AreYouSure{"/panel/forums/delete/submit/" + strconv.Itoa(fid), confirmMsg} yousure := c.AreYouSure{"/panel/forums/delete/submit/" + strconv.Itoa(fid), confirmMsg}
pi := c.PanelPage{basePage, tList, yousure} pi := c.PanelPage{basePage, tList, yousure}
@ -165,10 +165,10 @@ func ForumsEdit(w http.ResponseWriter, r *http.Request, user c.User, sfid string
if !user.Perms.ManageForums { if !user.Perms.ManageForums {
return c.NoPermissions(w, r, user) return c.NoPermissions(w, r, user)
} }
fid, err := strconv.Atoi(sfid) fid, err := strconv.Atoi(sfid)
if err != nil { if err != nil {
return c.SimpleError(phrases.GetErrorPhrase("url_id_must_be_integer"),w,r,basePage.Header) return c.SimpleError(p.GetErrorPhrase("url_id_must_be_integer"), w, r, basePage.Header)
} }
basePage.Header.AddScriptAsync("panel_forum_edit.js") basePage.Header.AddScriptAsync("panel_forum_edit.js")
@ -207,7 +207,7 @@ func ForumsEdit(w http.ResponseWriter, r *http.Request, user c.User, sfid string
} }
pi := c.PanelEditForumPage{basePage, forum.ID, forum.Name, forum.Desc, forum.Active, forum.Preset, gplist} pi := c.PanelEditForumPage{basePage, forum.ID, forum.Name, forum.Desc, forum.Active, forum.Preset, gplist}
return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage,"","","panel_forum_edit",&pi}) return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "", "", "panel_forum_edit", &pi})
} }
func ForumsEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, sfid string) c.RouteError { func ForumsEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, sfid string) c.RouteError {
@ -341,31 +341,30 @@ func ForumsEditPermsAdvance(w http.ResponseWriter, r *http.Request, user c.User,
} }
var formattedPermList []c.NameLangToggle var formattedPermList []c.NameLangToggle
// TODO: Load the phrases in bulk for efficiency? // TODO: Load the phrases in bulk for efficiency?
// TODO: Reduce the amount of code duplication between this and the group editor. Also, can we grind this down into one line or use a code generator to stay current more easily? // TODO: Reduce the amount of code duplication between this and the group editor. Also, can we grind this down into one line or use a code generator to stay current more easily?
addNameLangToggle := func(permStr string, perm bool) { addToggle := func(permStr string, perm bool) {
formattedPermList = append(formattedPermList, c.NameLangToggle{permStr, phrases.GetLocalPermPhrase(permStr), perm}) formattedPermList = append(formattedPermList, c.NameLangToggle{permStr, p.GetPermPhrase(permStr), perm})
} }
addNameLangToggle("ViewTopic", fp.ViewTopic) addToggle("ViewTopic", fp.ViewTopic)
addNameLangToggle("LikeItem", fp.LikeItem) addToggle("LikeItem", fp.LikeItem)
addNameLangToggle("CreateTopic", fp.CreateTopic) addToggle("CreateTopic", fp.CreateTopic)
//<-- //<--
addNameLangToggle("EditTopic", fp.EditTopic) addToggle("EditTopic", fp.EditTopic)
addNameLangToggle("DeleteTopic", fp.DeleteTopic) addToggle("DeleteTopic", fp.DeleteTopic)
addNameLangToggle("CreateReply", fp.CreateReply) addToggle("CreateReply", fp.CreateReply)
addNameLangToggle("EditReply", fp.EditReply) addToggle("EditReply", fp.EditReply)
addNameLangToggle("DeleteReply", fp.DeleteReply) addToggle("DeleteReply", fp.DeleteReply)
addNameLangToggle("PinTopic", fp.PinTopic) addToggle("PinTopic", fp.PinTopic)
addNameLangToggle("CloseTopic", fp.CloseTopic) addToggle("CloseTopic", fp.CloseTopic)
addNameLangToggle("MoveTopic", fp.MoveTopic) addToggle("MoveTopic", fp.MoveTopic)
if r.FormValue("updated") == "1" { if r.FormValue("updated") == "1" {
basePage.AddNotice("panel_forum_perms_updated") basePage.AddNotice("panel_forum_perms_updated")
} }
pi := c.PanelEditForumGroupPage{basePage, forum.ID, gid, forum.Name, forum.Desc, forum.Active, forum.Preset, formattedPermList} pi := c.PanelEditForumGroupPage{basePage, forum.ID, gid, forum.Name, forum.Desc, forum.Active, forum.Preset, formattedPermList}
return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage,"","","panel_forum_edit_perms",&pi}) return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "", "", "panel_forum_edit_perms", &pi})
} }
func ForumsEditPermsAdvanceSubmit(w http.ResponseWriter, r *http.Request, user c.User, paramList string) c.RouteError { func ForumsEditPermsAdvanceSubmit(w http.ResponseWriter, r *http.Request, user c.User, paramList string) c.RouteError {
@ -376,7 +375,7 @@ func ForumsEditPermsAdvanceSubmit(w http.ResponseWriter, r *http.Request, user c
if !user.Perms.ManageForums { if !user.Perms.ManageForums {
return c.NoPermissions(w, r, user) return c.NoPermissions(w, r, user)
} }
js := (r.PostFormValue("js") == "1") js := r.PostFormValue("js") == "1"
fid, gid, err := forumPermsExtractDash(paramList) fid, gid, err := forumPermsExtractDash(paramList)
if err != nil { if err != nil {

View File

@ -301,7 +301,7 @@ func GroupsEditPerms(w http.ResponseWriter, r *http.Request, user c.User, sgid s
// TODO: Load the phrases in bulk for efficiency? // TODO: Load the phrases in bulk for efficiency?
var localPerms []c.NameLangToggle var localPerms []c.NameLangToggle
addLocalPerm := func(permStr string, perm bool) { addLocalPerm := func(permStr string, perm bool) {
localPerms = append(localPerms, c.NameLangToggle{permStr, p.GetLocalPermPhrase(permStr), perm}) localPerms = append(localPerms, c.NameLangToggle{permStr, p.GetPermPhrase(permStr), perm})
} }
addLocalPerm("ViewTopic", g.Perms.ViewTopic) addLocalPerm("ViewTopic", g.Perms.ViewTopic)
@ -319,7 +319,7 @@ func GroupsEditPerms(w http.ResponseWriter, r *http.Request, user c.User, sgid s
var globalPerms []c.NameLangToggle var globalPerms []c.NameLangToggle
addGlobalPerm := func(permStr string, perm bool) { addGlobalPerm := func(permStr string, perm bool) {
globalPerms = append(globalPerms, c.NameLangToggle{permStr, p.GetGlobalPermPhrase(permStr), perm}) globalPerms = append(globalPerms, c.NameLangToggle{permStr, p.GetPermPhrase(permStr), perm})
} }
addGlobalPerm("BanUsers", g.Perms.BanUsers) addGlobalPerm("BanUsers", g.Perms.BanUsers)

View File

@ -214,7 +214,7 @@ func CreateReplySubmit(w http.ResponseWriter, r *http.Request, user c.User) c.Ro
// TODO: Disable stat updates in posts handled by plugin_guilds // TODO: Disable stat updates in posts handled by plugin_guilds
// TODO: Update the stats after edits so that we don't under or over decrement stats during deletes // TODO: Update the stats after edits so that we don't under or over decrement stats during deletes
func ReplyEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, srid string) c.RouteError { func ReplyEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, srid string) c.RouteError {
js := (r.PostFormValue("js") == "1") js := r.PostFormValue("js") == "1"
rid, err := strconv.Atoi(srid) rid, err := strconv.Atoi(srid)
if err != nil { if err != nil {
return c.PreErrorJSQ("The provided Reply ID is not a valid number.", w, r, js) return c.PreErrorJSQ("The provided Reply ID is not a valid number.", w, r, js)
@ -282,7 +282,7 @@ func ReplyEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, srid s
// TODO: Refactor this // TODO: Refactor this
// TODO: Disable stat updates in posts handled by plugin_guilds // TODO: Disable stat updates in posts handled by plugin_guilds
func ReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.User, srid string) c.RouteError { func ReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.User, srid string) c.RouteError {
js := (r.PostFormValue("js") == "1") js := r.PostFormValue("js") == "1"
rid, err := strconv.Atoi(srid) rid, err := strconv.Atoi(srid)
if err != nil { if err != nil {
return c.PreErrorJSQ("The provided Reply ID is not a valid number.", w, r, js) return c.PreErrorJSQ("The provided Reply ID is not a valid number.", w, r, js)
@ -307,8 +307,10 @@ func ReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.User, srid
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
if !user.Perms.ViewTopic || !user.Perms.DeleteReply { if reply.CreatedBy != user.ID {
return c.NoPermissionsJSQ(w, r, user, js) if !user.Perms.ViewTopic || !user.Perms.DeleteReply {
return c.NoPermissionsJSQ(w, r, user, js)
}
} }
err = reply.Delete() err = reply.Delete()
@ -501,7 +503,7 @@ func ProfileReplyCreateSubmit(w http.ResponseWriter, r *http.Request, user c.Use
} }
func ProfileReplyEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, srid string) c.RouteError { func ProfileReplyEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, srid string) c.RouteError {
js := (r.PostFormValue("js") == "1") js := r.PostFormValue("js") == "1"
rid, err := strconv.Atoi(srid) rid, err := strconv.Atoi(srid)
if err != nil { if err != nil {
return c.LocalErrorJSQ("The provided Reply ID is not a valid number.", w, r, user, js) return c.LocalErrorJSQ("The provided Reply ID is not a valid number.", w, r, user, js)
@ -537,7 +539,7 @@ func ProfileReplyEditSubmit(w http.ResponseWriter, r *http.Request, user c.User,
} }
func ProfileReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.User, srid string) c.RouteError { func ProfileReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.User, srid string) c.RouteError {
js := (r.PostFormValue("js") == "1") js := r.PostFormValue("js") == "1"
rid, err := strconv.Atoi(srid) rid, err := strconv.Atoi(srid)
if err != nil { if err != nil {
return c.LocalErrorJSQ("The provided Reply ID is not a valid number.", w, r, user, js) return c.LocalErrorJSQ("The provided Reply ID is not a valid number.", w, r, user, js)
@ -573,7 +575,7 @@ func ProfileReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.Use
} }
func ReplyLikeSubmit(w http.ResponseWriter, r *http.Request, user c.User, srid string) c.RouteError { func ReplyLikeSubmit(w http.ResponseWriter, r *http.Request, user c.User, srid string) c.RouteError {
js := (r.PostFormValue("js") == "1") js := r.PostFormValue("js") == "1"
rid, err := strconv.Atoi(srid) rid, err := strconv.Atoi(srid)
if err != nil { if err != nil {
return c.PreErrorJSQ("The provided Reply ID is not a valid number.", w, r, js) return c.PreErrorJSQ("The provided Reply ID is not a valid number.", w, r, js)

View File

@ -7,6 +7,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"io" "io"
//"fmt" //"fmt"
"log" "log"
"net/http" "net/http"
@ -18,7 +19,7 @@ import (
c "github.com/Azareal/Gosora/common" c "github.com/Azareal/Gosora/common"
"github.com/Azareal/Gosora/common/counters" "github.com/Azareal/Gosora/common/counters"
"github.com/Azareal/Gosora/common/phrases" "github.com/Azareal/Gosora/common/phrases"
"github.com/Azareal/Gosora/query_gen" qgen "github.com/Azareal/Gosora/query_gen"
) )
type TopicStmts struct { type TopicStmts struct {
@ -44,7 +45,7 @@ func ViewTopic(w http.ResponseWriter, r *http.Request, user c.User, header *c.He
page, _ := strconv.Atoi(r.FormValue("page")) page, _ := strconv.Atoi(r.FormValue("page"))
_, tid, err := ParseSEOURL(urlBit) _, tid, err := ParseSEOURL(urlBit)
if err != nil { if err != nil {
return c.SimpleError(phrases.GetErrorPhrase("url_id_must_be_integer"),w,r,header) return c.SimpleError(phrases.GetErrorPhrase("url_id_must_be_integer"), w, r, header)
} }
// Get the topic... // Get the topic...
@ -82,11 +83,11 @@ func ViewTopic(w http.ResponseWriter, r *http.Request, user c.User, header *c.He
if err != nil { if err != nil {
return c.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
topic.Tag = postGroup.Tag topic.Tag = postGroup.Tag
if postGroup.IsMod { if postGroup.IsMod {
topic.ClassName = c.Config.StaffCSS topic.ClassName = c.Config.StaffCSS
} }
topic.Deletable = user.Perms.DeleteTopic || topic.CreatedBy == user.ID
forum, err := c.Forums.Get(topic.ParentID) forum, err := c.Forums.Get(topic.ParentID)
if err != nil { if err != nil {
@ -155,8 +156,8 @@ func ViewTopic(w http.ResponseWriter, r *http.Request, user c.User, header *c.He
if tmpl == "" { if tmpl == "" {
rerr = renderTemplate("topic", w, r, header, tpage) rerr = renderTemplate("topic", w, r, header, tpage)
} else { } else {
tmpl = "topic_"+tmpl tmpl = "topic_" + tmpl
err = renderTemplate3(tmpl,tmpl, w, r, header, tpage) err = renderTemplate3(tmpl, tmpl, w, r, header, tpage)
if err != nil { if err != nil {
rerr = renderTemplate("topic", w, r, header, tpage) rerr = renderTemplate("topic", w, r, header, tpage)
} }
@ -328,7 +329,7 @@ func CreateTopic(w http.ResponseWriter, r *http.Request, user c.User, header *c.
func CreateTopicSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { func CreateTopicSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
fid, err := strconv.Atoi(r.PostFormValue("topic-board")) fid, err := strconv.Atoi(r.PostFormValue("topic-board"))
if err != nil { if err != nil {
return c.LocalError(phrases.GetErrorPhrase("id_must_be_integer"),w,r,user) return c.LocalError(phrases.GetErrorPhrase("id_must_be_integer"), w, r, user)
} }
// TODO: Add hooks to make use of headerLite // TODO: Add hooks to make use of headerLite
lite, ferr := c.SimpleForumUserCheck(w, r, &user, fid) lite, ferr := c.SimpleForumUserCheck(w, r, &user, fid)
@ -616,8 +617,10 @@ func DeleteTopicSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.Ro
if ferr != nil { if ferr != nil {
return ferr return ferr
} }
if !user.Perms.ViewTopic || !user.Perms.DeleteTopic { if topic.CreatedBy != user.ID {
return c.NoPermissionsJSQ(w, r, user, js) if !user.Perms.ViewTopic || !user.Perms.DeleteTopic {
return c.NoPermissionsJSQ(w, r, user, js)
}
} }
// We might be able to handle this err better // We might be able to handle this err better
@ -862,7 +865,7 @@ func addTopicAction(action string, t *c.Topic, u c.User) error {
// TODO: Refactor this // TODO: Refactor this
func LikeTopicSubmit(w http.ResponseWriter, r *http.Request, user c.User, stid string) c.RouteError { func LikeTopicSubmit(w http.ResponseWriter, r *http.Request, user c.User, stid string) c.RouteError {
js := (r.PostFormValue("js") == "1") js := r.PostFormValue("js") == "1"
tid, err := strconv.Atoi(stid) tid, err := strconv.Atoi(stid)
if err != nil { if err != nil {
return c.PreErrorJSQ(phrases.GetErrorPhrase("id_must_be_integer"), w, r, js) return c.PreErrorJSQ(phrases.GetErrorPhrase("id_must_be_integer"), w, r, js)

View File

@ -47,7 +47,7 @@
{{if .CurrentUser.Perms.EditTopic}}<a href='/topic/edit/{{.Topic.ID}}' class="mod_button open_edit" title="{{lang "topic.edit_tooltip"}}" aria-label="{{lang "topic.edit_aria"}}"><button class="username edit_label"></button></a>{{end}} {{if .CurrentUser.Perms.EditTopic}}<a href='/topic/edit/{{.Topic.ID}}' class="mod_button open_edit" title="{{lang "topic.edit_tooltip"}}" aria-label="{{lang "topic.edit_aria"}}"><button class="username edit_label"></button></a>{{end}}
{{end}} {{end}}
{{if .CurrentUser.Perms.DeleteTopic}}<a href='/topic/delete/submit/{{.Topic.ID}}?s={{.CurrentUser.Session}}' class="mod_button" title="{{lang "topic.delete_tooltip"}}" aria-label="{{lang "topic.delete_aria"}}"><button class="username delete_label"></button></a>{{end}} {{if .Topic.Deletable}}<a href='/topic/delete/submit/{{.Topic.ID}}?s={{.CurrentUser.Session}}' class="mod_button" title="{{lang "topic.delete_tooltip"}}" aria-label="{{lang "topic.delete_aria"}}"><button class="username delete_label"></button></a>{{end}}
{{if .CurrentUser.Perms.CloseTopic}}{{if .Topic.IsClosed}}<a class="mod_button" href='/topic/unlock/submit/{{.Topic.ID}}?s={{.CurrentUser.Session}}' title="{{lang "topic.unlock_tooltip"}}" aria-label="{{lang "topic.unlock_aria"}}"><button class="username unlock_label"></button></a>{{else}}<a href='/topic/lock/submit/{{.Topic.ID}}?s={{.CurrentUser.Session}}' class="mod_button" title="{{lang "topic.lock_tooltip"}}" aria-label="{{lang "topic.lock_aria"}}"><button class="username lock_label"></button></a>{{end}}{{end}} {{if .CurrentUser.Perms.CloseTopic}}{{if .Topic.IsClosed}}<a class="mod_button" href='/topic/unlock/submit/{{.Topic.ID}}?s={{.CurrentUser.Session}}' title="{{lang "topic.unlock_tooltip"}}" aria-label="{{lang "topic.unlock_aria"}}"><button class="username unlock_label"></button></a>{{else}}<a href='/topic/lock/submit/{{.Topic.ID}}?s={{.CurrentUser.Session}}' class="mod_button" title="{{lang "topic.lock_tooltip"}}" aria-label="{{lang "topic.lock_aria"}}"><button class="username lock_label"></button></a>{{end}}{{end}}

View File

@ -90,7 +90,7 @@
{{if not .Topic.IsClosed or .CurrentUser.Perms.CloseTopic}} {{if not .Topic.IsClosed or .CurrentUser.Perms.CloseTopic}}
{{if .CurrentUser.Perms.EditTopic}}<a href="/topic/edit/{{.Topic.ID}}" class="action_button open_edit" aria-label="{{lang "topic.edit_aria"}}" data-action="edit"></a>{{end}} {{if .CurrentUser.Perms.EditTopic}}<a href="/topic/edit/{{.Topic.ID}}" class="action_button open_edit" aria-label="{{lang "topic.edit_aria"}}" data-action="edit"></a>{{end}}
{{end}} {{end}}
{{if .CurrentUser.Perms.DeleteTopic}}<a href="/topic/delete/submit/{{.Topic.ID}}?s={{.CurrentUser.Session}}" class="action_button delete_item" aria-label="{{lang "topic.delete_aria"}}" data-action="delete"></a>{{end}} {{if .Topic.Deletable}}<a href="/topic/delete/submit/{{.Topic.ID}}?s={{.CurrentUser.Session}}" class="action_button delete_item" aria-label="{{lang "topic.delete_aria"}}" data-action="delete"></a>{{end}}
{{if .CurrentUser.Perms.CloseTopic}} {{if .CurrentUser.Perms.CloseTopic}}
{{if .Topic.IsClosed}}<a href='/topic/unlock/submit/{{.Topic.ID}}?s={{.CurrentUser.Session}}' class="action_button unlock_item" data-action="unlock" aria-label="{{lang "topic.unlock_aria"}}"></a>{{else}}<a href='/topic/lock/submit/{{.Topic.ID}}?s={{.CurrentUser.Session}}' class="action_button lock_item" data-action="lock" aria-label="{{lang "topic.lock_aria"}}"></a>{{end}}{{end}} {{if .Topic.IsClosed}}<a href='/topic/unlock/submit/{{.Topic.ID}}?s={{.CurrentUser.Session}}' class="action_button unlock_item" data-action="unlock" aria-label="{{lang "topic.unlock_aria"}}"></a>{{else}}<a href='/topic/lock/submit/{{.Topic.ID}}?s={{.CurrentUser.Session}}' class="action_button lock_item" data-action="lock" aria-label="{{lang "topic.lock_aria"}}"></a>{{end}}{{end}}
{{if .CurrentUser.Perms.PinTopic}} {{if .CurrentUser.Perms.PinTopic}}

View File

@ -36,7 +36,7 @@
{{if not $.Topic.IsClosed or $.CurrentUser.Perms.CloseTopic}} {{if not $.Topic.IsClosed or $.CurrentUser.Perms.CloseTopic}}
{{if $.CurrentUser.Perms.EditReply}}<a href="/reply/edit/submit/{{.ID}}?s={{$.CurrentUser.Session}}" class="action_button edit_item" aria-label="{{lang "topic.post_edit_aria"}}" data-action="edit"></a>{{end}} {{if $.CurrentUser.Perms.EditReply}}<a href="/reply/edit/submit/{{.ID}}?s={{$.CurrentUser.Session}}" class="action_button edit_item" aria-label="{{lang "topic.post_edit_aria"}}" data-action="edit"></a>{{end}}
{{end}} {{end}}
{{if $.CurrentUser.Perms.DeleteReply}}<a href="/reply/delete/submit/{{.ID}}?s={{$.CurrentUser.Session}}" class="action_button delete_item" aria-label="{{lang "topic.post_delete_aria"}}" data-action="delete"></a>{{end}} {{if .Deletable}}<a href="/reply/delete/submit/{{.ID}}?s={{$.CurrentUser.Session}}" class="action_button delete_item" aria-label="{{lang "topic.post_delete_aria"}}" data-action="delete"></a>{{end}}
{{if $.CurrentUser.Perms.ViewIPs}}<a href="/users/ips/?ip={{.IP}}" title="{{lang "topic.ip_full_tooltip"}}" class="action_button ip_item_button hide_on_big" aria-label="{{lang "topic.ip_full_aria"}}" data-action="ip"></a>{{end}} {{if $.CurrentUser.Perms.ViewIPs}}<a href="/users/ips/?ip={{.IP}}" title="{{lang "topic.ip_full_tooltip"}}" class="action_button ip_item_button hide_on_big" aria-label="{{lang "topic.ip_full_aria"}}" data-action="ip"></a>{{end}}
<a href="/report/submit/{{.ID}}?s={{$.CurrentUser.Session}}&amp;type=reply" class="action_button report_item" aria-label="{{lang "topic.report_aria"}}" data-action="report"></a> <a href="/report/submit/{{.ID}}?s={{$.CurrentUser.Session}}&amp;type=reply" class="action_button report_item" aria-label="{{lang "topic.report_aria"}}" data-action="report"></a>
<a href="#" class="action_button button_menu"></a> <a href="#" class="action_button button_menu"></a>

View File

@ -5,7 +5,7 @@
<span itemprop="text">{{.ActionType}}</span> <span itemprop="text">{{.ActionType}}</span>
</article> </article>
{{else}} {{else}}
<article {{scope "post"}} id="post-{{.ID}}" itemscope itemtype="http://schema.org/CreativeWork" class="rowitem passive deletable_block editable_parent post_item {{.ClassName}}" style="background-image:url({{.Avatar}}),url(/s/{{$.Header.Theme.Name}}/post-avatar-bg.jpg);background-position:0px {{if le .ContentLines 5}}-1{{end}}0px;background-repeat:no-repeat, repeat-y;"> <article {{scope "post"}} id="post-{{.ID}}" itemscope itemtype="http://schema.org/CreativeWork" class="rowitem passive deletable_block editable_parent post_item {{.ClassName}}" style="background-image:url({{.Avatar}}),url(/s/{{$.Header.Theme.Name}}/post-avatar-bg.jpg);background-position:0px {{if le .ContentLines 5}}-1{{end}}0px;background-repeat:no-repeat,repeat-y;">
{{/** TODO: We might end up with <br>s in the inline editor, fix this **/}} {{/** TODO: We might end up with <br>s in the inline editor, fix this **/}}
<div class="editable_block user_content" itemprop="text">{{.ContentHtml}}</div> <div class="editable_block user_content" itemprop="text">{{.ContentHtml}}</div>
{{if $.CurrentUser.Loggedin}}<div class="auto_hide edit_source">{{.Content}}</div>{{end}} {{if $.CurrentUser.Loggedin}}<div class="auto_hide edit_source">{{.Content}}</div>{{end}}
@ -21,7 +21,7 @@
{{if $.CurrentUser.Perms.EditReply}}<a href="/reply/edit/submit/{{.ID}}?s={{$.CurrentUser.Session}}" class="mod_button" title="{{lang "topic.post_edit_tooltip"}}" aria-label="{{lang "topic.post_edit_aria"}}"><button class="username edit_item edit_label"></button></a>{{end}} {{if $.CurrentUser.Perms.EditReply}}<a href="/reply/edit/submit/{{.ID}}?s={{$.CurrentUser.Session}}" class="mod_button" title="{{lang "topic.post_edit_tooltip"}}" aria-label="{{lang "topic.post_edit_aria"}}"><button class="username edit_item edit_label"></button></a>{{end}}
{{end}} {{end}}
{{if $.CurrentUser.Perms.DeleteReply}}<a href="/reply/delete/submit/{{.ID}}?s={{$.CurrentUser.Session}}" class="mod_button" title="{{lang "topic.post_delete_tooltip"}}" aria-label="{{lang "topic.post_delete_aria"}}"><button class="username delete_item delete_label"></button></a>{{end}} {{if .Deletable}}<a href="/reply/delete/submit/{{.ID}}?s={{$.CurrentUser.Session}}" class="mod_button" title="{{lang "topic.post_delete_tooltip"}}" aria-label="{{lang "topic.post_delete_aria"}}"><button class="username delete_item delete_label"></button></a>{{end}}
{{if $.CurrentUser.Perms.ViewIPs}}<a class="mod_button" href='/users/ips/?ip={{.IP}}' title="{{lang "topic.post_ip_tooltip"}}" aria-label="The poster's IP is {{.IP}}"><button class="username ip_label"></button></a>{{end}} {{if $.CurrentUser.Perms.ViewIPs}}<a class="mod_button" href='/users/ips/?ip={{.IP}}' title="{{lang "topic.post_ip_tooltip"}}" aria-label="The poster's IP is {{.IP}}"><button class="username ip_label"></button></a>{{end}}
<a href="/report/submit/{{.ID}}?s={{$.CurrentUser.Session}}&amp;type=reply" class="mod_button report_item" title="{{lang "topic.post_flag_tooltip"}}" aria-label="{{lang "topic.post_flag_aria"}}" rel="nofollow"><button class="username report_item flag_label"></button></a> <a href="/report/submit/{{.ID}}?s={{$.CurrentUser.Session}}&amp;type=reply" class="mod_button report_item" title="{{lang "topic.post_flag_tooltip"}}" aria-label="{{lang "topic.post_flag_aria"}}" rel="nofollow"><button class="username report_item flag_label"></button></a>