From cec5f93fb603e8c26b0aa314d100ebbf7eef4e70 Mon Sep 17 00:00:00 2001 From: cblgh Date: Thu, 22 Apr 2021 10:36:59 +0200 Subject: [PATCH] tests for restricted UI behavior * add tests for privacy mode settings * test privacy mode settings for member role * test default language settings * test denied keys interface for each role * test adding new member interface depending on role * test member details depending on role * test invite button is disabled pending on user role --- web/handlers/admin/denied_keys_test.go | 80 +++++++++++++++++++ web/handlers/admin/invites_test.go | 44 +++++++++++ web/handlers/admin/members_test.go | 87 +++++++++++++++++++-- web/handlers/admin/set_language_test.go | 5 ++ web/handlers/admin/settings_test.go | 100 ++++++++++++++++++++++++ web/handlers/admin/setup_test.go | 11 ++- web/members/helper.go | 2 +- web/templates/admin/denied-keys.tmpl | 2 +- web/templates/admin/member-list.tmpl | 2 +- web/templates/admin/settings.tmpl | 6 +- 10 files changed, 322 insertions(+), 17 deletions(-) create mode 100644 web/handlers/admin/settings_test.go diff --git a/web/handlers/admin/denied_keys_test.go b/web/handlers/admin/denied_keys_test.go index 678f41d..cc38289 100644 --- a/web/handlers/admin/denied_keys_test.go +++ b/web/handlers/admin/denied_keys_test.go @@ -8,6 +8,7 @@ import ( "net/url" "testing" + "github.com/PuerkitoBio/goquery" "github.com/stretchr/testify/assert" "github.com/ssb-ngi-pointer/go-ssb-room/roomdb" @@ -32,6 +33,85 @@ func TestDeniedKeysEmpty(t *testing.T) { }) } +func TestDeniedKeysDisabledInterface(t *testing.T) { + ts := newSession(t) + a := assert.New(t) + + listURL := ts.URLTo(router.AdminDeniedKeysOverview) + + ts.User = roomdb.Member{ + ID: 1234, + Role: roomdb.RoleAdmin, + } + + html, resp := ts.Client.GetHTML(listURL) + a.Equal(http.StatusOK, resp.Code, "wrong HTTP status code") + + formSelection := html.Find("form#add-entry") + a.EqualValues(1, formSelection.Length()) + + method, ok := formSelection.Attr("method") + a.True(ok, "form has method set") + a.Equal("POST", method) + + action, ok := formSelection.Attr("action") + a.True(ok, "form has action set") + + addURL := ts.URLTo(router.AdminDeniedKeysAdd) + a.Equal(addURL.String(), action) + + webassert.ElementsInForm(t, formSelection, []webassert.FormElement{ + {Name: "pub_key", Type: "text"}, + {Name: "comment", Type: "text"}, + }) + + newKey := "@x7iOLUcq3o+sjGeAnipvWeGzfuYgrXl8L4LYlxIhwDc=.ed25519" + addVals := url.Values{ + "comment": []string{"some comment"}, + // just any key that looks valid + "pub_key": []string{newKey}, + } + rec := ts.Client.PostForm(addURL, addVals) + a.Equal(http.StatusTemporaryRedirect, rec.Code) + + a.Equal(1, ts.DeniedKeysDB.AddCallCount()) + _, addedKey, addedComment := ts.DeniedKeysDB.AddArgsForCall(0) + a.Equal(newKey, addedKey.Ref()) + a.Equal("some comment", addedComment) + + /* Verify that the inputs are visible/hidden depending on user roles */ + checkInputsAreDisabled := func(shouldBeDisabled bool) { + html, resp = ts.Client.GetHTML(listURL) + a.Equal(http.StatusOK, resp.Code, "wrong HTTP status code") + inputContainer := html.Find("#denied-keys-input-container") + a.Equal(1, inputContainer.Length()) + inputs := inputContainer.Find("input") + // pubkey, comment, submit button + a.Equal(3, inputs.Length()) + inputs.Each(func(i int, el *goquery.Selection) { + _, disabled := el.Attr("disabled") + a.Equal(shouldBeDisabled, disabled) + }) + } + + // verify that inputs are enabled for RoleAdmin + checkInputsAreDisabled(false) + + // verify that inputs are enabled for RoleModerator + ts.User = roomdb.Member{ + ID: 9001, + Role: roomdb.RoleModerator, + } + checkInputsAreDisabled(false) + + // verify that inputs are disabled for RoleMember + ts.User = roomdb.Member{ + ID: 7331, + Role: roomdb.RoleMember, + } + checkInputsAreDisabled(true) +} + func TestDeniedKeysAdd(t *testing.T) { ts := newSession(t) a := assert.New(t) diff --git a/web/handlers/admin/invites_test.go b/web/handlers/admin/invites_test.go index 2a32ceb..c074060 100644 --- a/web/handlers/admin/invites_test.go +++ b/web/handlers/admin/invites_test.go @@ -64,6 +64,50 @@ func TestInvitesOverview(t *testing.T) { a.True(yes, "a-tag has href attribute") wantURL := ts.URLTo(router.AdminInvitesRevokeConfirm, "id", 666) a.Equal(wantURL.String(), link) + + testInviteButtonDisabled := func(shouldBeDisabled bool) { + html, resp = ts.Client.GetHTML(invitesOverviewURL) + a.Equal(http.StatusOK, resp.Code, "wrong HTTP status code") + inviteButton := html.Find("#create-invite button") + _, disabled := inviteButton.Attr("disabled") + a.EqualValues(shouldBeDisabled, disabled, "invite button should be disabled") + } + + // member, mod, admin should all be able to invite in ModeCommunity + ts.ConfigDB.GetPrivacyModeReturns(roomdb.ModeCommunity, nil) + ts.User = roomdb.Member{ + ID: 1234, + Role: roomdb.RoleAdmin, + } + testInviteButtonDisabled(false) + ts.User = roomdb.Member{ + ID: 7331, + Role: roomdb.RoleModerator, + } + testInviteButtonDisabled(false) + ts.User = roomdb.Member{ + ID: 9001, + Role: roomdb.RoleMember, + } + testInviteButtonDisabled(false) + + // mod and admin should be able to invite, member should not + ts.ConfigDB.GetPrivacyModeReturns(roomdb.ModeRestricted, nil) + ts.User = roomdb.Member{ + ID: 1234, + Role: roomdb.RoleAdmin, + } + testInviteButtonDisabled(false) + ts.User = roomdb.Member{ + ID: 7331, + Role: roomdb.RoleModerator, + } + testInviteButtonDisabled(false) + ts.User = roomdb.Member{ + ID: 9001, + Role: roomdb.RoleMember, + } + testInviteButtonDisabled(true) } func TestInvitesCreateForm(t *testing.T) { diff --git a/web/handlers/admin/members_test.go b/web/handlers/admin/members_test.go index 0d870f4..ac24bb0 100644 --- a/web/handlers/admin/members_test.go +++ b/web/handlers/admin/members_test.go @@ -7,6 +7,7 @@ import ( "net/url" "testing" + "github.com/PuerkitoBio/goquery" "github.com/stretchr/testify/assert" "github.com/ssb-ngi-pointer/go-ssb-room/roomdb" @@ -35,6 +36,11 @@ func TestMembersAdd(t *testing.T) { ts := newSession(t) a := assert.New(t) + ts.User = roomdb.Member{ + ID: 1234, + Role: roomdb.RoleAdmin, + } + listURL := ts.URLTo(router.AdminMembersOverview) html, resp := ts.Client.GetHTML(listURL) @@ -70,6 +76,43 @@ func TestMembersAdd(t *testing.T) { a.Equal(newKey, addedPubKey.Ref()) a.Equal(roomdb.RoleMember, addedRole) + /* Verify that the inputs are visible/hidden depending on user roles */ + checkInputsAreDisabled := func(shouldBeDisabled bool) { + html, resp = ts.Client.GetHTML(listURL) + a.Equal(http.StatusOK, resp.Code, "wrong HTTP status code") + inputContainer := html.Find("#add-member-input-container") + a.Equal(1, inputContainer.Length()) + inputs := inputContainer.Find("input") + // pubkey + a.Equal(1, inputs.Length()) + inputs.Each(func(i int, el *goquery.Selection) { + _, disabled := el.Attr("disabled") + a.Equal(shouldBeDisabled, disabled) + }) + button := inputContainer.Find("button") + a.Equal(1, button.Length()) + button.Each(func(i int, el *goquery.Selection) { + _, disabled := el.Attr("disabled") + a.Equal(shouldBeDisabled, disabled) + }) + } + + // verify that inputs are enabled for RoleAdmin + checkInputsAreDisabled(false) + + // verify that inputs are enabled for RoleModerator + ts.User = roomdb.Member{ + ID: 9001, + Role: roomdb.RoleModerator, + } + checkInputsAreDisabled(false) + + // verify that inputs are disabled for RoleMember + ts.User = roomdb.Member{ + ID: 7331, + Role: roomdb.RoleMember, + } + checkInputsAreDisabled(true) } func TestMembersDontAddInvalid(t *testing.T) { @@ -173,6 +216,11 @@ func TestMemberDetails(t *testing.T) { memberURL := ts.URLTo(router.AdminMemberDetails, "id", "1") + ts.User = roomdb.Member{ + ID: 1234, + Role: roomdb.RoleAdmin, + } + html, resp := ts.Client.GetHTML(memberURL) a.Equal(http.StatusOK, resp.Code, "wrong HTTP status code") @@ -180,14 +228,6 @@ func TestMemberDetails(t *testing.T) { {"title", "AdminMemberDetailsTitle"}, }) - // check for SSB ID - ssbID := html.Find("#ssb-id") - a.Equal(feedRef.Ref(), ssbID.Text()) - - // check for change-role dropdown - roleDropdown := html.Find("#change-role") - a.EqualValues(roleDropdown.Length(), 1) - aliasList := html.Find("#alias-list").Find("a") // check for link to resolve 1st Alias @@ -220,6 +260,37 @@ func TestMemberDetails(t *testing.T) { a.True(yes, "a-tag has href attribute") wantLink = ts.URLTo(router.AdminMembersRemoveConfirm, "id", 1) a.Equal(wantLink.String(), removeLink) + + testDisabledBehaviour := func(isElevated bool) { + html, resp := ts.Client.GetHTML(memberURL) + a.Equal(http.StatusOK, resp.Code, "wrong HTTP status code") + // check for SSB ID + ssbID := html.Find("#ssb-id") + a.Equal(feedRef.Ref(), ssbID.Text()) + + // check for change-role dropdown + roleDropdown := html.Find("#change-role") + if isElevated { + a.Equal(1, roleDropdown.Length()) + } else { + a.Equal(0, roleDropdown.Length()) + } + } + testDisabledBehaviour(true) + + /* Now: verify that moderators cannot make room settings changes */ + ts.User = roomdb.Member{ + ID: 7331, + Role: roomdb.RoleModerator, + } + testDisabledBehaviour(true) + + /* Finally: verify that members cannot make room settings changes */ + ts.User = roomdb.Member{ + ID: 9001, + Role: roomdb.RoleMember, + } + testDisabledBehaviour(false) } func TestMembersRemoveConfirmation(t *testing.T) { diff --git a/web/handlers/admin/set_language_test.go b/web/handlers/admin/set_language_test.go index 9d57d11..af5b5a1 100644 --- a/web/handlers/admin/set_language_test.go +++ b/web/handlers/admin/set_language_test.go @@ -5,6 +5,7 @@ import ( "strings" "testing" + "github.com/ssb-ngi-pointer/go-ssb-room/roomdb" "github.com/ssb-ngi-pointer/go-ssb-room/web/router" "github.com/stretchr/testify/assert" ) @@ -33,6 +34,10 @@ func TestLanguageSetDefaultLanguage(t *testing.T) { a := assert.New(t) ts.ConfigDB.GetDefaultLanguageReturns("de", nil) + ts.User = roomdb.Member{ + ID: 1234, + Role: roomdb.RoleAdmin, + } u := ts.URLTo(router.AdminSettings) html, resp := ts.Client.GetHTML(u) diff --git a/web/handlers/admin/settings_test.go b/web/handlers/admin/settings_test.go new file mode 100644 index 0000000..c05c3a8 --- /dev/null +++ b/web/handlers/admin/settings_test.go @@ -0,0 +1,100 @@ +package admin + +import ( + "net/http" + "strings" + "testing" + + "github.com/PuerkitoBio/goquery" + "github.com/stretchr/testify/assert" + + "github.com/ssb-ngi-pointer/go-ssb-room/roomdb" + "github.com/ssb-ngi-pointer/go-ssb-room/web/router" +) + +func TestSettingsOverview(t *testing.T) { + ts := newSession(t) + a := assert.New(t) + + /* First: make sure everything renders correctly for admins */ + ts.User = roomdb.Member{ + ID: 1234, + Role: roomdb.RoleAdmin, + } + + ts.ConfigDB.GetPrivacyModeReturns(roomdb.ModeCommunity, nil) + ts.ConfigDB.GetDefaultLanguageReturns("en", nil) + + settingsURL := ts.URLTo(router.AdminSettings) + + html, resp := ts.Client.GetHTML(settingsURL) + a.Equal(http.StatusOK, resp.Code, "wrong HTTP status code") + + // the privacy mode form & its summary/details container should exist + privacyFormContainer := html.Find("#change-privacy") + a.Equal(1, privacyFormContainer.Length()) + a.Equal(1, privacyFormContainer.Find("summary").Length()) + // chosen privacy mode is ModeCommunity (english translation will only be the name of the label, due to testing suite is set up atm) + a.Equal("ModeCommunity", strings.TrimSpace(privacyFormContainer.Find("summary").Text())) + // details-dropdown should have two forms, one for each of the other two privacy modes + // that can be selected (ModeOpen, ModeRestricted) + a.Equal(2, privacyFormContainer.Find("form").Length()) + // and one span, showing the selected mode + a.Equal(1, privacyFormContainer.Find("#selected-mode").Length()) + inputs := privacyFormContainer.Find("input") + // verify none of the privacy mode container's inputs are disabled + inputs.Each(func(i int, el *goquery.Selection) { + _, exists := el.Attr("disabled") + a.False(exists) + }) + + // verify that the change language form exists & is enabled + languageFormContainer := html.Find("#change-language-container") + a.Equal(1, languageFormContainer.Length()) + a.Equal(1, languageFormContainer.Find("summary").Length()) + // (english translation will only be the name of the label, due to testing suite is set up atm) + a.Equal("LanguageName", strings.TrimSpace(languageFormContainer.Find("summary").Text())) + + testDisabledBehaviour := func() { + settingsURL := ts.URLTo(router.AdminSettings) + html, resp := ts.Client.GetHTML(settingsURL) + a.Equal(http.StatusOK, resp.Code, "wrong HTTP status code") + + // we do not have the summary/details hack if the forms are hidden + privacyFormContainer := html.Find("#change-privacy") + a.Equal(0, privacyFormContainer.Length()) + // the should still be the parent container, however + privacyContainer := html.Find("#privacy-mode-container") + a.Equal(1, privacyContainer.Length()) + // there should only be one input in the privacy mode container now + inputs := privacyContainer.Find("input") + a.Equal(1, inputs.Length()) + // the input should be disabled + _, disabled := inputs.Attr("disabled") + a.True(disabled) + + // next, verify that the change language setting is disabled + languageContainer := html.Find("#change-language-container") + a.Equal(1, languageContainer.Length()) + // there should only be one input in the language mode container now + inputs = languageContainer.Find("input") + a.Equal(1, inputs.Length()) + // the input should be disabled + _, disabled = inputs.Attr("disabled") + a.True(disabled) + } + + /* Now: verify that moderators cannot make room settings changes */ + ts.User = roomdb.Member{ + ID: 7331, + Role: roomdb.RoleModerator, + } + testDisabledBehaviour() + + /* Finally: verify that members cannot make room settings changes */ + ts.User = roomdb.Member{ + ID: 9001, + Role: roomdb.RoleMember, + } + testDisabledBehaviour() +} diff --git a/web/handlers/admin/setup_test.go b/web/handlers/admin/setup_test.go index eeac3fb..07ce1e1 100644 --- a/web/handlers/admin/setup_test.go +++ b/web/handlers/admin/setup_test.go @@ -133,9 +133,14 @@ func newSession(t *testing.T) *testSession { testFuncs["urlToNotice"] = func(name string) string { return "" } testFuncs["language_count"] = func() int { return 1 } testFuncs["list_languages"] = func(*url.URL, string) string { return "" } - testFuncs["member_is_elevated"] = func() bool { return true } - testFuncs["member_is_admin"] = func() bool { return true } - testFuncs["member_can_invite"] = func() bool { return true } + testFuncs["member_is_elevated"] = func() bool { return ts.User.Role == roomdb.RoleAdmin || ts.User.Role == roomdb.RoleModerator } + testFuncs["member_is_admin"] = func() bool { return ts.User.Role == roomdb.RoleAdmin } + testFuncs["member_can_invite"] = func() bool { + pm, _ := ts.ConfigDB.GetPrivacyMode(ctx) + memberElevated := ts.User.Role == roomdb.RoleAdmin || ts.User.Role == roomdb.RoleModerator + memberCanInvite := ts.User.Role == roomdb.RoleMember && (pm == roomdb.ModeCommunity || pm == roomdb.ModeOpen) + return memberElevated || memberCanInvite + } testFuncs["list_languages"] = func(*url.URL, string) string { return "" } testFuncs["relative_time"] = func(when time.Time) string { return humanize.Time(when) } diff --git a/web/members/helper.go b/web/members/helper.go index 8677d53..42542ed 100644 --- a/web/members/helper.go +++ b/web/members/helper.go @@ -100,7 +100,7 @@ func ContextInjecter(mdb roomdb.MembersService, withPassword *auth.Handler, with // // {{ member_is_admin }} is a shortcut for {{ member_has_role "RoleAdmin" }} // -// {{ member_is_admin }} is a shortcut for {{ or member_has_role "RoleAdmin" member_has_role "RoleModerator"}} +// {{ member_is_elevated }} is a shortcut for {{ or member_has_role "RoleAdmin" member_has_role "RoleModerator"}} func TemplateHelpers() []render.Option { return []render.Option{ diff --git a/web/templates/admin/denied-keys.tmpl b/web/templates/admin/denied-keys.tmpl index 175bea9..c082bfc 100644 --- a/web/templates/admin/denied-keys.tmpl +++ b/web/templates/admin/denied-keys.tmpl @@ -20,7 +20,7 @@ method="POST" > {{ .csrfField }} -
+
{{ .csrfField }} -
+
{{ i18n "Settings" }} -
+

{{ i18n "PrivacyModesTitle" }}

{{ i18n "ExplanationPrivacyModes" }} @@ -39,7 +39,7 @@

- {{ i18n .String }} + {{ i18n .String }}
{{end}} {{end}} @@ -59,7 +59,7 @@
{{ i18n "ExplanationRestricted" }}
-
+

{{ i18n "DefaultLanguageTitle" }}

{{ i18n "ExplanationDefaultLanguage" }}