You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ro...@apache.org on 2020/07/07 07:09:14 UTC

[cloudstack-primate] branch master updated: image: Fixing permission issues (#472)

This is an automated email from the ASF dual-hosted git repository.

rohit pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cloudstack-primate.git


The following commit(s) were added to refs/heads/master by this push:
     new 8b20a95  image: Fixing permission issues (#472)
8b20a95 is described below

commit 8b20a9599cc4b6ed7e7d78a36b0c846131c2cba7
Author: davidjumani <dj...@gmail.com>
AuthorDate: Tue Jul 7 12:39:07 2020 +0530

    image: Fixing permission issues (#472)
    
    Fixes #463
    
    Co-authored-by: Rohit Yadav <ro...@shapeblue.com>
    Co-authored-by: Pearl Dsilva <pe...@shapeblue.com>
---
 src/components/view/DetailSettings.vue | 10 ++++--
 src/config/section/image.js            | 65 ++++++++++++++++++++++++++++++----
 src/views/compute/CreateSSHKeyPair.vue | 35 +++++++++++++-----
 src/views/image/IsoZones.vue           | 17 ++++++---
 src/views/image/TemplateZones.vue      | 16 ++++++---
 src/views/network/VpcTiersTab.vue      |  4 ++-
 6 files changed, 120 insertions(+), 27 deletions(-)

diff --git a/src/components/view/DetailSettings.vue b/src/components/view/DetailSettings.vue
index e97ca6c..bb3945a 100644
--- a/src/components/view/DetailSettings.vue
+++ b/src/components/view/DetailSettings.vue
@@ -27,7 +27,7 @@
           type="dashed"
           style="width: 100%"
           icon="plus"
-          :disabled="!('updateTemplate' in $store.getters.apis && 'updateVirtualMachine' in $store.getters.apis)"
+          :disabled="!('updateTemplate' in $store.getters.apis && 'updateVirtualMachine' in $store.getters.apis && isAdminOrOwner())"
           @click="showAddDetail = true">
           {{ $t('label.add.setting') }}
         </a-button>
@@ -69,7 +69,7 @@
             <span v-else>{{ item.value }}</span>
           </span>
         </a-list-item-meta>
-        <div slot="actions" v-if="!disableSettings && 'updateTemplate' in $store.getters.apis && 'updateVirtualMachine' in $store.getters.apis">
+        <div slot="actions" v-if="!disableSettings && 'updateTemplate' in $store.getters.apis && 'updateVirtualMachine' in $store.getters.apis && isAdminOrOwner()">
           <a-button shape="circle" size="default" @click="updateDetail(index)" v-if="item.edit">
             <a-icon type="check-circle" theme="twoTone" twoToneColor="#52c41a" />
           </a-button>
@@ -82,7 +82,7 @@
             v-if="!item.edit"
             @click="showEditDetail(index)" />
         </div>
-        <div slot="actions" v-if="!disableSettings && 'updateTemplate' in $store.getters.apis && 'updateVirtualMachine' in $store.getters.apis">
+        <div slot="actions" v-if="!disableSettings && 'updateTemplate' in $store.getters.apis && 'updateVirtualMachine' in $store.getters.apis && isAdminOrOwner()">
           <a-popconfirm
             title="Delete setting?"
             @confirm="deleteDetail(index)"
@@ -169,6 +169,10 @@ export default {
     onAddInputChange (val, obj) {
       this[obj] = val
     },
+    isAdminOrOwner () {
+      return ['Admin'].includes(this.$store.getters.userInfo.roletype) ||
+        (this.resource.domainid === this.$store.getters.userInfo.domainid && this.resource.account === this.$store.getters.userInfo.account)
+    },
     runApi () {
       var apiName = ''
       if (this.resourceType === 'UserVm') {
diff --git a/src/config/section/image.js b/src/config/section/image.js
index e489e95..7703d78 100644
--- a/src/config/section/image.js
+++ b/src/config/section/image.js
@@ -83,14 +83,32 @@ export default {
           icon: 'edit',
           label: 'label.edit',
           dataView: true,
-          args: ['name', 'displaytext', 'passwordenabled', 'sshkeyenabled', 'ostypeid', 'isdynamicallyscalable']
+          show: (record, store) => {
+            return (['Admin'].includes(store.userInfo.roletype) ||
+              (record.domainid === store.userInfo.domainid && record.account === store.userInfo.account)) &&
+              record.templatetype !== 'SYSTEM' &&
+              record.isready
+          },
+          args: (record, store) => {
+            var fields = ['name', 'displaytext', 'passwordenabled', 'sshkeyenabled', 'ostypeid', 'isdynamicallyscalable']
+            if (['Admin'].includes(store.userInfo.roletype)) {
+              fields.push('isrouting')
+            }
+            return fields
+          }
         },
         {
           api: 'updateTemplatePermissions',
           icon: 'share-alt',
           label: 'label.action.template.share',
           dataView: true,
-          args: ['ispublic', 'isfeatured', 'isextractable']
+          args: ['ispublic', 'isfeatured', 'isextractable'],
+          show: (record, store) => {
+            return (['Admin'].includes(store.userInfo.roletype) ||
+              (record.domainid === store.userInfo.domainid && record.account === store.userInfo.account)) &&
+              record.templatetype !== 'SYSTEM' &&
+              record.isready
+          }
         },
         {
           api: 'extractTemplate',
@@ -99,7 +117,13 @@ export default {
           message: 'message.action.download.template',
           docHelp: 'adminguide/templates.html#exporting-templates',
           dataView: true,
-          show: (record) => { return record && record.isextractable },
+          show: (record, store) => {
+            return (['Admin'].includes(store.userInfo.roletype) ||
+              (record.domainid === store.userInfo.domainid && record.account === store.userInfo.account)) &&
+              record.templatetype !== 'SYSTEM' &&
+              record.isready &&
+              record.isextractable
+          },
           args: ['zoneid', 'mode'],
           mapping: {
             zoneid: {
@@ -118,7 +142,12 @@ export default {
           docHelp: 'adminguide/templates.html#sharing-templates-with-other-accounts-projects',
           dataView: true,
           popup: true,
-          show: (record, store) => { return (['Admin', 'DomainAdmin'].includes(store.userInfo.roletype) && (record.domainid === store.userInfo.domainid && record.account === store.userInfo.account) || record.templatetype !== 'BUILTIN') },
+          show: (record, store) => {
+            return (['Admin'].includes(store.userInfo.roletype) ||
+              (record.domainid === store.userInfo.domainid && record.account === store.userInfo.account)) &&
+              record.templatetype !== 'SYSTEM' &&
+              record.isready
+          },
           component: () => import('@/views/image/UpdateTemplateIsoPermissions')
         }
       ]
@@ -177,6 +206,12 @@ export default {
           icon: 'edit',
           label: 'label.action.edit.iso',
           dataView: true,
+          show: (record, store) => {
+            return (['Admin'].includes(store.userInfo.roletype) ||
+              (record.domainid === store.userInfo.domainid && record.account === store.userInfo.account)) &&
+              !(record.account === 'SYSTEM' && record.domainid === 1) &&
+              record.isready
+          },
           args: ['name', 'displaytext', 'bootable', 'ostypeid']
         },
         {
@@ -184,7 +219,13 @@ export default {
           icon: 'share-alt',
           label: 'label.action.iso.share',
           dataView: true,
-          args: ['ispublic', 'isfeatured', 'isextractable']
+          args: ['ispublic', 'isfeatured', 'isextractable'],
+          show: (record, store) => {
+            return (['Admin'].includes(store.userInfo.roletype) ||
+              (record.domainid === store.userInfo.domainid && record.account === store.userInfo.account)) &&
+              !(record.account === 'SYSTEM' && record.domainid === 1) &&
+              record.isready
+          }
         },
         {
           api: 'extractIso',
@@ -193,7 +234,12 @@ export default {
           message: 'message.action.download.iso',
           docHelp: 'adminguide/templates.html#exporting-templates',
           dataView: true,
-          show: (record) => { return record && record.isextractable },
+          show: (record, store) => {
+            return (['Admin'].includes(store.userInfo.roletype) ||
+              (record.domainid === store.userInfo.domainid && record.account === store.userInfo.account)) &&
+              !(record.account === 'SYSTEM' && record.domainid === 1) &&
+              record.isready
+          },
           args: ['zoneid', 'mode'],
           mapping: {
             zoneid: {
@@ -213,7 +259,12 @@ export default {
           dataView: true,
           args: ['op', 'accounts', 'projectids'],
           popup: true,
-          show: (record, store) => { return (['Admin', 'DomainAdmin'].includes(store.userInfo.roletype) && (record.domainid === store.userInfo.domainid && record.account === store.userInfo.account) || record.templatetype !== 'BUILTIN') },
+          show: (record, store) => {
+            return (['Admin'].includes(store.userInfo.roletype) ||
+              (record.domainid === store.userInfo.domainid && record.account === store.userInfo.account)) &&
+              !(record.account === 'SYSTEM' && record.domainid === 1) &&
+              record.isready
+          },
           component: () => import('@/views/image/UpdateTemplateIsoPermissions')
         }
       ]
diff --git a/src/views/compute/CreateSSHKeyPair.vue b/src/views/compute/CreateSSHKeyPair.vue
index 2800d9d..a3aa8e2 100644
--- a/src/views/compute/CreateSSHKeyPair.vue
+++ b/src/views/compute/CreateSSHKeyPair.vue
@@ -17,7 +17,7 @@
 
 <template>
   <div class="form-layout">
-    <a-spin :spinning="loading">
+    <a-spin :spinning="loading" v-if="!isSubmitted">
       <p v-html="$t('message.desc.create.ssh.key.pair')"></p>
       <a-form
         :form="form"
@@ -64,6 +64,14 @@
         </div>
       </a-form>
     </a-spin>
+    <div v-if="isSubmitted">
+      <p v-html="$t('message.desc.created.ssh.key.pair')"></p>
+      <div :span="24" class="action-button">
+        <a-button @click="notifyCopied" v-clipboard:copy="hiddenElement.innerHTML" type="primary">{{ 'Copy to clipboard' }}</a-button>
+        <a-button @click="downloadKey" type="primary">{{ this.$t('Download') }}</a-button>
+        <a-button @click="closeAction">{{ this.$t('label.close') }}</a-button>
+      </div>
+    </div>
   </div>
 </template>
 
@@ -78,7 +86,9 @@ export default {
       domains: [],
       domainLoading: false,
       selectedDomain: {},
-      loading: false
+      loading: false,
+      isSubmitted: false,
+      hiddenElement: null
     }
   },
   beforeCreate () {
@@ -176,22 +186,31 @@ export default {
           api('createSSHKeyPair', params).then(json => {
             this.$message.success('Successfully created SSH key pair: ' + values.name)
             if (json.createsshkeypairresponse && json.createsshkeypairresponse.keypair && json.createsshkeypairresponse.keypair.privatekey) {
-              this.$notification.info({
-                message: this.$t('label.create.ssh.key.pair'),
-                description: (<span domPropsInnerHTML={'<strong>' + values.name + '</strong><br/><pre>' + json.createsshkeypairresponse.keypair.privatekey + '</pre>'}></span>),
-                duration: 0
-              })
+              this.isSubmitted = true
+              const key = json.createsshkeypairresponse.keypair.privatekey
+              this.hiddenElement = document.createElement('a')
+              this.hiddenElement.href = 'data:text/plain;charset=utf-8,' + encodeURI(key)
+              this.hiddenElement.innerHTML = key
+              this.hiddenElement.target = '_blank'
+              this.hiddenElement.download = values.name + '.key'
             }
           }).catch(error => {
             this.$notifyError(error)
           }).finally(() => {
             this.$emit('refresh-data')
             this.loading = false
-            this.closeAction()
           })
         }
       })
     },
+    downloadKey () {
+      this.hiddenElement.click()
+    },
+    notifyCopied () {
+      this.$notification.info({
+        message: this.$t('Copied Successfully to cilpboard')
+      })
+    },
     closeAction () {
       this.$emit('close-action')
     }
diff --git a/src/views/image/IsoZones.vue b/src/views/image/IsoZones.vue
index f23dacf..f76c034 100644
--- a/src/views/image/IsoZones.vue
+++ b/src/views/image/IsoZones.vue
@@ -166,15 +166,18 @@ export default {
         title: this.$t('label.isready'),
         dataIndex: 'isready',
         scopedSlots: { customRender: 'isready' }
-      },
-      {
+      }
+    ]
+    if (this.isActionPermitted()) {
+      this.columns.push({
         title: '',
         dataIndex: 'action',
         fixed: 'right',
         width: 100,
         scopedSlots: { customRender: 'action' }
-      }
-    ]
+      })
+    }
+
     const userInfo = this.$store.getters.userInfo
     if (!['Admin'].includes(userInfo.roletype) &&
       (userInfo.account !== this.resource.account || userInfo.domain !== this.resource.domain)) {
@@ -222,6 +225,12 @@ export default {
       this.pageSize = pageSize
       this.fetchData()
     },
+    isActionPermitted () {
+      return (['Admin'].includes(this.$store.getters.userInfo.roletype) ||
+        (this.resource.domainid === this.$store.getters.userInfo.domainid && this.resource.account === this.$store.getters.userInfo.account)) &&
+        !(this.resource.account !== 'SYSTEM' && this.resource.domainid === 1) &&
+        this.resource.isready
+    },
     deleteIso (record) {
       const params = {
         id: record.id,
diff --git a/src/views/image/TemplateZones.vue b/src/views/image/TemplateZones.vue
index 3b020c8..d9f1e1c 100644
--- a/src/views/image/TemplateZones.vue
+++ b/src/views/image/TemplateZones.vue
@@ -176,15 +176,18 @@ export default {
         title: this.$t('label.isready'),
         dataIndex: 'isready',
         scopedSlots: { customRender: 'isready' }
-      },
-      {
+      }
+    ]
+    if (this.isActionPermitted()) {
+      this.columns.push({
         title: '',
         dataIndex: 'action',
         fixed: 'right',
         width: 100,
         scopedSlots: { customRender: 'action' }
-      }
-    ]
+      })
+    }
+
     const userInfo = this.$store.getters.userInfo
     if (!['Admin'].includes(userInfo.roletype) &&
       (userInfo.account !== this.resource.account || userInfo.domain !== this.resource.domain)) {
@@ -232,6 +235,11 @@ export default {
       this.pageSize = pageSize
       this.fetchData()
     },
+    isActionPermitted () {
+      return (['Admin'].includes(this.$store.getters.userInfo.roletype) ||
+        (this.resource.domainid === this.$store.getters.userInfo.domainid && this.resource.account === this.$store.getters.userInfo.account)) &&
+        this.resource.isready && this.resource.templatetype !== 'SYSTEM'
+    },
     deleteTemplate () {
       const params = {
         id: this.currentRecord.id,
diff --git a/src/views/network/VpcTiersTab.vue b/src/views/network/VpcTiersTab.vue
index b4be7a6..7ff67b6 100644
--- a/src/views/network/VpcTiersTab.vue
+++ b/src/views/network/VpcTiersTab.vue
@@ -251,6 +251,7 @@ export default {
       default: false
     }
   },
+  inject: ['parentFetchData'],
   data () {
     return {
       networks: [],
@@ -487,11 +488,12 @@ export default {
           this.$notification.success({
             message: 'Successfully added VPC Network'
           })
-          this.fetchData()
         }).catch(error => {
           this.$notifyError(error)
         }).finally(() => {
+          this.parentFetchData()
           this.fetchData()
+          this.fetchLoading = false
         })
       })
     },