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.davidjumani1...@gmail.com> AuthorDate: Tue Jul 7 12:39:07 2020 +0530 image: Fixing permission issues (#472) Fixes #463 Co-authored-by: Rohit Yadav <rohit.ya...@shapeblue.com> Co-authored-by: Pearl Dsilva <pearl.dsi...@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 }) }) },