Browse Source

Feature: Mobile - Add query for product version.

Florian Liebe 2 years ago
parent
commit
1c3781d48b

+ 20 - 4
app/frontend/apps/mobile/pages/account/views/AccountOverview.vue

@@ -4,11 +4,13 @@
 import { computed, ref } from 'vue'
 import { useRouter } from 'vue-router'
 import { storeToRefs } from 'pinia'
-import { MutationHandler } from '@shared/server/apollo/handler'
+import { MutationHandler, QueryHandler } from '@shared/server/apollo/handler'
 import { useSessionStore } from '@shared/stores/session'
 import { useLocaleStore } from '@shared/stores/locale'
 import FormGroup from '@shared/components/Form/FormGroup.vue'
 import CommonUserAvatar from '@shared/components/CommonUserAvatar/CommonUserAvatar.vue'
+import type { ProductAboutQuery } from '@shared/graphql/types'
+import { useProductAboutQuery } from '@shared/graphql/queries/about.api'
 import CommonSectionMenu from '@mobile/components/CommonSectionMenu/CommonSectionMenu.vue'
 import CommonSectionMenuLink from '@mobile/components/CommonSectionMenu/CommonSectionMenuLink.vue'
 import { useAccountLocaleMutation } from '../graphql/mutations/locale.api'
@@ -19,7 +21,8 @@ const logout = () => {
   router.push('/logout')
 }
 
-const { user } = storeToRefs(useSessionStore())
+const session = useSessionStore()
+const { user } = storeToRefs(session)
 
 const localeStore = useLocaleStore()
 const savingLocale = ref(false)
@@ -55,6 +58,19 @@ const currentLocale = computed({
     })
   },
 })
+
+const productAbout = ref<ProductAboutQuery['productAbout']>()
+const versionPermission = session.hasPermission('admin.version')
+
+if (versionPermission) {
+  const productAboutQuery = new QueryHandler(useProductAboutQuery(), {
+    errorNotificationMessage: __('The product version could not be fetched.'),
+  })
+
+  productAboutQuery.watchOnResult((data) => {
+    productAbout.value = data?.productAbout
+  })
+}
 </script>
 
 <template>
