Merge pull request #1456 from jumpserver/dev

v2.20.0-rc2
This commit is contained in:
Jiangjie.Bai
2022-03-14 10:39:43 +08:00
committed by GitHub
26 changed files with 123 additions and 339 deletions

View File

@@ -103,6 +103,9 @@ export default {
// Request URL: http://localhost/api/v1/assets/assets/?node_id=d8212328-538d-41a6-bcfd-1e8cc7e3aed4&show_current_asset=null&draw=2&limit=15&offset=0&_=1587022917769
onSelected: function(event, treeNode) {
const show_current_asset = this.$cookie.get('show_current_asset') || '0'
if (!this.setting.url) {
return
}
let combinator = '?'
if (this.setting.url.indexOf('?') !== -1) {
combinator = '&'

View File

@@ -40,27 +40,31 @@ export default [
]
},
{
path: 'app-permissions',
path: 'application-permissions',
component: empty,
redirect: '',
meta: {
title: i18n.t('route.ApplicationPermission'),
permissions: ['perms.view_applicationpermission'],
resource: 'applicationpermission'
},
redirect: '',
children: [
{
path: '',
name: 'ApplicationPermissionList',
component: () => import('@/views/perms/ApplicationPermission/ApplicationPermissionList'),
meta: { title: i18n.t('route.ApplicationPermission'), permissions: ['perms.view_applicationpermission'] }
meta: {
title: i18n.t('route.ApplicationPermission')
}
},
{
path: 'create',
component: () => import('@/views/perms/ApplicationPermission/ApplicationPermissionCreateUpdate'),
name: 'ApplicationPermissionCreate',
hidden: true,
meta: { title: i18n.t('route.ApplicationPermissionCreate'), action: 'create' }
meta: {
title: i18n.t('route.ApplicationPermissionCreate'),
action: 'create'
}
},
{
path: ':id',

View File

@@ -69,6 +69,11 @@ export const constantRoutes = [
component: () => import('@/views/404'),
hidden: true
},
{
path: '*',
redirect: '/404',
hidden: true
},
...commonRoutes
]

View File

@@ -25,7 +25,7 @@ export default {
meta: {
title: i18n.t('setting.Basic'),
icon: 'gear',
permissions: ['settings.change_basic']
permissions: ['settings.view_setting']
}
},
{

View File

@@ -12,7 +12,8 @@ export default {
view: 'tickets',
type: 'view',
showNavSwitcher: false,
permissions: []
resource: 'ticket',
permissions: ['tickets.view_ticket']
},
children: [
{
@@ -22,10 +23,7 @@ export default {
meta: {
title: i18n.t('route.Tickets'),
icon: 'file-text-o',
showOrganization: false,
permissions: [],
resource: 'terminal',
app: 'terminal'
showOrganization: false
},
children: [
{
@@ -35,9 +33,7 @@ export default {
meta: {
title: i18n.t('route.Tickets'),
icon: 'file-text-o',
permissions: [],
resource: 'terminal',
app: 'terminal'
permissions: []
}
},
{

View File

@@ -44,6 +44,7 @@ export default {
{
name: 'TestConnection',
title: this.$t('assets.TestConnection'),
can: () => vm.$hasPerm('xpack.test_account'),
callback: function(val) {
this.$axios.get(`/api/v1/xpack/cloud/accounts/${val.row.id}/test-connective/`).then(res => {
this.$message.success(this.$t('common.TestSuccessMsg'))

View File

@@ -43,6 +43,7 @@ export default {
title: vm.$t('xpack.Execute'),
name: 'execute',
type: 'info',
can: () => vm.$hasPerm('xpack.change_syncinstancetask'),
callback: function(data) {
this.$axios.get(`/api/v1/xpack/cloud/sync-instance-tasks/${data.row.id}/run/`).then(res => {
openTaskPage(res['task'])

View File

@@ -29,7 +29,7 @@ export default {
],
[
this.$t('setting.Feature'), [
'TICKETS_ENABLED', 'ANNOUNCEMENT_ENABLED'
'ANNOUNCEMENT_ENABLED'
]
]
],
@@ -42,11 +42,6 @@ export default {
return !this.$store.getters.hasValidLicense
}
},
TICKETS_ENABLED: {
hidden: () => {
return !this.$store.getters.hasValidLicense
}
},
ANNOUNCEMENT_ENABLED: {
// label: '公告',
component: Announcement

View File

@@ -27,6 +27,7 @@ export default {
Organization: {},
config: {
activeMenu: 'OrganizationDetail',
url: '/api/v1/orgs/orgs',
submenu: [
{
title: this.$t('xpack.Organization.OrganizationDetail'),
@@ -51,7 +52,7 @@ export default {
try {
await performDelete.bind(this)()
this.$message.success(this.$t('common.deleteSuccessMsg'))
this.$router.push('/xpack/orgs/') // 返回列表
this.$router.push({ name: 'OrganizationList' })
return done()
} catch (error) {
this.$log.error(error)

View File

@@ -14,9 +14,14 @@ export default {
GenericListPage
},
data() {
const vm = this
return {
tableConfig: {
url: '/api/v1/orgs/orgs/',
permissions: {
app: 'orgs',
resource: 'organization'
},
columns: ['name',
'resource_statistics.users_amount',
'resource_statistics.groups_amount',
@@ -55,10 +60,8 @@ export default {
actions: {
prop: 'id',
formatterArgs: {
canClone: true,
canUpdate: true,
canDelete: function({ row }) {
return !row.is_default
return !row.is_default && vm.$hasPerm('orgs.delete_organization')
},
onDelete: function({ row, col, cellValue, reload }) {
const msg = this.$t('xpack.Organization.DeleteOrgMsg')
@@ -88,7 +91,6 @@ export default {
}
},
headerActions: {
canCreate: true,
hasExport: false,
hasImport: false,
hasMoreActions: false

View File

@@ -53,9 +53,6 @@ export default {
label: this.$t('xpack.RegularlyPerform'),
helpText: this.$t('xpack.HelpText.CrontabOfCreateUpdatePage')
},
TICKETS_ENABLED: {
hidden: () => this.hasValidLicense()
},
HELP_DOCUMENT_URL: {
label: this.$t('xpack.helpDocument'),
helpText: this.$t('xpack.helpDocumentTip'),

View File

@@ -26,7 +26,7 @@ export default {
ticketTableConfig: {
url: this.url,
permissions: {
resource: 'superticket'
resource: 'ticket'
},
columns: [
{

View File

@@ -14,7 +14,7 @@
<br>
<small class="text-muted">{{ toSafeLocalDateStr(item.date_created) }}</small>
<pre style="padding-top: 10px; overflow: auto">
{{ item.body }}
{{ item.body }}
</pre>
</div>
</div>

View File

@@ -9,7 +9,7 @@
</el-col>
<el-col :span="6" :offset="1">
<Steps :object="object" />
<Session :object="object" />
<Session v-perms="'tickets.view_ticketsession'" :object="object" />
</el-col>
</el-row>
</template>

View File

@@ -37,7 +37,7 @@
<el-button
type="danger"
size="small"
:disabled="!session.can_terminate"
:disabled="asDisabled(!session.can_terminate)"
@click="onConnect"
>
{{ $t('sessions.terminate') }}
@@ -45,7 +45,7 @@
<el-button
type="primary"
size="small"
:disabled="!session.can_join"
:disabled="asDisabled(!session.can_join)"
@click="onMonitor"
>
{{ $t('sessions.Monitor') }}
@@ -115,6 +115,9 @@ export default {
onMonitor() {
const joinUrl = `/luna/monitor/${this.session.id}`
window.open(joinUrl, 'height=600, width=800, top=400, left=400, toolbar=no, menubar=no, scrollbars=no, location=no, status=no')
},
asDisabled(type) {
return (type || true) || !this.$hasPerm('tickets.change_ticketsession')
}
}

View File

@@ -20,18 +20,15 @@ import { mapGetters } from 'vuex'
import { getTicketOpenCount } from '@/api/ticket'
import AssignedTicketList from './AssignedTicketList'
import MyTicketList from './MyTicketList'
import TicketFlow from './TicketFlow/TicketFlow'
export default {
name: 'Index',
components: {
TabPage,
AssignedTicketList,
MyTicketList,
TicketFlow
MyTicketList
},
data() {
const vm = this
return {
assignedTicketCount: 0,
config: {
@@ -44,14 +41,6 @@ export default {
{
title: this.$t('tickets.AssignedMe'),
name: 'AssignedTicketList'
},
{
title: this.$t('tickets.FlowSetUp'),
icon: 'fa-gear',
name: 'TicketFlow',
hidden: () => {
return !vm.$store.getters.currentUserIsSuperAdmin
}
}
]
}

View File

@@ -60,26 +60,49 @@ export default {
enable: false
},
callback: {
onCheck(event, treeId, treeNode) {
onCheck: _.debounce((event, treeId, treeNode) => {
// 选择后,更新按钮可用
vm.$nextTick(() => {
vm.isDisabled = false
})
vm.checkDeps(event, treeNode)
vm.checkViewNodeIfNeed()
},
onSelected() {
vm.checkActionDeps(treeNode)
vm.checkSpecDeps()
}, 200),
beforeCheck: (treeId, treeNode) => {
return true
}
}
},
viewPermMapper: [
['view_console', ['rbac.view_console', 'rbac.view_dashboard']],
['view_audit', ['rbac.view_audit', 'rbac.view_dashboard']],
['view_workspace', ['rbac.view_workspace']]
]
nodesDeps: {
'view_console': ['rbac.view_console'],
'view_audit': ['rbac.view_audit'],
'view_workspace': ['rbac.view_workspace'],
'view_setting': ['settings.view_setting', 'settings.change_setting'],
'users.invite_user': [
'users.match_user', 'rbac.add_orgrolebinding', 'rbac.change_orgrolebinding',
'rbac.view_orgrolebinding', 'rbac.view_orgrole'
],
'assets.view_asset': ['assets.view_node'],
'assets.commandfilterrule': ['assets.view_commandfilter'],
'assets.gateway': ['assets.view_domain'],
'cloud_import': ['assets.view_asset'],
'xpack.add_syncinstancetask': [
'assets.view_asset', 'assets.view_node', 'assets.view_systemuser',
'xpack.view_account'
],
'applications.add_application': ['assets.view_asset'],
'perms.view_assetpermission': ['assets.view_node'],
'perms.view_applicationpermission': ['applications.view_application'],
'acls.loginacl': ['users.view_user'],
'rbac.orgrolebinding': ['rbac.view_orgrole'],
'rbac.systemrolebinding': ['rbac.view_systemrole']
}
}
},
computed: {
ztree() {
return this.$refs.tree.zTree
},
detailItems() {
return [
{
@@ -136,7 +159,7 @@ export default {
}
return { action, resource, app }
},
checkDeps(evt, node) {
checkActionDeps(node) {
if (node.isParent) {
this.$log.debug('Is parent')
return
@@ -187,39 +210,35 @@ export default {
ztree.checkNode(viewNode, true)
}
},
checkViewNodeIfNeed() {
checkSpecDeps() {
const ztree = this.$refs.tree.zTree
for (const [viewId, permIds] of this.viewPermMapper) {
const viewNode = ztree.getNodeByParam('id', viewId)
const permNodes = permIds.map(i => ztree.getNodeByParam('title', i))
if (!viewNode || permNodes.length === 0) {
this.$log.debug('Not view node or perms nodes length 0')
continue
}
const nodeStatus = viewNode.getCheckStatus()
const viewStatus = nodeStatus.checked || nodeStatus.half
for (const permNode of permNodes) {
ztree.checkNode(permNode, viewStatus)
}
const depsId = ztree.getCheckedNodes().filter(i => {
return !!this.nodesDeps[i.title]
}).reduce((result, v) => {
return [...result, ...this.nodesDeps[v.title]]
}, [])
this.$log.debug('Select nodes should try: ', depsId)
for (const i of depsId) {
const depNode = this.ztree.getNodeByParam('title', i)
this.ztree.checkNode(depNode, true)
}
return Promise.resolve(true)
},
updatePermissions() {
this.checkViewNodeIfNeed().then(() => {
const ztree = this.$refs.tree.zTree
const checkedNodes = ztree.getCheckedNodes()
const permNodes = checkedNodes.filter(node => !node.isParent)
const permIds = permNodes.map(node => node.id)
const roleDetailUrl = `/api/v1/rbac/${this.object.scope}-roles/${this.object.id}/`
const data = {
permissions: permIds
}
this.$axios.patch(roleDetailUrl, data).then(() => {
this.$message.success(this.$t('common.updateSuccessMsg'))
}).catch(error => {
this.$message.error(this.$t('common.updateErrorMsg') + error)
this.$log.error(error)
})
const ztree = this.$refs.tree.zTree
const checkedNodes = ztree.getCheckedNodes()
const permNodes = checkedNodes.filter(node => !node.isParent)
const permIds = permNodes.map(node => node.id)
const roleDetailUrl = `/api/v1/rbac/${this.object.scope}-roles/${this.object.id}/`
const data = {
permissions: permIds
}
this.$axios.patch(roleDetailUrl, data).then(() => {
this.$message.success(this.$t('common.updateSuccessMsg'))
}).catch(error => {
this.$message.error(this.$t('common.updateErrorMsg') + error)
this.$log.error(error)
})
}
}

View File

@@ -19,6 +19,7 @@ export default {
},
data() {
const scopeRole = this.scope + 'role'
const vm = this
return {
loading: true,
scopeRole: scopeRole,
@@ -72,6 +73,15 @@ export default {
},
canClone: ({ row }) => {
return this.$hasPerm(`rbac.add_${row.scope}role`)
},
onClone: ({ row }) => {
return vm.$router.push({
name: 'RoleCreate',
query: {
scope: this.scope,
clone_from: row.id
}
})
}
}
}

View File

@@ -16,6 +16,7 @@ export default {
}
},
data() {
const vm = this
return {
tableConfig: {
url: `/api/v1/perms/application-permissions/?user_id=${this.object.id}&draw=1`,
@@ -49,6 +50,7 @@ export default {
},
actions: {
formatterArgs: {
canUpdate: vm.$hasPerm('perms.change_applicationpermission'),
onUpdate: ({ row, col, cellValue }) => {
const route = {
name: 'ApplicationPermissionUpdate',
@@ -57,11 +59,13 @@ export default {
}
this.$router.push(route)
},
canDelete: vm.$hasPerm('perms.delete_applicationpermission'),
performDelete: ({ row, col }) => {
const id = row.id
const url = `/api/v1/perms/application-permissions/${id}/?user_id=${this.object.id}&draw=1`
return this.$axios.delete(url)
},
canClone: vm.$hasPerm('perms.add_applicationpermission'),
onClone: ({ row }) => {
const route = {
name: 'ApplicationPermissionCreate',

View File

@@ -17,6 +17,7 @@ export default {
}
},
data() {
const vm = this
return {
tableConfig: {
url: `/api/v1/perms/asset-permissions/?user_id=${this.object.id}`,
@@ -69,7 +70,13 @@ export default {
},
actions: {
formatterArgs: {
canClone: vm.$hasPerm('perms.add_assetpermission'),
cloneRoute: {
name: 'AssetPermissionCreate'
},
updateRoute: 'AssetPermissionUpdate',
canUpdate: vm.$hasPerm('perms.change_assetpermission'),
canDelete: vm.$hasPerm('perms.delete_assetpermission'),
performDelete: ({ row, col }) => {
const id = row.id
const url = `/api/v1/perms/asset-permissions/${id}/?user_id=${this.object.id}&draw=1`

View File

@@ -1,70 +0,0 @@
<template>
<ListTable :table-config="tableConfig" :header-actions="headerActions" />
</template>
<script>
import ListTable from '@/components/ListTable'
export default {
name: 'UserDatabasePermissionRules',
components: {
ListTable
},
props: {
object: {
type: Object,
required: true
}
},
data() {
return {
tableConfig: {
url: `/api/v1/perms/database-app-permissions/?user_id=${this.object.id}&draw=1`,
columns: ['name', 'users_amount', 'user_groups_amount', 'database_apps_amount', 'system_users_amount', 'is_valid', 'actions'],
columnsMeta: {
name: {
formatterArgs: {
route: 'DatabaseAppPermissionDetail'
}
},
users_amount: {
label: this.$t('users.Users'),
width: '110px'
},
user_groups_amount: {
label: this.$t('users.UserGroups'),
width: '110px'
},
database_apps_amount: {
label: this.$t('assets.RemoteApps'),
width: '110px'
},
system_users_amount: {
label: this.$t('assets.SystemUsers'),
width: '110px'
},
actions: {
formatterArgs: {
updateRoute: 'DatabaseAppPermissionUpdate',
performDelete: ({ row, col }) => {
const id = row.id
const url = `/api/v1/perms/database-app-permissions/${id}/?user_id=${this.object.id}&draw=1`
return this.$axios.delete(url)
}
}
}
}
},
headerActions: {
hasLeftActions: false,
hasImport: false,
hasExport: false
}
}
}
}
</script>
<style scoped>
</style>

View File

@@ -1,56 +0,0 @@
<template>
<ListTable :table-config="tableConfig" :header-actions="headerActions" />
</template>
<script>
import ListTable from '@/components/ListTable'
export default {
name: 'UserGrantedDatabases',
components: {
ListTable
},
props: {
object: {
type: Object,
required: true
}
},
data() {
return {
tableConfig: {
url: `/api/v1/perms/users/${this.object.id}/database-apps/?draw=1`,
columns: ['name', 'get_type_display', 'host', 'port', 'database', 'comment'],
columnsMeta: {
name: {
formatterArgs: {
route: 'DatabaseAppDetail'
}
},
get_type_display: {
label: this.$t('applications.type'),
width: '80px'
},
host: {
width: '140px'
},
port: {
width: '60px'
},
database: {
showOverflowTooltip: true
}
}
},
headerActions: {
hasLeftActions: false,
hasImport: false,
hasExport: false
}
}
}
}
</script>
<style scoped>
</style>

View File

@@ -1,49 +0,0 @@
<template>
<ListTable :table-config="tableConfig" :header-actions="headerActions" />
</template>
<script>
import ListTable from '@/components/ListTable'
export default {
name: 'UserGrantedK8Ss',
components: {
ListTable
},
props: {
object: {
type: Object,
required: true
}
},
data() {
return {
tableConfig: {
url: `/api/v1/perms/users/${this.object.id}/k8s-apps/?draw=1`,
columns: ['name', 'type', 'cluster', 'comment'],
columnsMeta: {
name: {
formatterArgs: {
route: 'KubernetesAppDetail'
}
},
comment: {
width: '340px'
},
type: {
width: '140px'
}
}
},
headerActions: {
hasLeftActions: false,
hasImport: false,
hasExport: false
}
}
}
}
</script>
<style scoped>
</style>

View File

@@ -1,70 +0,0 @@
<template>
<ListTable :table-config="tableConfig" :header-actions="headerActions" />
</template>
<script>
import ListTable from '@/components/ListTable'
export default {
name: 'UserDatabasePermissionRules',
components: {
ListTable
},
props: {
object: {
type: Object,
required: true
}
},
data() {
return {
tableConfig: {
url: `/api/v1/perms/k8s-app-permissions/?user_id=${this.object.id}&draw=1`,
columns: ['name', 'users_amount', 'user_groups_amount', 'k8s_apps_amount', 'system_users_amount', 'is_valid', 'actions'],
columnsMeta: {
name: {
formatterArgs: {
route: 'KubernetesAppPermissionDetail'
}
},
users_amount: {
label: this.$t('users.Users'),
width: '110px'
},
user_groups_amount: {
label: this.$t('users.UserGroups'),
width: '110px'
},
k8s_apps_amount: {
label: this.$t('perms.KubernetesApp'),
width: '110px'
},
system_users_amount: {
label: this.$t('assets.SystemUsers'),
width: '110px'
},
actions: {
formatterArgs: {
updateRoute: 'KubernetesAppPermissionUpdate',
performDelete: ({ row, col }) => {
const id = row.id
const url = `/api/v1/perms/k8s-app-permissions/${id}/?user_id=${this.object.id}&draw=1`
return this.$axios.delete(url)
}
}
}
}
},
headerActions: {
hasLeftActions: false,
hasImport: false,
hasExport: false
}
}
}
}
</script>
<style scoped>
</style>

View File

@@ -12,11 +12,7 @@ import UserAssetPermissionRules from './UserAssetPermissionRules'
import UserGrantedAssets from './UserGrantedAssets'
import UserGrantedApplications from './UserGrantedApplications'
import UserApplicationPermissionRules from './UserApplicationsPermissionRules'
import UserGrantedDatabases from './UserGrantedDatabases'
import UserGrantedK8Ss from './UserGrantedK8Ss'
import UserK8SPermissionRules from './UserK8SPermissionRules'
import UserLoginACLList from '@/views/acl/UserLoginACL/UserLoginACLList'
import UserDatabasePermissionRules from './UserDatabasePermissionRules'
import UserInfo from './UserInfo'
export default {
@@ -27,10 +23,6 @@ export default {
UserAssetPermissionRules,
UserGrantedApplications,
UserApplicationPermissionRules,
UserGrantedDatabases,
UserDatabasePermissionRules,
UserK8SPermissionRules,
UserGrantedK8Ss,
UserLoginACLList
},
data() {

View File

@@ -61,7 +61,7 @@ export default {
component: Select2,
el: {
ajax: {
url: '/api/v1/rbac/roles/?scope=org',
url: '/api/v1/rbac/org-roles/',
transformOption: (item) => {
return { label: `${item.display_name}`, value: item.id }
}