diff --git a/.dockerignore b/.dockerignore index de4d1f007..7c3b4c0b7 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1,3 @@ +lina dist node_modules diff --git a/.eslintignore b/.eslintignore index 3085b90eb..ae66d5e2f 100644 --- a/.eslintignore +++ b/.eslintignore @@ -2,4 +2,5 @@ build/*.js src/assets public dist +lina node_modules diff --git a/.gitignore b/.gitignore index 9ad28d23d..e5c58cf89 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .DS_Store node_modules/ dist/ +lina/ npm-debug.log* yarn-debug.log* yarn-error.log* diff --git a/Dockerfile b/Dockerfile index 66d2f8330..82bb15c9a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,5 +8,5 @@ RUN yarn build:prod FROM nginx:alpine -COPY --from=stage-build /data/dist /opt/lina/ +COPY --from=stage-build /data/lina /opt/lina/ COPY nginx.conf /etc/nginx/conf.d/default.conf diff --git a/src/router/applications.js b/src/router/applications.js index 0468f6759..77c5b690f 100644 --- a/src/router/applications.js +++ b/src/router/applications.js @@ -1,32 +1,41 @@ import i18n from '@/i18n/i18n' +import empty from '@/layout/empty' export default [ { path: 'remote-apps', - name: 'RemoteAppList', - component: () => import('@/views/applications/RemoteApp/RemoteAppList'), - meta: { title: i18n.t('route.RemoteApp'), licenseRequired: true } - }, - { - path: 'remote-apps/create', - name: 'RemoteAppCreate', - component: () => import('@/views/applications/RemoteApp/RemoteAppCreateUpdate'), - meta: { title: i18n.t('route.RemoteApp'), activeMenu: '/applications/remote-apps', action: 'create', licenseRequired: true }, - hidden: true - }, - { - path: 'remote-apps/:id/update', - name: 'RemoteAppUpdate', - component: () => import('@/views/applications/RemoteApp/RemoteAppCreateUpdate'), - meta: { title: i18n.t('route.RemoteAppUpdate'), activeMenu: '/applications/remote-apps', action: 'update', licenseRequired: true }, - hidden: true - }, - { - path: 'remote-apps/:id', - name: 'RemoteAppDetail', - component: () => import('@/views/applications/RemoteApp/RemoteAppDetail/index'), - meta: { title: i18n.t('route.RemoteAppDetail'), activeMenu: '/applications/remote-apps', licenseRequired: true }, - hidden: true + redirect: '', + component: empty, + meta: { title: i18n.t('route.RemoteApp'), licenseRequired: true }, + children: [ + { + path: '', + name: 'RemoteAppList', + meta: { title: i18n.t('route.RemoteApp') }, + component: () => import('@/views/applications/RemoteApp/RemoteAppList') + }, + { + path: 'create', + name: 'RemoteAppCreate', + component: () => import('@/views/applications/RemoteApp/RemoteAppCreateUpdate'), + meta: { title: i18n.t('route.RemoteApp'), activeMenu: '/applications/remote-apps', action: 'create' }, + hidden: true + }, + { + path: ':id/update', + name: 'RemoteAppUpdate', + component: () => import('@/views/applications/RemoteApp/RemoteAppCreateUpdate'), + meta: { title: i18n.t('route.RemoteAppUpdate'), activeMenu: '/applications/remote-apps', action: 'update' }, + hidden: true + }, + { + path: ':id', + name: 'RemoteAppDetail', + component: () => import('@/views/applications/RemoteApp/RemoteAppDetail/index'), + meta: { title: i18n.t('route.RemoteAppDetail'), activeMenu: '/applications/remote-apps' }, + hidden: true + } + ] }, { path: 'database-apps', diff --git a/src/router/index.js b/src/router/index.js index bfbcb55ae..fb982cc63 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -105,6 +105,7 @@ export const allRoleRoutes = [ component: Layout, redirect: '/applications/remote-apps/', name: 'applications', + alwaysShow: true, meta: { title: i18n.t('route.Applications'), icon: 'th' }, children: ApplicationsRoute }, @@ -129,6 +130,7 @@ export const allRoleRoutes = [ component: Layout, redirect: '/ops/tasks/', name: 'JobCenter', + alwaysShow: true, meta: { title: i18n.t('route.JobCenter'), icon: 'coffee' }, children: OpsRoutes }, diff --git a/src/router/ops.js b/src/router/ops.js index 41cf0e88c..2c66bdc73 100644 --- a/src/router/ops.js +++ b/src/router/ops.js @@ -1,5 +1,5 @@ import i18n from '@/i18n/i18n' - +import rolec from '@/utils/role' export default [ { path: 'tasks', @@ -45,6 +45,6 @@ export default [ path: 'task/monitor', name: 'TaskMonitor', component: () => window.open(`/core/flower?_=${Date.now()}`), - meta: { title: i18n.t('route.TaskMonitor') } + meta: { title: i18n.t('route.TaskMonitor'), permissions: [rolec.PERM_SUPER] } } ] diff --git a/src/router/perms.js b/src/router/perms.js index ed15b599e..32d86c6d5 100644 --- a/src/router/perms.js +++ b/src/router/perms.js @@ -1,4 +1,5 @@ import i18n from '@/i18n/i18n' +import empty from '@/layout/empty' const assetPermissionRoutes = [ { @@ -33,31 +34,40 @@ const assetPermissionRoutes = [ const remoteAppPermissionRoutes = [ { path: 'remote-app-permissions', - name: 'RemoteAppPermissionList', - component: () => import('@/views/perms/RemoteAppPermission/RemoteAppPermissionList'), - meta: { title: i18n.t('route.RemoteAppPermission') } - }, - { - path: 'remote-app-permissions/create', - component: () => import('@/views/perms/RemoteAppPermission/RemoteAppPermissionCreateUpdate'), - name: 'RemoteAppPermissionCreate', - hidden: true, - meta: { title: i18n.t('route.RemoteAppPermissionCreate'), activeMenu: '/perms/remote-app-permissions', action: 'create' } - }, - { - path: 'remote-app-permissions/update', - component: () => import('@/views/perms/RemoteAppPermission/RemoteAppPermissionCreateUpdate'), - name: 'RemoteAppPermissionUpdate', - hidden: true, - meta: { title: i18n.t('route.RemoteAppPermissionUpdate'), activeMenu: '/perms/remote-app-permissions', action: 'update' } - }, - { - path: 'remote-app-permissions/:id', - component: () => import('@/views/perms/RemoteAppPermission/RemoteAppPermissionDetail/index'), - name: 'RemoteAppPermissionDetail', - hidden: true, - meta: { title: i18n.t('route.RemoteAppPermissionDetail'), activeMenu: '/perms/remote-app-permissions' } + component: empty, + meta: { title: i18n.t('route.RemoteAppPermission'), licenseRequired: true }, + redirect: '', + children: [ + { + path: '', + name: 'RemoteAppPermissionList', + component: () => import('@/views/perms/RemoteAppPermission/RemoteAppPermissionList'), + meta: { title: i18n.t('route.RemoteAppPermission') } + + }, + { + path: 'create', + component: () => import('@/views/perms/RemoteAppPermission/RemoteAppPermissionCreateUpdate'), + name: 'RemoteAppPermissionCreate', + hidden: true, + meta: { title: i18n.t('route.RemoteAppPermissionCreate'), activeMenu: '/perms/remote-app-permissions', action: 'create' } + }, + { + path: 'update', + component: () => import('@/views/perms/RemoteAppPermission/RemoteAppPermissionCreateUpdate'), + name: 'RemoteAppPermissionUpdate', + hidden: true, + meta: { title: i18n.t('route.RemoteAppPermissionUpdate'), activeMenu: '/perms/remote-app-permissions', action: 'update' } + }, + { + path: ':id', + component: () => import('@/views/perms/RemoteAppPermission/RemoteAppPermissionDetail/index'), + name: 'RemoteAppPermissionDetail', + hidden: true, + meta: { title: i18n.t('route.RemoteAppPermissionDetail'), activeMenu: '/perms/remote-app-permissions' } + }] } + ] const databasePermissionRoutes = [ diff --git a/src/router/sessions.js b/src/router/sessions.js index 1d793158b..07f276393 100644 --- a/src/router/sessions.js +++ b/src/router/sessions.js @@ -1,5 +1,6 @@ import i18n from '@/i18n/i18n' import rolec from '@/utils/role' +import empty from '@/layout/empty' export default [ { path: 'session', @@ -34,57 +35,65 @@ export default [ }, { path: 'terminal', - name: 'TerminalList', - component: () => import('@/views/sessions/TerminalList'), - meta: { title: i18n.t('route.Terminal') } - }, - { - path: 'terminals/:id', - name: 'TerminalDetail', - component: () => import('@/views/sessions/TerminalDetail'), - meta: { title: i18n.t('route.Terminal'), activeMenu: '/terminal/terminal' }, - hidden: true - }, - { - path: 'terminals/:id/update', - name: 'TerminalUpdate', - component: () => import('@/views/sessions/TerminalUpdate'), - meta: { title: i18n.t('route.Terminal'), activeMenu: '/terminal/terminal' }, - hidden: true + component: empty, + redirect: '', + meta: { title: i18n.t('route.Terminal'), permissions: [rolec.PERM_SUPER] }, + children: [ + { + path: '', + name: 'TerminalList', + component: () => import('@/views/sessions/TerminalList'), + meta: { title: i18n.t('route.Terminal') } + }, + { + path: ':id', + name: 'TerminalDetail', + component: () => import('@/views/sessions/TerminalDetail'), + meta: { title: i18n.t('route.Terminal'), activeMenu: '/terminal/terminal' }, + hidden: true + }, + { + path: ':id/update', + name: 'TerminalUpdate', + component: () => import('@/views/sessions/TerminalUpdate'), + meta: { title: i18n.t('route.Terminal'), activeMenu: '/terminal/terminal' }, + hidden: true + } + ] }, { path: 'storages', name: 'Storage', component: () => import('@/views/sessions/Storage/index'), - meta: { activeMenu: '/terminal/terminal' }, + meta: { activeMenu: '/terminal/terminal', permissions: [rolec.PERM_SUPER] }, hidden: true }, { path: 'replay-storage/create', name: 'CreateReplayStorage', component: () => import('@/views/sessions/ReplayStorageCreateUpdate'), - meta: { title: i18n.t('route.CreateReplayStorage'), activeMenu: '/terminal/terminal' }, + meta: { title: i18n.t('route.CreateReplayStorage'), activeMenu: '/terminal/terminal', permissions: [rolec.PERM_SUPER] }, hidden: true }, { path: 'command-storage/create', name: 'CreateCommandStorage', component: () => import('@/views/sessions/CommandStorageCreateUpdate'), - meta: { title: i18n.t('route.CreateCommandStorage'), activeMenu: '/terminal/terminal' }, + meta: { title: i18n.t('route.CreateCommandStorage'), activeMenu: '/terminal/terminal', permissions: [rolec.PERM_SUPER] }, hidden: true }, { path: 'replay-storage/:id/update', name: 'ReplayStorageUpdate', component: () => import('@/views/sessions/ReplayStorageCreateUpdate'), - meta: { title: i18n.t('route.ReplayStorageUpdate'), activeMenu: '/terminal/terminal' }, + meta: { title: i18n.t('route.ReplayStorageUpdate'), activeMenu: '/terminal/terminal', permissions: [rolec.PERM_SUPER] }, hidden: true }, { path: 'command-storage/:id/update', name: 'CommandStorageUpdate', component: () => import('@/views/sessions/CommandStorageCreateUpdate'), - meta: { title: i18n.t('route.CommandStorageUpdate'), activeMenu: '/terminal/terminal' }, + meta: { title: i18n.t('route.CommandStorageUpdate'), activeMenu: '/terminal/terminal', permissions: [rolec.PERM_SUPER] }, hidden: true } ] diff --git a/src/router/userPage.js b/src/router/userPage.js index c5fcd6d04..9364c32ff 100644 --- a/src/router/userPage.js +++ b/src/router/userPage.js @@ -33,13 +33,14 @@ export default [ name: 'Apps', component: Layout, redirect: '/apps/remoteapp', + alwaysShow: true, meta: { title: i18n.t('route.MyApps'), icon: 'th', permissions: [rolec.PERM_USE] }, children: [ { path: '/apps/remoteapp', name: 'MyRemoteApps', component: () => import('@/userviews/apps/RemoteApp'), - meta: { title: i18n.t('route.RemoteApp'), permissions: [rolec.PERM_USE] } + meta: { title: i18n.t('route.RemoteApp'), permissions: [rolec.PERM_USE], licenseRequired: true } }, { path: '/apps/database', diff --git a/src/store/modules/permission.js b/src/store/modules/permission.js index c698b84f2..c78ee4772 100644 --- a/src/store/modules/permission.js +++ b/src/store/modules/permission.js @@ -28,15 +28,16 @@ function hasLicense(licState, route) { return licState === requireLic } -function hasCommand(cmdState, route) { - if (cmdState) { - return cmdState +function hasCommand(cmdBulkExecutionEnable, route) { + const routeRequireCmd = route.meta ? route.meta.commandExecutionRequired : false + if (!routeRequireCmd) { + return true } - let requireCmd = route.meta ? route.meta.commandExecutionRequired : null - if (!requireCmd) { - requireCmd = false + + if (!cmdBulkExecutionEnable) { + return false } - return cmdState === requireCmd + return true } export function filterLicRoutes(routes, roles) { @@ -113,10 +114,12 @@ const mutations = { const actions = { generateRoutes({ commit, rootState }, roles) { return new Promise(resolve => { - console.log(rootState) let accessedRoutes = filterAsyncRoutes(allRoleRoutes, roles) accessedRoutes = filterCmdRoutes(accessedRoutes, rootState.settings.publicSettings.SECURITY_COMMAND_EXECUTION) - accessedRoutes = filterLicRoutes(accessedRoutes, rootState.settings.publicSettings.XPACK_ENABLED) + accessedRoutes = filterLicRoutes(accessedRoutes, rootState.settings.publicSettings.XPACK_LICENSE_IS_VALID) + if (accessedRoutes.length === 0) { + console.log('No route find') + } commit('SET_ROUTES', accessedRoutes) resolve(accessedRoutes) }) diff --git a/src/utils/request.js b/src/utils/request.js index e7c659292..ad84f60c2 100644 --- a/src/utils/request.js +++ b/src/utils/request.js @@ -49,7 +49,7 @@ service.interceptors.request.use( ) function ifUnauthorized({ response, error }) { - if (response.status === 401 && response.request.url.indexOf('/users/profile') !== -1) { + if (response.status === 401 && response.request.responseURL.indexOf('/users/profile') === -1) { response.config.disableFlashErrorMsg = true // 未授权重定向到登录页面 const title = i18n.t('common.Info') diff --git a/src/views/sessions/SessionDetail/SessionDetailCard.vue b/src/views/sessions/SessionDetail/SessionDetailCard.vue index 45cff80f1..41667262f 100644 --- a/src/views/sessions/SessionDetail/SessionDetailCard.vue +++ b/src/views/sessions/SessionDetail/SessionDetailCard.vue @@ -103,7 +103,7 @@ export default { window.open(replayUrl) }, openReplayDownload: function(id) { - const downloadUrl = '/api/v1/terminal/session/00000000-0000-0000-0000-000000000000/replay/download/' + const downloadUrl = '/api/v1/terminal/sessions/00000000-0000-0000-0000-000000000000/replay/download/' .replace('00000000-0000-0000-0000-000000000000', id) window.open(downloadUrl) } diff --git a/src/views/settings/index.vue b/src/views/settings/index.vue index fbc1124f5..d46438d28 100644 --- a/src/views/settings/index.vue +++ b/src/views/settings/index.vue @@ -130,13 +130,58 @@ export default { } }, basicData(data) { - return data.basic + const basic = data.basic + if (basic.SITE_URL === null) { + basic.SITE_URL = '' + } + if (basic.EMAIL_SUBJECT_PREFIX === null) { + basic.EMAIL_SUBJECT_PREFIX = '' + } + if (basic.USER_GUIDE_URL === null) { + basic.USER_GUIDE_URL = '' + } + return basic }, emailData(data) { - return data.email + const email = data.email + if (email.EMAIL_FROM === null) { + email.EMAIL_FROM = '' + } + if (email.EMAIL_RECIPIENT === null) { + email.EMAIL_RECIPIENT = '' + } + if (email.EMAIL_USE_TLS === null) { + email.EMAIL_USE_TLS = false + } + if (email.EMAIL_HOST === null) { + email.EMAIL_HOST = '' + } + if (email.EMAIL_HOST_USER === null) { + email.EMAIL_HOST_USER = '' + } + if (email.EMAIL_PORT === null) { + email.EMAIL_PORT = '' + } + if (email.EMAIL_USE_SSL === null) { + email.EMAIL_USE_SSL = false + } + return email }, emailContentData(data) { - return data.email_content + const email_content = data.email_content + if (email_content.EMAIL_CUSTOM_USER_CREATED_BODY === null) { + email_content.EMAIL_CUSTOM_USER_CREATED_BODY = '' + } + if (email_content.EMAIL_CUSTOM_USER_CREATED_HONORIFIC === null) { + email_content.EMAIL_CUSTOM_USER_CREATED_HONORIFIC = '' + } + if (email_content.EMAIL_CUSTOM_USER_CREATED_SIGNATURE === null) { + email_content.EMAIL_CUSTOM_USER_CREATED_SIGNATURE = '' + } + if (email_content.EMAIL_CUSTOM_USER_CREATED_SUBJECT === null) { + email_content.EMAIL_CUSTOM_USER_CREATED_SUBJECT = '' + } + return email_content }, ldapData(data) { return data.ldap @@ -145,7 +190,11 @@ export default { return data.terminal }, securityData(data) { - return data.security + const security = data.security + if (security.SECURITY_COMMAND_EXECUTION === null) { + security.SECURITY_COMMAND_EXECUTION = false + } + return security } } } diff --git a/vue.config.js b/vue.config.js index b7990bf9d..bd8113b3e 100644 --- a/vue.config.js +++ b/vue.config.js @@ -29,7 +29,7 @@ module.exports = { /\/node_modules\/resize-detector\// ], publicPath: '/ui/', - outputDir: 'dist', + outputDir: 'lina', assetsDir: 'assets', lintOnSave: process.env.NODE_ENV === 'development', productionSourceMap: false,