diff --git a/CHANGELOG.rst b/CHANGELOG.rst index fe7a89aa0ed37c4d3b6bf684618a0f2f1c5ac001..5edb5daf763038840e0242bfe1c86006c5eec721 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,6 +9,11 @@ and this project adheres to `Semantic Versioning`_. Unreleased ---------- +Fixed +~~~~~ + +* The search bar in the sidenav menu is shown even though the user has no permission to see it. + `3.0`_ - 2022-05-11 ------------------- diff --git a/aleksis/core/frontend/components/app/SideNav.vue b/aleksis/core/frontend/components/app/SideNav.vue index 0975c580cda88d03fd8a5d34b2fb16425ece69ee..70537e18342c56bd931f96adc89e796596dd5cb6 100644 --- a/aleksis/core/frontend/components/app/SideNav.vue +++ b/aleksis/core/frontend/components/app/SideNav.vue @@ -10,7 +10,7 @@ <brand-logo :site-preferences="systemProperties.sitePreferences" /> </a> </v-list-item> - <v-list-item class="search"> + <v-list-item v-if="checkPermission('core.search_rule')" class="search"> <sidenav-search /> </v-list-item> <v-list-item-group :value="$route.name" v-if="sideNavMenu"> @@ -94,6 +94,8 @@ import BrandLogo from "./BrandLogo.vue"; import LanguageForm from "./LanguageForm.vue"; import SidenavSearch from "./SidenavSearch.vue"; +import permissionsMixin from "../../mixins/permissions.js"; + export default { name: "SideNav", components: { @@ -106,6 +108,10 @@ export default { systemProperties: { type: Object, required: true }, value: { type: Boolean, required: true }, }, + mixins: [permissionsMixin], + mounted() { + this.fetchPermissions(["core.search_rule"]); + }, }; </script> diff --git a/aleksis/core/frontend/components/app/permissions.graphql b/aleksis/core/frontend/components/app/permissions.graphql new file mode 100644 index 0000000000000000000000000000000000000000..fcb6133e0afdb78e9a2fb750e1972d64aa0968e7 --- /dev/null +++ b/aleksis/core/frontend/components/app/permissions.graphql @@ -0,0 +1,8 @@ +query gqlPermissions($permissions: [String]!) { + whoAmI { + permissions: globalPermissionsByName(permissions: $permissions) { + name + result + } + } +} diff --git a/aleksis/core/frontend/components/app/whoAmI.graphql b/aleksis/core/frontend/components/app/whoAmI.graphql index 0b2877bd2cf15b5134c8e70978fb6b2218414e3a..57e0292d37ea4d221c9f263621647bfdabe38b6f 100644 --- a/aleksis/core/frontend/components/app/whoAmI.graphql +++ b/aleksis/core/frontend/components/app/whoAmI.graphql @@ -1,4 +1,4 @@ -query ($permissions: [String]!) { +query whoAmI { whoAmI { username isAuthenticated @@ -12,9 +12,5 @@ query ($permissions: [String]!) { avatarUrl isDummy } - permissions: globalPermissionsByName(permissions: $permissions) { - name - result - } } } diff --git a/aleksis/core/frontend/index.js b/aleksis/core/frontend/index.js index f59aa8578b59addcb420d6165c6ef1672c669c30..d82922996539f353ec2aa9a7ecb4faaf68d08322 100644 --- a/aleksis/core/frontend/index.js +++ b/aleksis/core/frontend/index.js @@ -70,6 +70,7 @@ const app = new Vue({ backgroundActive: true, invalidation: false, snackbarItems: [], + permissions: [], }), computed: { matchedComponents() { diff --git a/aleksis/core/frontend/mixins/menus.js b/aleksis/core/frontend/mixins/menus.js index 9ba58bcaa84e72917e3057614fca6058df39af3a..7b6317a5aa3f625501bd51119d0fc4c6f633b379 100644 --- a/aleksis/core/frontend/mixins/menus.js +++ b/aleksis/core/frontend/mixins/menus.js @@ -1,15 +1,17 @@ import gqlCustomMenu from "../components/app/customMenu.graphql"; +import permissionsMixin from "./permissions.js"; + /** * Vue mixin containing menu generation code. * * Only used by main App component, but factored out for readability. */ const menusMixin = { + mixins: [permissionsMixin], data() { return { footerMenu: null, - permissionNames: [], sideNavMenu: null, accountMenu: null, }; @@ -35,8 +37,7 @@ const menusMixin = { } } - this.permissionNames = permArray; - this.$apollo.queries.whoAmI.refetch(); + this.fetchPermissions(permArray); }, buildMenu(routes, menuKey) { let menu = {}; @@ -99,14 +100,6 @@ const menusMixin = { return Object.values(menu); }, - checkPermission(permissionName) { - return ( - this.whoAmI && - this.whoAmI.permissions && - this.whoAmI.permissions.find((p) => p.name === permissionName) && - this.whoAmI.permissions.find((p) => p.name === permissionName).result - ); - }, checkValidators(validators) { for (const validator of validators) { if (!validator(this.whoAmI)) { @@ -118,14 +111,9 @@ const menusMixin = { buildMenus() { this.accountMenu = this.buildMenu( this.$router.getRoutes(), - "inAccountMenu", - this.whoAmI ? this.whoAmI.permissions : [] - ); - this.sideNavMenu = this.buildMenu( - this.$router.getRoutes(), - "inMenu", - this.whoAmI ? this.whoAmI.permissions : [] + "inAccountMenu" ); + this.sideNavMenu = this.buildMenu(this.$router.getRoutes(), "inMenu"); }, }, apollo: { diff --git a/aleksis/core/frontend/mixins/permissions.js b/aleksis/core/frontend/mixins/permissions.js new file mode 100644 index 0000000000000000000000000000000000000000..55bc94f30a39e6712a6e74863b045707c3ae3bba --- /dev/null +++ b/aleksis/core/frontend/mixins/permissions.js @@ -0,0 +1,55 @@ +import gqlPermissions from "../components/app/permissions.graphql"; + +/** + * Vue mixin containing permission checking code. + */ + +const permissionsMixin = { + apollo: { + permissions: { + query: gqlPermissions, + update(data) { + this.$root.permissions = data.whoAmI.permissions; + }, + variables: { + permissions: [], + }, + }, + }, + methods: { + checkPermission(permissionName) { + return ( + this.$root.permissions && + this.$root.permissions.find((p) => p.name === permissionName) && + this.$root.permissions.find((p) => p.name === permissionName).result + ); + }, + fetchPermissions(permissionNames) { + this.$apollo.queries.permissions.fetchMore({ + variables: { + permissions: permissionNames, + }, + updateQuery: (previousResult, { fetchMoreResult }) => { + const oldPermissions = previousResult.whoAmI.permissions; + const newPermissions = fetchMoreResult.whoAmI.permissions; + + const keepPermissions = oldPermissions.filter( + (oldPermission) => + !newPermissions.find( + (newPermission) => newPermission.name === oldPermission.name + ) + ); + + return { + whoAmI: { + __typename: previousResult.whoAmI.__typename, + permissions: [...keepPermissions, ...newPermissions], + }, + }; + }, + }); + }, + }, +}; + +export default permissionsMixin;