unit tests for profile comment visibility

This commit is contained in:
Azareal 2020-07-15 16:59:47 +10:00
parent eeb932bd4b
commit 5bfc5e3e40
4 changed files with 158 additions and 53 deletions

View File

@ -66,8 +66,8 @@ type User struct {
} }
type UserPrivacy struct { type UserPrivacy struct {
ShowComments int // 0 = default, 1 = public, 2 = registered, 3 = friends, 4 = mods / self ShowComments int // 0 = default, 1 = public, 2 = registered, 3 = friends, 4 = self, 5 = disabled / unused
AllowMessage int // 0 = default, 1 = registered, 2 = friends, 3 = mods / self AllowMessage int // 0 = default, 1 = registered, 2 = friends, 3 = mods, 4 = disabled / unused
} }
func (u *User) WebSockets() *WsJSONUser { func (u *User) WebSockets() *WsJSONUser {
@ -569,7 +569,6 @@ var ErrProfileCommentsOutOfBounds = errors.New("profile_comments must be an inte
var ErrEnableEmbedsOutOfBounds = errors.New("enable_embeds must be -1, 0 or 1") var ErrEnableEmbedsOutOfBounds = errors.New("enable_embeds must be -1, 0 or 1")
/*func (u *User) UpdatePrivacyS(sProfileComments, sEnableEmbeds string) error { /*func (u *User) UpdatePrivacyS(sProfileComments, sEnableEmbeds string) error {
return u.UpdatePrivacy(profileComments, enableEmbeds) return u.UpdatePrivacy(profileComments, enableEmbeds)
}*/ }*/
@ -723,6 +722,43 @@ func (u *User) InitPerms() {
} }
} }
// TODO: Write tests
// TODO: Implement and use this
// TODO: Implement friends
func PrivacyAllowMessage(pu, u *User) (canMsg bool) {
switch pu.Privacy.AllowMessage {
case 4: // Unused
canMsg = false
case 3: // mods
canMsg = u.IsSuperMod
//case 2: // friends
case 1: // registered
canMsg = true
default: // 0
canMsg = true
}
return canMsg
}
// TODO: Implement friend system
func PrivacyCommentsShow(pu, u *User) (showComments bool) {
switch pu.Privacy.ShowComments {
case 5: // Unused
showComments = false
case 4: // Self
showComments = u.ID == pu.ID
case 3: // friends
showComments = u.ID == pu.ID
case 2: // registered
showComments = u.Loggedin
case 1: // public
showComments = true
default: // 0
showComments = true
}
return showComments
}
var guestAvatar GuestAvatar var guestAvatar GuestAvatar
type GuestAvatar struct { type GuestAvatar struct {

View File

@ -2197,6 +2197,108 @@ func passwordTest(t *testing.T, realPassword, hashedPassword string) {
expect(t, err != nil, "The two shouldn't match!") expect(t, err != nil, "The two shouldn't match!")
} }
func TestUserPrivacy(t *testing.T) {
pu, u := c.BlankUser(), &c.GuestUser
pu.ID = 1
var msg string
test := func(expects bool, level int) {
pu.Privacy.ShowComments = level
val := c.PrivacyCommentsShow(pu, u)
var bit string
if !expects {
bit = " not"
val = !val
}
expect(t, val, fmt.Sprintf("%s should%s be able to see comments on level %d", msg, bit, level))
}
// 0 = default, 1 = public, 2 = registered, 3 = friends, 4 = self, 5 = disabled
msg = "guest users"
test(true, 0)
test(true, 1)
test(false, 2)
test(false, 3)
test(false, 4)
test(false, 5)
u = c.BlankUser()
msg = "blank users"
test(true, 0)
test(true, 1)
test(false, 2)
//test(false,3)
test(false, 4)
test(false, 5)
u.Loggedin = true
msg = "registered users"
test(true, 0)
test(true, 1)
test(true, 2)
test(false, 3)
test(false, 4)
test(false, 5)
u.IsBanned = true
msg = "banned users"
test(true, 0)
test(true, 1)
test(true, 2)
test(false, 3)
test(false, 4)
test(false, 5)
u.IsBanned = false
u.IsMod = true
msg = "mods"
test(true, 0)
test(true, 1)
test(true, 2)
test(false, 3)
test(false, 4)
test(false, 5)
u.IsMod = false
u.IsSuperMod = true
msg = "super mods"
test(true, 0)
test(true, 1)
test(true, 2)
test(false, 3)
test(false, 4)
test(false, 5)
u.IsSuperMod = false
u.IsAdmin = true
msg = "admins"
test(true, 0)
test(true, 1)
test(true, 2)
test(false, 3)
test(false, 4)
test(false, 5)
u.IsAdmin = false
u.IsSuperAdmin = true
msg = "super admins"
test(true, 0)
test(true, 1)
test(true, 2)
test(false, 3)
test(false, 4)
test(false, 5)
u.IsSuperAdmin = false
u.ID = 1
test(true, 0)
test(true, 1)
test(true, 2)
test(true, 3)
test(true, 4)
test(false, 5)
}
type METri struct { type METri struct {
Name string // Optional, this is here for tests involving invisible characters so we know what's going in Name string // Optional, this is here for tests involving invisible characters so we know what's going in
Msg string Msg string

View File

@ -113,46 +113,14 @@ func ViewProfile(w http.ResponseWriter, r *http.Request, user *c.User, h *c.Head
canMessage := (!blockedInv && user.Perms.UseConvos) || (!blockedInv && puser.IsSuperMod && user.Perms.UseConvosOnlyWithMod) || user.IsSuperMod canMessage := (!blockedInv && user.Perms.UseConvos) || (!blockedInv && puser.IsSuperMod && user.Perms.UseConvosOnlyWithMod) || user.IsSuperMod
canComment := !blockedInv && user.Perms.CreateProfileReply canComment := !blockedInv && user.Perms.CreateProfileReply
showComments := profileCommentsShow(puser, user) showComments := c.PrivacyCommentsShow(puser, user)
if !showComments { if !showComments {
canComment = false canComment = false
} }
if !profileAllowMessage(puser, user) { if !c.PrivacyAllowMessage(puser, user) {
canMessage = false canMessage = false
} }
ppage := c.ProfilePage{h, reList, *puser, currentScore, nextScore, blocked, canMessage, canComment, showComments} ppage := c.ProfilePage{h, reList, *puser, currentScore, nextScore, blocked, canMessage, canComment, showComments}
return renderTemplate("profile", w, r, h, ppage) return renderTemplate("profile", w, r, h, ppage)
} }
func profileAllowMessage(pu, u *c.User) (canMsg bool) {
switch pu.Privacy.AllowMessage {
case 4: // Unused
canMsg = false
case 3: // mods / self
canMsg = u.IsSuperMod
//case 2: // friends
case 1: // registered
canMsg = true
default: // 0
canMsg = true
}
return canMsg
}
func profileCommentsShow(pu, u *c.User) (showComments bool) {
switch pu.Privacy.ShowComments {
case 5: // Unused
showComments = false
case 4: // Self
showComments = u.ID == pu.ID
//case 3: // friends
case 2: // registered
showComments = u.Loggedin
case 1: // public
showComments = true
default: // 0
showComments = true
}
return showComments
}

View File

@ -6,51 +6,51 @@ import (
"strconv" "strconv"
c "github.com/Azareal/Gosora/common" c "github.com/Azareal/Gosora/common"
"github.com/Azareal/Gosora/common/counters" co "github.com/Azareal/Gosora/common/counters"
) )
func ProfileReplyCreateSubmit(w http.ResponseWriter, r *http.Request, user *c.User) c.RouteError { func ProfileReplyCreateSubmit(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError {
if !user.Perms.CreateProfileReply { if !u.Perms.CreateProfileReply {
return c.NoPermissions(w, r, user) return c.NoPermissions(w, r, u)
} }
uid, err := strconv.Atoi(r.PostFormValue("uid")) uid, err := strconv.Atoi(r.PostFormValue("uid"))
if err != nil { if err != nil {
return c.LocalError("Invalid UID", w, r, user) return c.LocalError("Invalid UID", w, r, u)
} }
profileOwner, err := c.Users.Get(uid) profileOwner, err := c.Users.Get(uid)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
return c.LocalError("The profile you're trying to post on doesn't exist.", w, r, user) return c.LocalError("The profile you're trying to post on doesn't exist.", w, r, u)
} else if err != nil { } else if err != nil {
return c.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
blocked, err := c.UserBlocks.IsBlockedBy(profileOwner.ID, user.ID) blocked, err := c.UserBlocks.IsBlockedBy(profileOwner.ID, u.ID)
if err != nil { if err != nil {
return c.InternalError(err, w, r) 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 // Supermods can bypass blocks so they can tell people off when they do something stupid or have to convey important information
if (blocked || !profileCommentsShow(profileOwner, user)) && !user.IsSuperMod { if (blocked || !c.PrivacyCommentsShow(profileOwner, u)) && !u.IsSuperMod {
return c.LocalError("You don't have permission to send messages to one of these users.", w, r, user) return c.LocalError("You don't have permission to send messages to one of these users.", w, r, u)
} }
content := c.PreparseMessage(r.PostFormValue("content")) content := c.PreparseMessage(r.PostFormValue("content"))
if len(content) == 0 { if len(content) == 0 {
return c.LocalError("You can't make a blank post", w, r, user) return c.LocalError("You can't make a blank post", w, r, u)
} }
// TODO: Fully parse the post and store it in the parsed column // TODO: Fully parse the post and store it in the parsed column
prid, err := c.Prstore.Create(profileOwner.ID, content, user.ID, user.GetIP()) prid, err := c.Prstore.Create(profileOwner.ID, content, u.ID, u.GetIP())
if err != nil { if err != nil {
return c.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
// ! Be careful about leaking per-route permission state with user ptr // ! Be careful about leaking per-route permission state with user ptr
alert := c.Alert{ActorID: user.ID, TargetUserID: profileOwner.ID, Event: "reply", ElementType: "user", ElementID: profileOwner.ID, Actor: user, Extra: strconv.Itoa(prid)} alert := c.Alert{ActorID: u.ID, TargetUserID: profileOwner.ID, Event: "reply", ElementType: "user", ElementID: profileOwner.ID, Actor: u, Extra: strconv.Itoa(prid)}
err = c.AddActivityAndNotifyTarget(alert) err = c.AddActivityAndNotifyTarget(alert)
if err != nil { if err != nil {
return c.InternalError(err, w, r) return c.InternalError(err, w, r)
} }
counters.PostCounter.Bump() co.PostCounter.Bump()
http.Redirect(w, r, "/user/"+strconv.Itoa(uid), http.StatusSeeOther) http.Redirect(w, r, "/user/"+strconv.Itoa(uid), http.StatusSeeOther)
return nil return nil
} }
@ -91,7 +91,7 @@ func ProfileReplyEditSubmit(w http.ResponseWriter, r *http.Request, u *c.User, s
return c.InternalError(err, w, r) 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 // Supermods can bypass blocks so they can tell people off when they do something stupid or have to convey important information
if (blocked || !profileCommentsShow(profileOwner, u)) && !u.IsSuperMod { if (blocked || !c.PrivacyCommentsShow(profileOwner, u)) && !u.IsSuperMod {
return c.NoPermissionsJSQ(w, r, u, js) return c.NoPermissionsJSQ(w, r, u, js)
} }
@ -108,7 +108,6 @@ func ProfileReplyDeleteSubmit(w http.ResponseWriter, r *http.Request, u *c.User,
if err != nil { if err != nil {
return c.LocalErrorJSQ("The provided Reply ID is not a valid number.", w, r, u, js) return c.LocalErrorJSQ("The provided Reply ID is not a valid number.", w, r, u, js)
} }
reply, err := c.Prstore.Get(rid) reply, err := c.Prstore.Get(rid)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
return c.PreErrorJSQ("The target reply doesn't exist.", w, r, js) return c.PreErrorJSQ("The target reply doesn't exist.", w, r, js)