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/05/05 09:57:38 UTC

[cloudstack-primate] branch master updated: iam: user change password action form (#264)

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 f52c7e2  iam: user change password action form (#264)
f52c7e2 is described below

commit f52c7e203363afeba1300443dc6494ee69b1f808
Author: Abhishek Kumar <ab...@gmail.com>
AuthorDate: Tue May 5 15:27:27 2020 +0530

    iam: user change password action form (#264)
    
    Fixes #177
    
    Signed-off-by: Abhishek Kumar <ab...@gmail.com>
    Co-authored-by: Rohit Yadav <ro...@shapeblue.com>
---
 src/config/section/iam.js            |  13 +--
 src/locales/en.json                  |   4 +-
 src/views/iam/ChangeUserPassword.vue | 183 +++++++++++++++++++++++++++++++++++
 3 files changed, 193 insertions(+), 7 deletions(-)

diff --git a/src/config/section/iam.js b/src/config/section/iam.js
index f91789a..b473d0c 100644
--- a/src/config/section/iam.js
+++ b/src/config/section/iam.js
@@ -46,34 +46,35 @@ export default {
         {
           api: 'updateUser',
           icon: 'key',
-          label: 'Change Password',
+          label: 'label.action.change.password',
           dataView: true,
-          args: ['currentpassword', 'password']
+          popup: true,
+          component: () => import('@/views/iam/ChangeUserPassword.vue')
         },
         {
           api: 'registerUserKeys',
           icon: 'file-protect',
-          label: 'Generate Keys',
+          label: 'label.action.generate.keys',
           dataView: true
         },
         {
           api: 'enableUser',
           icon: 'play-circle',
-          label: 'Enable User',
+          label: 'label.action.enable.user',
           dataView: true,
           show: (record) => { return record.state === 'disabled' }
         },
         {
           api: 'disableUser',
           icon: 'pause-circle',
-          label: 'Disable User',
+          label: 'label.action.disable.user',
           dataView: true,
           show: (record) => { return record.state === 'enabled' }
         },
         {
           api: 'deleteUser',
           icon: 'delete',
-          label: 'Delete user',
+          label: 'label.action.delete.user',
           dataView: true
         }
       ]
diff --git a/src/locales/en.json b/src/locales/en.json
index 7174a08..86d80d7 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -127,6 +127,7 @@
 "clusternamelabel": "Cluster Name",
 "clusters": "Clusters",
 "clustertype": "Cluster Type",
+"confirmpassword": "Confirm Password",
 "connectiontimeout": "Connection Timeout",
 "conservemode": "Conserve mode",
 "counterid": "Counter",
@@ -149,6 +150,7 @@
 "credit": "Credit",
 "crossZones": "Cross Zones",
 "current": "isCurrent",
+"currentpassword": "Current Password",
 "date": "Date",
 "dedicated": "Dedicated",
 "default": "Default",
@@ -744,6 +746,7 @@
 "message.network.removeNIC": "Please confirm that want to remove this NIC, which will also remove the associated network from the VM.",
 "message.network.secondaryIP" : "Please confirm that you would like to acquire a new secondary IP for this NIC. \n NOTE: You need to manually configure the newly-acquired secondary IP inside the virtual machine.",
 "message.network.updateIp": "Please confirm that you would like to change the IP address for this NIC on VM.",
+"message.validate.equalto": "Please enter the same value again.",
 "message.desc.create.ssh.key.pair": "Please fill in the following data to create or register a ssh key pair.<br><br>(1) If public key is set, CloudStack will register the public key. You can use it through your private key.<br><br>(2) If public key is not set, CloudStack will create a new SSH Key pair. In this case, please copy and save the private key. CloudStack will not keep it.<br>",
 "mincpunumber": "Min CPU Cores",
 "minInstance": "Min Instances",
@@ -1111,7 +1114,6 @@
 "sshKeyPairs": "SSH keypairs",
 "wednesday": "Wednesday",
 "noselect": "No thanks",
-"group": "Group",
 "keyboard": "Keyboard language",
 "userdata": "Userdata",
 "label.back": "Back",
diff --git a/src/views/iam/ChangeUserPassword.vue b/src/views/iam/ChangeUserPassword.vue
new file mode 100644
index 0000000..927312c
--- /dev/null
+++ b/src/views/iam/ChangeUserPassword.vue
@@ -0,0 +1,183 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+<template>
+  <div class="form-layout">
+    <a-spin :spinning="loading">
+      <a-form
+        :form="form"
+        @submit="handleSubmit"
+        layout="vertical">
+        <a-form-item v-if="!this.isAdminOrDomainAdmin()">
+          <span slot="label">
+            {{ $t('currentpassword') }}
+            <a-tooltip :title="apiParams.currentpassword.description">
+              <a-icon type="info-circle" style="color: rgba(0,0,0,.45)" />
+            </a-tooltip>
+          </span>
+          <a-input-password
+            v-decorator="['currentpassword', {
+              rules: [{ required: true, message: 'Please enter current password' }]
+            }]"
+            :placeholder="apiParams.currentpassword.description"/>
+        </a-form-item>
+        <a-form-item>
+          <span slot="label">
+            {{ $t('password') }}
+            <a-tooltip :title="apiParams.password.description">
+              <a-icon type="info-circle" style="color: rgba(0,0,0,.45)" />
+            </a-tooltip>
+          </span>
+          <a-input-password
+            v-decorator="['password', {
+              rules: [{ required: true, message: 'Please enter new password' }]
+            }]"
+            :placeholder="apiParams.password.description"/>
+        </a-form-item>
+        <a-form-item>
+          <span slot="label">
+            {{ $t('confirmpassword') }}
+            <a-tooltip :title="apiParams.password.description">
+              <a-icon type="info-circle" style="color: rgba(0,0,0,.45)" />
+            </a-tooltip>
+          </span>
+          <a-input-password
+            v-decorator="['confirmpassword', {
+              rules: [
+                {
+                  required: true,
+                  message: 'Please confirm new password'
+                },
+                {
+                  validator: validateTwoPassword
+                }
+              ]
+            }]"
+            :placeholder="apiParams.password.description"/>
+        </a-form-item>
+
+        <div :span="24" class="action-button">
+          <a-button @click="closeAction">{{ this.$t('Cancel') }}</a-button>
+          <a-button :loading="loading" type="primary" @click="handleSubmit">{{ this.$t('OK') }}</a-button>
+        </div>
+      </a-form>
+    </a-spin>
+  </div>
+</template>
+
+<script>
+import { api } from '@/api'
+
+export default {
+  name: 'ChangeUserPassword',
+  props: {
+    resource: {
+      type: Object,
+      required: true
+    }
+  },
+  data () {
+    return {
+      loading: false
+    }
+  },
+  beforeCreate () {
+    this.form = this.$form.createForm(this)
+    this.apiParams = {}
+    this.apiConfig = this.$store.getters.apis.updateUser || {}
+    this.apiConfig.params.forEach(param => {
+      this.apiParams[param.name] = param
+    })
+  },
+  methods: {
+    isAdminOrDomainAdmin () {
+      return ['Admin', 'DomainAdmin'].includes(this.$store.getters.userInfo.roletype)
+    },
+    isValidValueForKey (obj, key) {
+      return key in obj && obj[key] != null
+    },
+    validateTwoPassword (rule, value, callback) {
+      if (!value || value.length === 0) {
+        callback()
+      } else if (rule.field === 'confirmpassword') {
+        const form = this.form
+        const messageConfirm = this.$t('message.validate.equalto')
+        const passwordVal = form.getFieldValue('password')
+        if (passwordVal && passwordVal !== value) {
+          callback(messageConfirm)
+        } else {
+          callback()
+        }
+      } else {
+        callback()
+      }
+    },
+    handleSubmit (e) {
+      e.preventDefault()
+      this.form.validateFields((err, values) => {
+        if (err) {
+          return
+        }
+        this.loading = true
+        const params = {
+          id: this.resource.id,
+          password: values.password
+        }
+        if (this.isValidValueForKey(values, 'currentpassword') && values.currentpassword.length > 0) {
+          params.currentpassword = values.currentpassword
+        }
+        api('updateUser', params).then(json => {
+          this.$notification.success({
+            message: this.$t('label.action.change.password'),
+            description: 'Successfully changed password for user "' + this.resource.username + '"'
+          })
+        }).catch(error => {
+          this.$notification.error({
+            message: 'Error',
+            description: (error.response && error.response.headers && error.response.headers['x-description']) || error.message
+          })
+        }).finally(() => {
+          this.$emit('refresh-data')
+          this.loading = false
+          this.closeAction()
+        })
+      })
+    },
+    closeAction () {
+      this.$emit('close-action')
+    }
+  }
+}
+</script>
+
+<style scoped lang="less">
+  .form-layout {
+    width: 80vw;
+
+    @media (min-width: 600px) {
+      width: 450px;
+    }
+  }
+
+  .action-button {
+    text-align: right;
+
+    button {
+      margin-right: 5px;
+    }
+  }
+</style>