diff --git a/common/user.go b/common/user.go index 37d935b6..c8895675 100644 --- a/common/user.go +++ b/common/user.go @@ -66,8 +66,8 @@ type User struct { } type UserPrivacy struct { - ShowComments int // 0 = default, 1 = public, 2 = registered, 3 = friends, 4 = mods / self - AllowMessage int // 0 = default, 1 = registered, 2 = friends, 3 = 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, 4 = disabled / unused } 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") /*func (u *User) UpdatePrivacyS(sProfileComments, sEnableEmbeds string) error { - 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 type GuestAvatar struct { diff --git a/misc_test.go b/misc_test.go index 3e023401..92a24d8a 100644 --- a/misc_test.go +++ b/misc_test.go @@ -2012,7 +2012,7 @@ func TestUtils(t *testing.T) { eemail := "" cemail = c.CanonEmail(email) expect(t, cemail == eemail, fmt.Sprintf("%s should be %s", cemail, eemail)) - + email = "ddd" eemail = "ddd" cemail = c.CanonEmail(email) @@ -2197,6 +2197,108 @@ func passwordTest(t *testing.T, realPassword, hashedPassword string) { 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 { Name string // Optional, this is here for tests involving invisible characters so we know what's going in Msg string diff --git a/routes/profile.go b/routes/profile.go index 3cd8ce84..f4946ad8 100644 --- a/routes/profile.go +++ b/routes/profile.go @@ -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 canComment := !blockedInv && user.Perms.CreateProfileReply - showComments := profileCommentsShow(puser, user) + showComments := c.PrivacyCommentsShow(puser, user) if !showComments { canComment = false } - if !profileAllowMessage(puser, user) { + if !c.PrivacyAllowMessage(puser, user) { canMessage = false } ppage := c.ProfilePage{h, reList, *puser, currentScore, nextScore, blocked, canMessage, canComment, showComments} 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 -} diff --git a/routes/profile_reply.go b/routes/profile_reply.go index 031af0c0..396abb58 100644 --- a/routes/profile_reply.go +++ b/routes/profile_reply.go @@ -6,51 +6,51 @@ import ( "strconv" 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 { - if !user.Perms.CreateProfileReply { - return c.NoPermissions(w, r, user) +func ProfileReplyCreateSubmit(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError { + if !u.Perms.CreateProfileReply { + return c.NoPermissions(w, r, u) } uid, err := strconv.Atoi(r.PostFormValue("uid")) 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) 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 { 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 { 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 || !profileCommentsShow(profileOwner, user)) && !user.IsSuperMod { - return c.LocalError("You don't have permission to send messages to one of these users.", w, r, user) + 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, u) } content := c.PreparseMessage(r.PostFormValue("content")) 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 - 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 { return c.InternalError(err, w, r) } // ! 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) if err != nil { return c.InternalError(err, w, r) } - counters.PostCounter.Bump() + co.PostCounter.Bump() http.Redirect(w, r, "/user/"+strconv.Itoa(uid), http.StatusSeeOther) return nil } @@ -91,7 +91,7 @@ func ProfileReplyEditSubmit(w http.ResponseWriter, r *http.Request, u *c.User, s 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 || !profileCommentsShow(profileOwner, u)) && !u.IsSuperMod { + if (blocked || !c.PrivacyCommentsShow(profileOwner, u)) && !u.IsSuperMod { 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 { return c.LocalErrorJSQ("The provided Reply ID is not a valid number.", w, r, u, js) } - reply, err := c.Prstore.Get(rid) if err == sql.ErrNoRows { return c.PreErrorJSQ("The target reply doesn't exist.", w, r, js)