Skip to content
This repository has been archived by the owner on Jan 20, 2021. It is now read-only.

Commit

Permalink
projects: Enabling Role based Users in Projects (#382)
Browse files Browse the repository at this point in the history
Enables creating role based users in projects
UI for feature: apache/cloudstack#4128

Also addresses issue: #485

Co-authored-by: Pearl Dsilva <pearl.dsilva@shapeblue.com>
  • Loading branch information
2 people authored and ustcweizhou committed Jan 19, 2021
1 parent ca4219e commit a3aaa92
Show file tree
Hide file tree
Showing 15 changed files with 1,459 additions and 73 deletions.
1 change: 1 addition & 0 deletions src/components/header/ProjectMenu.vue
Expand Up @@ -91,6 +91,7 @@ export default {
},
changeProject (index) {
const project = this.projects[index]
this.$store.dispatch('ProjectView', project.id)
this.$store.dispatch('SetProject', project)
this.$store.dispatch('ToggleTheme', project.id === undefined ? 'light' : 'dark')
this.$message.success(`Switched to "${project.displaytext}"`)
Expand Down
14 changes: 14 additions & 0 deletions src/components/view/DetailsTab.vue
Expand Up @@ -93,6 +93,20 @@ export default {
},
$route () {
this.dedicatedSectionActive = this.dedicatedRoutes.includes(this.$route.meta.name)
this.fetchProjectAdmins()
}
},
methods: {
fetchProjectAdmins () {
if (!this.resource.owner) {
return false
}
var owners = this.resource.owner
var projectAdmins = []
for (var owner of owners) {
projectAdmins.push(Object.keys(owner).includes('user') ? owner.account + '(' + owner.user + ')' : owner.account)
}
this.resource.account = projectAdmins.join()
}
}
}
Expand Down
15 changes: 15 additions & 0 deletions src/components/view/InfoCard.vue
Expand Up @@ -459,6 +459,21 @@
<span v-else>{{ resource.zone || resource.zonename || resource.zoneid }}</span>
</div>
</div>
<div class="resource-detail-item" v-if="resource.owner">
<div class="resource-detail-item__label">{{ $t('label.owners') }}</div>
<div class="resource-detail-item__details">
<a-icon type="user" />
<template v-for="(item,idx) in resource.owner">
<span style="margin-right:5px" :key="idx">
<span v-if="$store.getters.userInfo.roletype !== 'User'">
<router-link v-if="'user' in item" :to="{ path: '/accountuser', query: { username: item.user, domainid: resource.domainid }}">{{ item.account + '(' + item.user + ')' }}</router-link>
<router-link v-else :to="{ path: '/account', query: { name: item.account, domainid: resource.domainid } }">{{ item.account }}</router-link>
</span>
<span v-else>{{ item.user ? item.account + '(' + item.user + ')' : item.account }}</span>
</span>
</template>
</div>
</div>
<div class="resource-detail-item" v-if="resource.account && !resource.account.startsWith('PrjAcct-')">
<div class="resource-detail-item__label">{{ $t('label.account') }}</div>
<div class="resource-detail-item__details">
Expand Down
11 changes: 11 additions & 0 deletions src/components/view/ListView.vue
Expand Up @@ -169,6 +169,17 @@
<router-link :to="{ path: '/pod/' + record.podid }">{{ text }}</router-link>
</a>
<span slot="account" slot-scope="text, record">
<template v-if="record.owner">
<template v-for="(item,idx) in record.owner">
<span style="margin-right:5px" :key="idx">
<span v-if="$store.getters.userInfo.roletype !== 'User'">
<router-link v-if="'user' in item" :to="{ path: '/accountuser', query: { username: item.user, domainid: record.domainid }}">{{ item.account + '(' + item.user + ')' }}</router-link>
<router-link v-else :to="{ path: '/account', query: { name: item.account, domainid: record.domainid } }">{{ item.account }}</router-link>
</span>
<span v-else>{{ item.user ? item.account + '(' + item.user + ')' : item.account }}</span>
</span>
</template>
</template>
<template v-if="text && !text.startsWith('PrjAcct-')">
<router-link
v-if="'quota' in record && $router.resolve(`${$route.path}/${record.account}`) !== '404'"
Expand Down
3 changes: 2 additions & 1 deletion src/components/view/ResourceView.vue
Expand Up @@ -88,7 +88,8 @@ export default {
data () {
return {
activeTab: '',
networkService: null
networkService: null,
projectAccount: null
}
},
watch: {
Expand Down
44 changes: 27 additions & 17 deletions src/config/section/project.js
Expand Up @@ -14,6 +14,7 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
import store from '@/store'

export default {
name: 'project',
Expand All @@ -28,7 +29,20 @@ export default {
tabs: [
{
name: 'details',
component: () => import('@/components/view/DetailsTab.vue')
component: () => import('@/views/project/ProjectDetailsTab.vue')
},
{
name: 'accounts',
component: () => import('@/views/project/AccountsTab.vue'),
show: (record, route, user) => { return ['Admin', 'DomainAdmin'].includes(user.roletype) || record.isCurrentUserProjectAdmin }
},
{
name: 'project.roles',
component: () => import('@/views/project/iam/ProjectRoleTab.vue'),
show: (record, route, user) => {
return (['Admin', 'DomainAdmin'].includes(user.roletype) || record.isCurrentUserProjectAdmin) &&
'listProjectRoles' in store.getters.apis
}
},
{
name: 'resources',
Expand All @@ -38,11 +52,6 @@ export default {
name: 'limits',
show: (record, route, user) => { return ['Admin'].includes(user.roletype) },
component: () => import('@/components/view/ResourceLimitTab.vue')
},
{
name: 'accounts',
show: (record, route, user) => { return record.account === user.account || ['Admin', 'DomainAdmin'].includes(user.roletype) },
component: () => import('@/views/project/AccountsTab.vue')
}
],
actions: [
Expand Down Expand Up @@ -84,7 +93,7 @@ export default {
dataView: true,
args: ['displaytext'],
show: (record, store) => {
return record.account === store.userInfo.account || ['Admin', 'DomainAdmin'].includes(store.userInfo.roletype)
return (['Admin', 'DomainAdmin'].includes(store.userInfo.roletype)) || record.isCurrentUserProjectAdmin
}
},
{
Expand All @@ -94,7 +103,7 @@ export default {
message: 'message.activate.project',
dataView: true,
show: (record, store) => {
return (record.account === store.userInfo.account || ['Admin', 'DomainAdmin'].includes(store.userInfo.roletype)) && record.state === 'Suspended'
return ((['Admin', 'DomainAdmin'].includes(store.userInfo.roletype)) || record.isCurrentUserProjectAdmin) && record.state === 'Suspended'
}
},
{
Expand All @@ -105,7 +114,8 @@ export default {
docHelp: 'adminguide/projects.html#sending-project-membership-invitations',
dataView: true,
show: (record, store) => {
return (record.account === store.userInfo.account || ['Admin', 'DomainAdmin'].includes(store.userInfo.roletype)) && record.state !== 'Suspended'
return ((['Admin', 'DomainAdmin'].includes(store.userInfo.roletype)) ||
record.isCurrentUserProjectAdmin) && record.state !== 'Suspended'
}
},
{
Expand All @@ -114,13 +124,11 @@ export default {
label: 'label.action.project.add.account',
docHelp: 'adminguide/projects.html#adding-project-members-from-the-ui',
dataView: true,
args: ['projectid', 'account', 'email'],
show: (record, store) => { return record.account === store.userInfo.account || ['Admin', 'DomainAdmin'].includes(store.userInfo.roletype) },
mapping: {
projectid: {
value: (record) => { return record.id }
}
}
popup: true,
show: (record, store) => {
return (['Admin', 'DomainAdmin'].includes(store.userInfo.roletype)) || record.isCurrentUserProjectAdmin
},
component: () => import('@/views/project/AddAccountOrUserToProject.vue')
},
{
api: 'deleteProject',
Expand All @@ -129,7 +137,9 @@ export default {
message: 'message.delete.project',
docHelp: 'adminguide/projects.html#suspending-or-deleting-a-project',
dataView: true,
show: (record, store) => { return record.account === store.userInfo.account || ['Admin', 'DomainAdmin'].includes(store.userInfo.roletype) }
show: (record, store) => {
return (['Admin', 'DomainAdmin'].includes(store.userInfo.roletype)) || record.isCurrentUserProjectAdmin
}
}
]
}
22 changes: 22 additions & 0 deletions src/locales/en.json
Expand Up @@ -213,6 +213,7 @@
"label.action.migrate.systemvm": "Migrate System VM",
"label.action.migrate.systemvm.processing": "Migrating System VM....",
"label.action.project.add.account": "Add Account to Project",
"label.action.project.add.user": "Add User to Project",
"label.action.reboot.instance": "Reboot Instance",
"label.action.reboot.instance.processing": "Rebooting Instance....",
"label.action.reboot.router": "Reboot Router",
Expand Down Expand Up @@ -339,6 +340,7 @@
"label.add.portable.ip.range": "Add Portable IP Range",
"label.add.primary.storage": "Add Primary Storage",
"label.add.private.gateway": "Add Private Gateway",
"label.add.project.role": "Add Project Role",
"label.add.region": "Add Region",
"label.add.resources": "Add Resources",
"label.add.role": "Add Role",
Expand Down Expand Up @@ -608,6 +610,7 @@
"label.create.nfs.secondary.staging.storage": "Create NFS Secondary Staging Store",
"label.create.nfs.secondary.staging.store": "Create NFS secondary staging store",
"label.create.project": "Create project",
"label.create.project.role": "Create Project Role",
"label.create.user": "Create user",
"label.create.site.vpn.connection": "Create Site-to-Site VPN Connection",
"label.create.site.vpn.gateway": "Create Site-to-Site VPN Gateway",
Expand Down Expand Up @@ -675,6 +678,7 @@
"label.delete.pa": "Delete Palo Alto",
"label.delete.portable.ip.range": "Delete Portable IP Range",
"label.delete.project": "Delete project",
"label.delete.project.role": "Delete Project Role",
"label.delete.role": "Delete Role",
"label.delete.rule": "Delete rule",
"label.delete.secondary.staging.store": "Delete Secondary Staging Store",
Expand All @@ -694,6 +698,8 @@
"label.deleting.failed": "Deleting Failed",
"label.deleting.iso": "Deleting ISO",
"label.deleting.processing": "Deleting....",
"label.demote.project.owner": "Demote account to Regular role",
"label.demote.project.owner.user": "Demote user to Regular role",
"label.deleting.template": "Deleting template",
"label.deny": "Deny",
"label.deploymentplanner": "Deployment planner",
Expand Down Expand Up @@ -793,6 +799,7 @@
"label.edit.lb.rule": "Edit LB rule",
"label.edit.network.details": "Edit network details",
"label.edit.project.details": "Edit project details",
"label.edit.project.role": "Edit Project Role",
"label.edit.region": "Edit Region",
"label.edit.role": "Edit Role",
"label.edit.rule": "Edit rule",
Expand Down Expand Up @@ -1239,6 +1246,7 @@
"label.macaddresschanges": "MAC Address Changes",
"label.macos": "MacOS",
"label.make.project.owner": "Make account project owner",
"label.make.user.project.owner": "Make user project owner",
"label.makeredundant": "Make redundant",
"label.manage": "Manage",
"label.manage.resources": "Manage Resources",
Expand Down Expand Up @@ -1325,6 +1333,7 @@
"label.metrics.network.usage": "Network Usage",
"label.metrics.network.write": "Write",
"label.metrics.num.cpu.cores": "Cores",

"label.migrate.instance.to": "Migrate instance to",
"label.migrate.instance.to.host": "Migrate instance to another host",
"label.migrate.instance.to.ps": "Migrate instance to another primary storage",
Expand Down Expand Up @@ -1503,6 +1512,7 @@
"label.owned.public.ips": "Owned Public IP Addresses",
"label.owner.account": "Owner Account",
"label.owner.domain": "Owner Domain",
"label.owners": "Owners",
"label.pa": "Palo Alto",
"label.page": "page",
"label.palo.alto.details": "Palo Alto details",
Expand Down Expand Up @@ -1593,6 +1603,10 @@
"label.project.invitation": "Project Invitations",
"label.project.invite": "Invite to project",
"label.project.name": "Project name",
"label.project.owner": "Project Owner(s)",
"label.project.role": "Project Role",
"label.project.roles": "Project Roles",
"label.project.role.permissions": "Project Role Permissions",
"label.project.view": "Project View",
"label.projectaccountname": "Project Account Name",
"label.projectid": "Project ID",
Expand Down Expand Up @@ -1712,6 +1726,8 @@
"label.remove.network.offering": "Remove network offering",
"label.remove.pf": "Remove port forwarding rule",
"label.remove.project.account": "Remove account from project",
"label.remove.project.role": "Remove project role",
"label.remove.project.user": "Remove user from project",
"label.remove.region": "Remove Region",
"label.remove.rule": "Remove rule",
"label.remove.ssh.key.pair": "Remove SSH Key Pair",
Expand Down Expand Up @@ -2094,6 +2110,7 @@
"label.untagged": "Untagged",
"label.update.instance.group": "Update Instance Group",
"label.update.project.resources": "Update project resources",
"label.update.project.role": "Update project role",
"label.update.ssl": " SSL Certificate",
"label.update.ssl.cert": " SSL Certificate",
"label.update.to": "updated to",
Expand All @@ -2120,6 +2137,7 @@
"label.usehttps": "Use HTTPS",
"label.usenewdiskoffering": "Replace disk offering?",
"label.user": "User",
"label.user.as.admin": "Make User the Project Admin",
"label.user.conflict": "Conflict",
"label.user.details": "User details",
"label.user.source": "source",
Expand Down Expand Up @@ -2440,6 +2458,7 @@
"message.add.tag.for.networkacl": "Add tag for NetworkACL",
"message.add.tag.processing": "Adding new tag...",
"message.add.template": "Please enter the following data to create your new template",
"message.add.user.to.project": "This form is to enable adding specific users of an account to a project.<br>Furthermore, a ProjectRole may be added to the added user/account to allow/disallow API access at project level.<br> We can also specify the role with which the user should be added to a project - Admin/Regular; if not specified, it defaults to 'Regular'",
"message.add.volume": "Please fill in the following data to add a new volume.",
"message.add.vpn.connection.failed": "Adding VPN Connection failed",
"message.add.vpn.connection.processing": "Adding VPN Connection...",
Expand Down Expand Up @@ -3183,6 +3202,9 @@
"message.zone.step.3.desc": "Please enter the following info to add a new pod",
"message.zonewizard.enable.local.storage": "WARNING: If you enable local storage for this zone, you must do the following, depending on where you would like your system VMs to launch:<br/><br/>1. If system VMs need to be launched in shared primary storage, shared primary storage needs to be added to the zone after creation. You must also start the zone in a disabled state.<br/><br/>2. If system VMs need to be launched in local primary storage, system.vm.use.local.storage needs to be set to true before you enable the zone.<br/><br/><br/>Would you like to continue?",
"messgae.validate.min": "Please enter a value greater than or equal to {0}.",
"migrate.from": "Migrate From",
"migrate.to": "Migrate To",
"migrationPolicy": "Migration Policy",
"network.rate": "Network Rate",
"router.health.checks": "Health Check",
"side.by.side": "Side by Side",
Expand Down
27 changes: 24 additions & 3 deletions src/store/modules/user.js
Expand Up @@ -91,7 +91,6 @@ const user = {
return new Promise((resolve, reject) => {
login(userInfo).then(response => {
const result = response.loginresponse || {}

Cookies.set('account', result.account, { expires: 1 })
Cookies.set('domainid', result.domainid, { expires: 1 })
Cookies.set('role', result.type, { expires: 1 })
Expand All @@ -100,7 +99,6 @@ const user = {
Cookies.set('userfullname', result.firstname + ' ' + result.lastname, { expires: 1 })
Cookies.set('userid', result.userid, { expires: 1 })
Cookies.set('username', result.username, { expires: 1 })

Vue.ls.set(ACCESS_TOKEN, result.sessionkey, 24 * 60 * 60 * 1000)
commit('SET_TOKEN', result.sessionkey)

Expand Down Expand Up @@ -174,7 +172,7 @@ const user = {
})
}

api('listUsers', { username: Cookies.get('username'), listall: true }).then(response => {
api('listUsers', { username: Cookies.get('username') }).then(response => {
const result = response.listusersresponse.user[0]
commit('SET_INFO', result)
commit('SET_NAME', result.firstname + ' ' + result.lastname)
Expand Down Expand Up @@ -248,6 +246,29 @@ const user = {
var jobsArray = Vue.ls.get(ASYNC_JOB_IDS, [])
jobsArray.push(jobJson)
commit('SET_ASYNC_JOB_IDS', jobsArray)
},
ProjectView ({ commit }, projectid) {
return new Promise((resolve, reject) => {
api('listApis', { projectid: projectid }).then(response => {
const apis = {}
const apiList = response.listapisresponse.api
for (var idx = 0; idx < apiList.length; idx++) {
const api = apiList[idx]
const apiName = api.name
apis[apiName] = {
params: api.params,
response: api.response
}
}
commit('SET_APIS', apis)
resolve(apis)
store.dispatch('GenerateRoutes', { apis }).then(() => {
router.addRoutes(store.getters.addRouters)
})
}).catch(error => {
reject(error)
})
})
}
}
}
Expand Down
17 changes: 12 additions & 5 deletions src/views/AutogenView.vue
Expand Up @@ -576,6 +576,18 @@ export default {
this.items = []
}
if (['listTemplates', 'listIsos'].includes(this.apiName) && this.items.length > 1) {
this.items = [...new Map(this.items.map(x => [x.id, x])).values()]
}
if (this.apiName === 'listProjects' && this.items.length > 0) {
this.columns.map(col => {
if (col.title === 'Account') {
col.title = this.$t('label.project.owner')
}
})
}
for (let idx = 0; idx < this.items.length; idx++) {
this.items[idx].key = idx
for (const key in customRender) {
Expand Down Expand Up @@ -818,7 +830,6 @@ export default {
execSubmit (e) {
e.preventDefault()
this.form.validateFields((err, values) => {
console.log(values)
if (!err) {
const params = {}
if ('id' in this.resource && this.currentAction.params.map(i => { return i.name }).includes('id')) {
Expand Down Expand Up @@ -868,10 +879,6 @@ export default {
}
}
console.log(this.currentAction)
console.log(this.resource)
console.log(params)
const resourceName = params.displayname || params.displaytext || params.name || params.hostname || params.username || params.ipaddress || params.virtualmachinename || this.resource.name
var hasJobId = false
Expand Down

0 comments on commit a3aaa92

Please sign in to comment.