@@ -102,11 +118,11 @@ const currentLocale = computed({
       </template>
     </FormGroup>
 
-    <CommonSectionMenu>
+    <CommonSectionMenu v-if="versionPermission">
       <CommonSectionMenuLink
         :icon="{ name: 'info', size: 'base' }"
+        :information="productAbout"
         icon-bg="bg-gray"
-        information="v 1.1"
       >
         {{ $t('About') }}
       </CommonSectionMenuLink>

+ 19 - 0
app/frontend/shared/graphql/queries/about.api.ts

@@ -0,0 +1,19 @@
+import * as Types from '../types';
+
+import gql from 'graphql-tag';
+import * as VueApolloComposable from '@vue/apollo-composable';
+import * as VueCompositionApi from 'vue';
+export type ReactiveFunction<TParam> = () => TParam;
+
+export const ProductAboutDocument = gql`
+    query productAbout {
+  productAbout
+}
+    `;
+export function useProductAboutQuery(options: VueApolloComposable.UseQueryOptions<Types.ProductAboutQuery, Types.ProductAboutQueryVariables> | VueCompositionApi.Ref<VueApolloComposable.UseQueryOptions<Types.ProductAboutQuery, Types.ProductAboutQueryVariables>> | ReactiveFunction<VueApolloComposable.UseQueryOptions<Types.ProductAboutQuery, Types.ProductAboutQueryVariables>> = {}) {
+  return VueApolloComposable.useQuery<Types.ProductAboutQuery, Types.ProductAboutQueryVariables>(ProductAboutDocument, {}, options);
+}
+export function useProductAboutLazyQuery(options: VueApolloComposable.UseQueryOptions<Types.ProductAboutQuery, Types.ProductAboutQueryVariables> | VueCompositionApi.Ref<VueApolloComposable.UseQueryOptions<Types.ProductAboutQuery, Types.ProductAboutQueryVariables>> | ReactiveFunction<VueApolloComposable.UseQueryOptions<Types.ProductAboutQuery, Types.ProductAboutQueryVariables>> = {}) {
+  return VueApolloComposable.useLazyQuery<Types.ProductAboutQuery, Types.ProductAboutQueryVariables>(ProductAboutDocument, {}, options);
+}
+export type ProductAboutQueryCompositionFunctionResult = VueApolloComposable.UseQueryReturn<Types.ProductAboutQuery, Types.ProductAboutQueryVariables>;

+ 3 - 0
app/frontend/shared/graphql/queries/about.graphql

@@ -0,0 +1,3 @@
+query productAbout {
+  productAbout
+}

+ 7 - 0
app/frontend/shared/graphql/types.ts

@@ -636,6 +636,8 @@ export type Queries = {
   objectManagerFrontendAttributes?: Maybe<ObjectManagerFrontendAttributesPayload>;
   /** Fetch an organization by ID */
   organization: Organization;
+  /** Fetch the version of Zammad */
+  productAbout: Scalars['String'];
   /** Generic object search */
   search: Array<SearchResult>;
   /** The sessionId of the currently authenticated user. */
@@ -1390,6 +1392,11 @@ export type LogoutMutationVariables = Exact<{ [key: string]: never; }>;
 
 export type LogoutMutation = { __typename?: 'Mutations', logout?: { __typename?: 'LogoutPayload', success: boolean } | null };
 
+export type ProductAboutQueryVariables = Exact<{ [key: string]: never; }>;
+
+
+export type ProductAboutQuery = { __typename?: 'Queries', productAbout: string };
+
 export type ApplicationBuildChecksumQueryVariables = Exact<{ [key: string]: never; }>;
 
 

+ 17 - 0
app/graphql/gql/queries/product/about.rb

@@ -0,0 +1,17 @@
+# Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
+
+module Gql::Queries
+  class Product::About < BaseQuery
+    description 'Fetch the version of Zammad'
+
+    type String, null: false
+
+    def self.authorize(_obj, ctx)
+      VersionPolicy.new(ctx.current_user, nil).show?
+    end
+
+    def resolve(...)
+      Version.get
+    end
+  end
+end

+ 7 - 0
app/policies/version_policy.rb

@@ -0,0 +1,7 @@
+# Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
+
+class VersionPolicy < ApplicationPolicy
+  def show?
+    user.permissions?('admin.version')
+  end
+end

+ 4 - 0
i18n/zammad.pot

@@ -9716,6 +9716,10 @@ msgstr ""
 msgid "The preview cannot be generated. The format is corrupted or not supported."
 msgstr ""
 
+#: app/frontend/apps/mobile/pages/account/views/AccountOverview.vue
+msgid "The product version could not be fetched."
+msgstr ""
+
 #: app/controllers/import_freshdesk_controller.rb
 #: app/controllers/import_kayako_controller.rb
 #: app/controllers/import_otrs_controller.rb

+ 37 - 0
spec/graphql/gql/queries/product/about_spec.rb

@@ -0,0 +1,37 @@
+# Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
+
+require 'rails_helper'
+
+RSpec.describe Gql::Queries::Product::About, type: :graphql do
+  context 'when fetching product about' do
+    let(:query) do
+      <<~QUERY
+        query productAbout {
+          productAbout
+        }
+      QUERY
+    end
+
+    context 'when authorized', authenticated_as: :admin do
+      let(:admin) { create(:admin) }
+
+      before do
+        gql.execute(query)
+      end
+
+      it 'returns data' do
+        expect(gql.result.data).to eq(Version.get)
+      end
+    end
+
+    context 'when not authorized', authenticated_as: :agent do
+      let(:agent) { create(:agent) }
+
+      before do
+        gql.execute(query)
+      end
+
+      it_behaves_like 'graphql responds with error if unauthenticated'
+    end
+  end
+end

+ 25 - 0
spec/policies/version_policy_spec.rb

@@ -0,0 +1,25 @@
+# Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
+
+require 'rails_helper'
+
+describe VersionPolicy do
+  subject(:version_policy) { described_class.new(user, nil) }
+
+  let(:user) { create(:user, roles: [role]) }
+
+  context 'with "admin.version" privileges' do
+    let(:role) do
+      create(:role).tap { |role| role.permission_grant('admin') }
+    end
+
+    it { is_expected.to permit_actions(%i[show]) }
+  end
+
+  context 'without "admin.version" privileges' do
+    let(:role) do
+      create(:role).tap { |role| role.permission_grant('ticket.agent') }
+    end
+
+    it { is_expected.to forbid_actions(%i[show]) }
+  end
+end

+ 21 - 4
spec/system/apps/mobile/account_spec.rb

@@ -3,14 +3,15 @@
 require 'rails_helper'
 
 RSpec.describe 'Mobile > App Account Page', type: :system, app: :mobile do
-  context 'when on account page', authenticated_as: :admin do
+  context 'when on account page' do
     let(:admin) { create(:admin) }
+    let(:agent) { create(:agent) }
 
     before do
       visit '/account'
     end
 
-    context 'when updating locale' do
+    context 'when updating locale', authenticated_as: :agent do
       it 'check that user can see and change locale' do
         # current locale is visible
         expect(page).to have_content('English')
@@ -18,8 +19,24 @@ RSpec.describe 'Mobile > App Account Page', type: :system, app: :mobile do
         click('output', text: %r{English}i)
         click('span', text: %r{Dansk}i)
         wait_for_gql('apps/mobile/pages/account/graphql/mutations/locale.graphql')
-        admin.reload
-        expect(admin.preferences[:locale]).to eq('da')
+        agent.reload
+        expect(agent.preferences[:locale]).to eq('da')
+      end
+    end
+
+    context 'when checking about information' do
+      context 'when permitted', authenticated_as: :admin do
+        it 'shows about information' do
+          wait_for_gql('shared/graphql/queries/about.graphql')
+
+          expect(page).to have_content(Version.get)
+        end
+      end
+
+      context 'when forbidden', authenticated_as: :agent do
+        it 'does not show about information' do
+          expect(page).to have_no_content(Version.get)
+        end
       end
     end
   end