Stop blocked users making profile comments too.
Hide the Send Message option on profiles for blocked users. Move the profile reply routes to their own file. Remove a redundant user initialisation. Shorten things.
This commit is contained in:
parent
8720de83d8
commit
bbfd3c51c7
|
@ -95,9 +95,9 @@ func (f *Forum) Update(name string, desc string, active bool, preset string) err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Forum) SetPreset(preset string, gid int) error {
|
func (f *Forum) SetPreset(preset string, gid int) error {
|
||||||
fperms, changed := GroupForumPresetToForumPerms(preset)
|
fp, changed := GroupForumPresetToForumPerms(preset)
|
||||||
if changed {
|
if changed {
|
||||||
return f.SetPerms(fperms, preset, gid)
|
return f.SetPerms(fp, preset, gid)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
package common
|
package common
|
||||||
|
|
||||||
import "database/sql"
|
import (
|
||||||
import "github.com/Azareal/Gosora/query_gen"
|
"database/sql"
|
||||||
|
|
||||||
|
qgen "github.com/Azareal/Gosora/query_gen"
|
||||||
|
)
|
||||||
|
|
||||||
var Likes LikeStore
|
var Likes LikeStore
|
||||||
|
|
||||||
|
@ -22,7 +25,7 @@ func NewDefaultLikeStore(acc *qgen.Accumulator) (*DefaultLikeStore, error) {
|
||||||
|
|
||||||
// TODO: Write a test for this
|
// TODO: Write a test for this
|
||||||
func (s *DefaultLikeStore) BulkExists(ids []int, sentBy int, targetType string) (eids []int, err error) {
|
func (s *DefaultLikeStore) BulkExists(ids []int, sentBy int, targetType string) (eids []int, err error) {
|
||||||
rows, err := qgen.NewAcc().Select("likes").Columns("targetItem").Where("sentBy = ? AND targetType = ?").In("targetItem", ids).Query(sentBy,targetType)
|
rows, err := qgen.NewAcc().Select("likes").Columns("targetItem").Where("sentBy = ? AND targetType = ?").In("targetItem", ids).Query(sentBy, targetType)
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
|
@ -32,11 +35,10 @@ func (s *DefaultLikeStore) BulkExists(ids []int, sentBy int, targetType string)
|
||||||
|
|
||||||
var id int
|
var id int
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
err = rows.Scan(&id)
|
if err := rows.Scan(&id); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
eids = append(eids,id)
|
eids = append(eids, id)
|
||||||
}
|
}
|
||||||
return eids, rows.Err()
|
return eids, rows.Err()
|
||||||
}
|
}
|
||||||
|
@ -49,4 +51,4 @@ func (s *DefaultLikeStore) Count() (count int) {
|
||||||
LogError(err)
|
LogError(err)
|
||||||
}
|
}
|
||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
|
|
|
@ -208,6 +208,8 @@ type ProfilePage struct {
|
||||||
CurrentScore int
|
CurrentScore int
|
||||||
NextScore int
|
NextScore int
|
||||||
Blocked bool
|
Blocked bool
|
||||||
|
CanMessage bool
|
||||||
|
CanComment bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateTopicPage struct {
|
type CreateTopicPage struct {
|
||||||
|
|
|
@ -23,19 +23,20 @@ type DefaultBlockStore struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDefaultBlockStore(acc *qgen.Accumulator) (*DefaultBlockStore, error) {
|
func NewDefaultBlockStore(acc *qgen.Accumulator) (*DefaultBlockStore, error) {
|
||||||
|
ub := "users_blocks"
|
||||||
return &DefaultBlockStore{
|
return &DefaultBlockStore{
|
||||||
isBlocked: acc.Select("users_blocks").Cols("blocker").Where("blocker = ? AND blockedUser = ?").Prepare(),
|
isBlocked: acc.Select(ub).Cols("blocker").Where("blocker = ? AND blockedUser = ?").Prepare(),
|
||||||
add: acc.Insert("users_blocks").Columns("blocker,blockedUser").Fields("?,?").Prepare(),
|
add: acc.Insert(ub).Columns("blocker,blockedUser").Fields("?,?").Prepare(),
|
||||||
remove: acc.Delete("users_blocks").Where("blocker = ? AND blockedUser = ?").Prepare(),
|
remove: acc.Delete(ub).Where("blocker = ? AND blockedUser = ?").Prepare(),
|
||||||
}, acc.FirstError()
|
}, acc.FirstError()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DefaultBlockStore) IsBlockedBy(blocker, blockee int) (bool, error) {
|
func (s *DefaultBlockStore) IsBlockedBy(blocker, blockee int) (bool, error) {
|
||||||
err := s.isBlocked.QueryRow(blocker, blockee).Scan(&blocker)
|
err := s.isBlocked.QueryRow(blocker, blockee).Scan(&blocker)
|
||||||
if err != nil && err != ErrNoRows {
|
if err == ErrNoRows {
|
||||||
return false, err
|
return false, nil
|
||||||
}
|
}
|
||||||
return err != ErrNoRows, nil
|
return err == nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DefaultBlockStore) Add(blocker, blockee int) error {
|
func (s *DefaultBlockStore) Add(blocker, blockee int) error {
|
||||||
|
|
|
@ -296,7 +296,7 @@ func compileTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName string
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ppage := ProfilePage{htitle("User 526"), replyList, user, 0, 0, false} // TODO: Use the score from user to generate the currentScore and nextScore
|
ppage := ProfilePage{htitle("User 526"), replyList, user, 0, 0, false,false,false} // TODO: Use the score from user to generate the currentScore and nextScore
|
||||||
t.Add("profile", "c.ProfilePage", ppage)
|
t.Add("profile", "c.ProfilePage", ppage)
|
||||||
|
|
||||||
var topicsList []*TopicsRow
|
var topicsList []*TopicsRow
|
||||||
|
|
|
@ -242,9 +242,8 @@ func init() {
|
||||||
// Flush the topic out of the cache
|
// Flush the topic out of the cache
|
||||||
// ? - We do a CacheRemove() here instead of mutating the pointer to avoid creating a race condition
|
// ? - We do a CacheRemove() here instead of mutating the pointer to avoid creating a race condition
|
||||||
func (t *Topic) cacheRemove() {
|
func (t *Topic) cacheRemove() {
|
||||||
tcache := Topics.GetCache()
|
if tc := Topics.GetCache(); tc != nil {
|
||||||
if tcache != nil {
|
tc.Remove(t.ID)
|
||||||
tcache.Remove(t.ID)
|
|
||||||
}
|
}
|
||||||
TopicListThaw.Thaw()
|
TopicListThaw.Thaw()
|
||||||
}
|
}
|
||||||
|
@ -565,11 +564,10 @@ func (t *TopicUser) Replies(offset int, pFrag int, user *User) (rlist []*ReplyUs
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
|
if err := reply.Init(); err != nil {
|
||||||
err = reply.Init()
|
|
||||||
if err != nil {
|
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
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?
|
// TODO: This doesn't work properly so pick the first one instead?
|
||||||
|
|
|
@ -180,9 +180,8 @@ func (u *User) Init() {
|
||||||
|
|
||||||
// TODO: Refactor this idiom into something shorter, maybe with a NullUserCache when one isn't set?
|
// TODO: Refactor this idiom into something shorter, maybe with a NullUserCache when one isn't set?
|
||||||
func (u *User) CacheRemove() {
|
func (u *User) CacheRemove() {
|
||||||
ucache := Users.GetCache()
|
if uc := Users.GetCache(); uc != nil {
|
||||||
if ucache != nil {
|
uc.Remove(u.ID)
|
||||||
ucache.Remove(u.ID)
|
|
||||||
}
|
}
|
||||||
TopicListThaw.Thaw()
|
TopicListThaw.Thaw()
|
||||||
}
|
}
|
||||||
|
@ -336,9 +335,8 @@ func (u *User) ChangeGroup(group int) (err error) {
|
||||||
// ! Only updates the database not the *User for safety reasons
|
// ! Only updates the database not the *User for safety reasons
|
||||||
func (u *User) UpdateIP(host string) error {
|
func (u *User) UpdateIP(host string) error {
|
||||||
_, err := userStmts.updateLastIP.Exec(host, u.ID)
|
_, err := userStmts.updateLastIP.Exec(host, u.ID)
|
||||||
ucache := Users.GetCache()
|
if uc := Users.GetCache(); uc != nil {
|
||||||
if ucache != nil {
|
uc.Remove(u.ID)
|
||||||
ucache.Remove(u.ID)
|
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,6 @@ func ViewProfile(w http.ResponseWriter, r *http.Request, user c.User, header *c.
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
puser.Init()
|
|
||||||
}
|
}
|
||||||
header.Title = phrases.GetTitlePhrasef("profile", puser.Name)
|
header.Title = phrases.GetTitlePhrasef("profile", puser.Name)
|
||||||
header.Path = c.BuildProfileURL(c.NameToSlug(puser.Name), puser.ID)
|
header.Path = c.BuildProfileURL(c.NameToSlug(puser.Name), puser.ID)
|
||||||
|
@ -86,13 +85,10 @@ func ViewProfile(w http.ResponseWriter, r *http.Request, user c.User, header *c.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
if group.Tag != "" {
|
if group.Tag != "" {
|
||||||
ru.Tag = group.Tag
|
ru.Tag = group.Tag
|
||||||
} else if puser.ID == ru.CreatedBy {
|
} else if puser.ID == ru.CreatedBy {
|
||||||
ru.Tag = phrases.GetTmplPhrase("profile_owner_tag")
|
ru.Tag = phrases.GetTmplPhrase("profile_owner_tag")
|
||||||
} else {
|
|
||||||
ru.Tag = ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add a hook here
|
// TODO: Add a hook here
|
||||||
|
@ -111,6 +107,13 @@ func ViewProfile(w http.ResponseWriter, r *http.Request, user c.User, header *c.
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
ppage := c.ProfilePage{header, replyList, *puser, currentScore, nextScore, blocked}
|
blockedInv, err := c.UserBlocks.IsBlockedBy(puser.ID, user.ID)
|
||||||
|
if err != nil {
|
||||||
|
return c.InternalError(err, w, r)
|
||||||
|
}
|
||||||
|
canMessage := (!blockedInv && user.Perms.UseConvos) || user.IsSuperMod
|
||||||
|
canComment := !blockedInv && user.Perms.ViewTopic && user.Perms.CreateReply
|
||||||
|
|
||||||
|
ppage := c.ProfilePage{header, replyList, *puser, currentScore, nextScore, blocked, canMessage, canComment}
|
||||||
return renderTemplate("profile", w, r, header, ppage)
|
return renderTemplate("profile", w, r, header, ppage)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
package routes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
c "github.com/Azareal/Gosora/common"
|
||||||
|
"github.com/Azareal/Gosora/common/counters"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ProfileReplyCreateSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
|
||||||
|
if !user.Perms.ViewTopic || !user.Perms.CreateReply {
|
||||||
|
return c.NoPermissions(w, r, user)
|
||||||
|
}
|
||||||
|
uid, err := strconv.Atoi(r.PostFormValue("uid"))
|
||||||
|
if err != nil {
|
||||||
|
return c.LocalError("Invalid UID", w, r, user)
|
||||||
|
}
|
||||||
|
|
||||||
|
profileOwner, err := c.Users.Get(uid)
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return c.LocalError("The profile you're trying to post on doesn't exist.", w, r, user)
|
||||||
|
} else if err != nil {
|
||||||
|
return c.InternalError(err, w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
blocked, err := c.UserBlocks.IsBlockedBy(profileOwner.ID, user.ID)
|
||||||
|
if err != nil {
|
||||||
|
return c.InternalError(err, w, r)
|
||||||
|
}
|
||||||
|
// Supermods can bypass blocks so they can tell people off when they do something stupid or have to convey important information
|
||||||
|
if blocked && !user.IsSuperMod {
|
||||||
|
return c.LocalError("You don't have permission to send messages to one of these users.", w, r, user)
|
||||||
|
}
|
||||||
|
|
||||||
|
content := c.PreparseMessage(r.PostFormValue("content"))
|
||||||
|
if len(content) == 0 {
|
||||||
|
return c.LocalError("You can't make a blank post", w, r, user)
|
||||||
|
}
|
||||||
|
// TODO: Fully parse the post and store it in the parsed column
|
||||||
|
_, err = c.Prstore.Create(profileOwner.ID, content, user.ID, user.LastIP)
|
||||||
|
if err != nil {
|
||||||
|
return c.InternalError(err, w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ! Be careful about leaking per-route permission state with &user
|
||||||
|
alert := c.Alert{ActorID: user.ID, TargetUserID: profileOwner.ID, Event: "reply", ElementType: "user", ElementID: profileOwner.ID, Actor: &user}
|
||||||
|
err = c.AddActivityAndNotifyTarget(alert)
|
||||||
|
if err != nil {
|
||||||
|
return c.InternalError(err, w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
counters.PostCounter.Bump()
|
||||||
|
http.Redirect(w, r, "/user/"+strconv.Itoa(uid), http.StatusSeeOther)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProfileReplyEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, srid string) c.RouteError {
|
||||||
|
js := r.PostFormValue("js") == "1"
|
||||||
|
rid, err := strconv.Atoi(srid)
|
||||||
|
if err != nil {
|
||||||
|
return c.LocalErrorJSQ("The provided Reply ID is not a valid number.", w, r, user, js)
|
||||||
|
}
|
||||||
|
|
||||||
|
reply, err := c.Prstore.Get(rid)
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return c.PreErrorJSQ("The target reply doesn't exist.", w, r, js)
|
||||||
|
} else if err != nil {
|
||||||
|
return c.InternalErrorJSQ(err, w, r, js)
|
||||||
|
}
|
||||||
|
|
||||||
|
creator, err := c.Users.Get(reply.CreatedBy)
|
||||||
|
if err != nil {
|
||||||
|
return c.InternalErrorJSQ(err, w, r, js)
|
||||||
|
}
|
||||||
|
// ? Does the admin understand that this group perm affects this?
|
||||||
|
if user.ID != creator.ID && !user.Perms.EditReply {
|
||||||
|
return c.NoPermissionsJSQ(w, r, user, js)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Stop blocked users from modifying profile replies?
|
||||||
|
|
||||||
|
err = reply.SetBody(r.PostFormValue("edit_item"))
|
||||||
|
if err != nil {
|
||||||
|
return c.InternalErrorJSQ(err, w, r, js)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !js {
|
||||||
|
http.Redirect(w, r, "/user/"+strconv.Itoa(creator.ID)+"#reply-"+strconv.Itoa(rid), http.StatusSeeOther)
|
||||||
|
} else {
|
||||||
|
w.Write(successJSONBytes)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProfileReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.User, srid string) c.RouteError {
|
||||||
|
js := r.PostFormValue("js") == "1"
|
||||||
|
rid, err := strconv.Atoi(srid)
|
||||||
|
if err != nil {
|
||||||
|
return c.LocalErrorJSQ("The provided Reply ID is not a valid number.", w, r, user, js)
|
||||||
|
}
|
||||||
|
|
||||||
|
reply, err := c.Prstore.Get(rid)
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return c.PreErrorJSQ("The target reply doesn't exist.", w, r, js)
|
||||||
|
} else if err != nil {
|
||||||
|
return c.InternalErrorJSQ(err, w, r, js)
|
||||||
|
}
|
||||||
|
|
||||||
|
creator, err := c.Users.Get(reply.CreatedBy)
|
||||||
|
if err != nil {
|
||||||
|
return c.InternalErrorJSQ(err, w, r, js)
|
||||||
|
}
|
||||||
|
if user.ID != creator.ID && !user.Perms.DeleteReply {
|
||||||
|
return c.NoPermissionsJSQ(w, r, user, js)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = reply.Delete()
|
||||||
|
if err != nil {
|
||||||
|
return c.InternalErrorJSQ(err, w, r, js)
|
||||||
|
}
|
||||||
|
//log.Printf("The profile post '%d' was deleted by c.User #%d", reply.ID, user.ID)
|
||||||
|
|
||||||
|
if !js {
|
||||||
|
//http.Redirect(w,r, "/user/" + strconv.Itoa(creator.ID), http.StatusSeeOther)
|
||||||
|
} else {
|
||||||
|
w.Write(successJSONBytes)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
164
routes/reply.go
164
routes/reply.go
|
@ -92,26 +92,27 @@ func CreateReplySubmit(w http.ResponseWriter, r *http.Request, user c.User) c.Ro
|
||||||
//c.DebugDetail("key: ", key)
|
//c.DebugDetail("key: ", key)
|
||||||
//c.DebugDetailf("values: %+v\n", values)
|
//c.DebugDetailf("values: %+v\n", values)
|
||||||
for _, value := range values {
|
for _, value := range values {
|
||||||
if strings.HasPrefix(key, "pollinputitem[") {
|
if !strings.HasPrefix(key, "pollinputitem[") {
|
||||||
halves := strings.Split(key, "[")
|
continue
|
||||||
if len(halves) != 2 {
|
}
|
||||||
return c.LocalErrorJSQ("Malformed pollinputitem", w, r, user, js)
|
halves := strings.Split(key, "[")
|
||||||
}
|
if len(halves) != 2 {
|
||||||
halves[1] = strings.TrimSuffix(halves[1], "]")
|
return c.LocalErrorJSQ("Malformed pollinputitem", w, r, user, js)
|
||||||
|
}
|
||||||
|
halves[1] = strings.TrimSuffix(halves[1], "]")
|
||||||
|
|
||||||
index, err := strconv.Atoi(halves[1])
|
index, err := strconv.Atoi(halves[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.LocalErrorJSQ("Malformed pollinputitem", w, r, user, js)
|
return c.LocalErrorJSQ("Malformed pollinputitem", w, r, user, js)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there are duplicates, then something has gone horribly wrong, so let's ignore them, this'll likely happen during an attack
|
// If there are duplicates, then something has gone horribly wrong, so let's ignore them, this'll likely happen during an attack
|
||||||
_, exists := pollInputItems[index]
|
_, exists := pollInputItems[index]
|
||||||
// TODO: Should we use SanitiseBody instead to keep the newlines?
|
// TODO: Should we use SanitiseBody instead to keep the newlines?
|
||||||
if !exists && len(c.SanitiseSingleLine(value)) != 0 {
|
if !exists && len(c.SanitiseSingleLine(value)) != 0 {
|
||||||
pollInputItems[index] = c.SanitiseSingleLine(value)
|
pollInputItems[index] = c.SanitiseSingleLine(value)
|
||||||
if len(pollInputItems) >= maxPollOptions {
|
if len(pollInputItems) >= maxPollOptions {
|
||||||
break
|
break
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -140,8 +141,7 @@ func CreateReplySubmit(w http.ResponseWriter, r *http.Request, user c.User) c.Ro
|
||||||
return c.InternalErrorJSQ(err, w, r, js)
|
return c.InternalErrorJSQ(err, w, r, js)
|
||||||
}
|
}
|
||||||
|
|
||||||
wcount := c.WordCount(content)
|
err = user.IncreasePostStats(c.WordCount(content), false)
|
||||||
err = user.IncreasePostStats(wcount, false)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalErrorJSQ(err, w, r, js)
|
return c.InternalErrorJSQ(err, w, r, js)
|
||||||
}
|
}
|
||||||
|
@ -164,14 +164,12 @@ func CreateReplySubmit(w http.ResponseWriter, r *http.Request, user c.User) c.Ro
|
||||||
var rids []int
|
var rids []int
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var rid int
|
var rid int
|
||||||
err := rows.Scan(&rid)
|
if err := rows.Scan(&rid); err != nil {
|
||||||
if err != nil {
|
|
||||||
return c.InternalErrorJSQ(err, w, r, js)
|
return c.InternalErrorJSQ(err, w, r, js)
|
||||||
}
|
}
|
||||||
rids = append(rids, rid)
|
rids = append(rids, rid)
|
||||||
}
|
}
|
||||||
err = rows.Err()
|
if err := rows.Err(); err != nil {
|
||||||
if err != nil {
|
|
||||||
return c.InternalErrorJSQ(err, w, r, js)
|
return c.InternalErrorJSQ(err, w, r, js)
|
||||||
}
|
}
|
||||||
if len(rids) == 0 {
|
if len(rids) == 0 {
|
||||||
|
@ -312,9 +310,7 @@ func ReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.User, srid
|
||||||
return c.NoPermissionsJSQ(w, r, user, js)
|
return c.NoPermissionsJSQ(w, r, user, js)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if err := reply.Delete(); err != nil {
|
||||||
err = reply.Delete()
|
|
||||||
if err != nil {
|
|
||||||
return c.InternalErrorJSQ(err, w, r, js)
|
return c.InternalErrorJSQ(err, w, r, js)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,8 +329,7 @@ func ReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.User, srid
|
||||||
// ? - What happens if an error fires after a redirect...?
|
// ? - What happens if an error fires after a redirect...?
|
||||||
replyCreator, err := c.Users.Get(reply.CreatedBy)
|
replyCreator, err := c.Users.Get(reply.CreatedBy)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
wcount := c.WordCount(reply.Content)
|
err = replyCreator.DecreasePostStats(c.WordCount(reply.Content), false)
|
||||||
err = replyCreator.DecreasePostStats(wcount, false)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalErrorJSQ(err, w, r, js)
|
return c.InternalErrorJSQ(err, w, r, js)
|
||||||
}
|
}
|
||||||
|
@ -463,117 +458,6 @@ func RemoveAttachFromReplySubmit(w http.ResponseWriter, r *http.Request, user c.
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Move the profile reply routes to their own file?
|
|
||||||
func ProfileReplyCreateSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
|
|
||||||
if !user.Perms.ViewTopic || !user.Perms.CreateReply {
|
|
||||||
return c.NoPermissions(w, r, user)
|
|
||||||
}
|
|
||||||
uid, err := strconv.Atoi(r.PostFormValue("uid"))
|
|
||||||
if err != nil {
|
|
||||||
return c.LocalError("Invalid UID", w, r, user)
|
|
||||||
}
|
|
||||||
|
|
||||||
profileOwner, err := c.Users.Get(uid)
|
|
||||||
if err == sql.ErrNoRows {
|
|
||||||
return c.LocalError("The profile you're trying to post on doesn't exist.", w, r, user)
|
|
||||||
} else if err != nil {
|
|
||||||
return c.InternalError(err, w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
content := c.PreparseMessage(r.PostFormValue("content"))
|
|
||||||
if len(content) == 0 {
|
|
||||||
return c.LocalError("You can't make a blank post", w, r, user)
|
|
||||||
}
|
|
||||||
// TODO: Fully parse the post and store it in the parsed column
|
|
||||||
_, err = c.Prstore.Create(profileOwner.ID, content, user.ID, user.LastIP)
|
|
||||||
if err != nil {
|
|
||||||
return c.InternalError(err, w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ! Be careful about leaking per-route permission state with &user
|
|
||||||
alert := c.Alert{ActorID: user.ID, TargetUserID: profileOwner.ID, Event: "reply", ElementType: "user", ElementID: profileOwner.ID, Actor: &user}
|
|
||||||
err = c.AddActivityAndNotifyTarget(alert)
|
|
||||||
if err != nil {
|
|
||||||
return c.InternalError(err, w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
counters.PostCounter.Bump()
|
|
||||||
http.Redirect(w, r, "/user/"+strconv.Itoa(uid), http.StatusSeeOther)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ProfileReplyEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, srid string) c.RouteError {
|
|
||||||
js := r.PostFormValue("js") == "1"
|
|
||||||
rid, err := strconv.Atoi(srid)
|
|
||||||
if err != nil {
|
|
||||||
return c.LocalErrorJSQ("The provided Reply ID is not a valid number.", w, r, user, js)
|
|
||||||
}
|
|
||||||
|
|
||||||
reply, err := c.Prstore.Get(rid)
|
|
||||||
if err == sql.ErrNoRows {
|
|
||||||
return c.PreErrorJSQ("The target reply doesn't exist.", w, r, js)
|
|
||||||
} else if err != nil {
|
|
||||||
return c.InternalErrorJSQ(err, w, r, js)
|
|
||||||
}
|
|
||||||
|
|
||||||
creator, err := c.Users.Get(reply.CreatedBy)
|
|
||||||
if err != nil {
|
|
||||||
return c.InternalErrorJSQ(err, w, r, js)
|
|
||||||
}
|
|
||||||
// ? Does the admin understand that this group perm affects this?
|
|
||||||
if user.ID != creator.ID && !user.Perms.EditReply {
|
|
||||||
return c.NoPermissionsJSQ(w, r, user, js)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = reply.SetBody(r.PostFormValue("edit_item"))
|
|
||||||
if err != nil {
|
|
||||||
return c.InternalErrorJSQ(err, w, r, js)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !js {
|
|
||||||
http.Redirect(w, r, "/user/"+strconv.Itoa(creator.ID)+"#reply-"+strconv.Itoa(rid), http.StatusSeeOther)
|
|
||||||
} else {
|
|
||||||
w.Write(successJSONBytes)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ProfileReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, user c.User, srid string) c.RouteError {
|
|
||||||
js := r.PostFormValue("js") == "1"
|
|
||||||
rid, err := strconv.Atoi(srid)
|
|
||||||
if err != nil {
|
|
||||||
return c.LocalErrorJSQ("The provided Reply ID is not a valid number.", w, r, user, js)
|
|
||||||
}
|
|
||||||
|
|
||||||
reply, err := c.Prstore.Get(rid)
|
|
||||||
if err == sql.ErrNoRows {
|
|
||||||
return c.PreErrorJSQ("The target reply doesn't exist.", w, r, js)
|
|
||||||
} else if err != nil {
|
|
||||||
return c.InternalErrorJSQ(err, w, r, js)
|
|
||||||
}
|
|
||||||
|
|
||||||
creator, err := c.Users.Get(reply.CreatedBy)
|
|
||||||
if err != nil {
|
|
||||||
return c.InternalErrorJSQ(err, w, r, js)
|
|
||||||
}
|
|
||||||
if user.ID != creator.ID && !user.Perms.DeleteReply {
|
|
||||||
return c.NoPermissionsJSQ(w, r, user, js)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = reply.Delete()
|
|
||||||
if err != nil {
|
|
||||||
return c.InternalErrorJSQ(err, w, r, js)
|
|
||||||
}
|
|
||||||
//log.Printf("The profile post '%d' was deleted by c.User #%d", reply.ID, user.ID)
|
|
||||||
|
|
||||||
if !js {
|
|
||||||
//http.Redirect(w,r, "/user/" + strconv.Itoa(creator.ID), http.StatusSeeOther)
|
|
||||||
} else {
|
|
||||||
w.Write(successJSONBytes)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
||||||
|
|
|
@ -27,13 +27,13 @@
|
||||||
{{if not .CurrentUser.Loggedin}}<div class="rowitem passive">
|
{{if not .CurrentUser.Loggedin}}<div class="rowitem passive">
|
||||||
<a class="profile_menu_item">{{lang "profile_login_for_options"}}</a>
|
<a class="profile_menu_item">{{lang "profile_login_for_options"}}</a>
|
||||||
</div>{{else}}
|
</div>{{else}}
|
||||||
<div class="rowitem passive">
|
{{if .CanMessage}}<div class="rowitem passive">
|
||||||
<a href="/user/convos/create/" class="profile_menu_item">{{lang "profile_send_message"}}</a>
|
<a href="/user/convos/create/" class="profile_menu_item">{{lang "profile_send_message"}}</a>
|
||||||
</div>
|
</div>{{end}}
|
||||||
<!--<div class="rowitem passive">
|
<!--<div class="rowitem passive">
|
||||||
<a class="profile_menu_item">{{lang "profile_add_friend"}}</a>
|
<a class="profile_menu_item">{{lang "profile_add_friend"}}</a>
|
||||||
</div>-->
|
</div>-->
|
||||||
{{if (.CurrentUser.IsSuperMod) and not (.ProfileOwner.IsSuperMod) }}<div class="rowitem passive">
|
{{if (.CurrentUser.IsSuperMod) and not (.ProfileOwner.IsSuperMod)}}<div class="rowitem passive">
|
||||||
{{if .ProfileOwner.IsBanned}}<a href="/users/unban/{{.ProfileOwner.ID}}?s={{.CurrentUser.Session}}" class="profile_menu_item">{{lang "profile_unban"}}</a>
|
{{if .ProfileOwner.IsBanned}}<a href="/users/unban/{{.ProfileOwner.ID}}?s={{.CurrentUser.Session}}" class="profile_menu_item">{{lang "profile_unban"}}</a>
|
||||||
{{else}}<a href="#ban_user" class="profile_menu_item">{{lang "profile_ban"}}</a>{{end}}
|
{{else}}<a href="#ban_user" class="profile_menu_item">{{lang "profile_ban"}}</a>{{end}}
|
||||||
</div>{{end}}
|
</div>{{end}}
|
||||||
|
@ -97,7 +97,7 @@
|
||||||
<div id="profile_comments" class="colstack_item hash_hide">{{template "profile_comments_row.html" . }}</div>
|
<div id="profile_comments" class="colstack_item hash_hide">{{template "profile_comments_row.html" . }}</div>
|
||||||
|
|
||||||
{{if .CurrentUser.Loggedin}}
|
{{if .CurrentUser.Loggedin}}
|
||||||
{{if not .CurrentUser.IsBanned}}
|
{{if .CanComment}}
|
||||||
<form id="profile_comments_form" class="hash_hide" action="/profile/reply/create/?s={{.CurrentUser.Session}}" method="post">
|
<form id="profile_comments_form" class="hash_hide" action="/profile/reply/create/?s={{.CurrentUser.Session}}" method="post">
|
||||||
<input name="uid" value='{{.ProfileOwner.ID}}' type="hidden" />
|
<input name="uid" value='{{.ProfileOwner.ID}}' type="hidden" />
|
||||||
<div class="colstack_item topic_reply_form" style="border-top:none;">
|
<div class="colstack_item topic_reply_form" style="border-top:none;">
|
||||||
|
|
Loading…
Reference in New Issue