import { Vue as VueConstructor } from 'vue-property-decorator' ; import { installFn } from './install' ; import { assert } from './util' ; import extend from 'lodash/extend' ; import pick from 'lodash/pick' ; import get from 'lodash/get' ; import map from 'lodash/map' ; import flatten from 'lodash/flatten' ; import uniqueId from 'lodash/uniqueId' ; import AccessOptions from './types/AccessOptions' ; import ApplyMixin from './mixin' ; import { User } from '@lywzx/access.control' ; import { AbilityOptions , MapKeyStringValueBoolean , RoleAndOwnsOptions , RoleTypes , StringOrStringArray , } from '@lywzx/access.control/dist/typings/types/Types' ; import { PostTypes as Post } from '@lywzx/access.control/dist/typings/types/PostTypes' ; import { getRole , standardize } from '@lywzx/access.control' ; import AccessConstructorOptions from './types/AccessConstructorOptions' ; import RouterMiddleware from './router/RouterMiddleware' ; import AccessVmData from './types/AccessVmData' ; import AccessUserOptions from './types/AccessUserOptions' ; import LoginMiddleware from './router/middle/LoginMiddleware' ; import AccessRoleMiddleware from './router/middle/AccessRoleMiddleware' ; import { RawLocation , Route , VueRouter } from 'vue-router/types/router' ; const createUniqueId = ( ) => uniqueId ( 'vue.access.control-' ) ; let Vue ; export class Access { /**
     * a vue instance
     */ public _vm : VueConstructor ; /**
     *
     */ public get key ( ) { return this . accessData . key ; } /**
     *
     */ protected options : AccessOptions ; type AccessOptions public static defaultOptions : AccessOptions = { foreignKeyName : 'user_id' , notLoginRoleName : 'Guest' , vueRouter : false , globalMiddleware : [ ] , } ; /**
     *
     */ public accessData : AccessVmData ; /**
     * router middleware
     */ public accessRouterMiddleware ? : RouterMiddleware ; param options public constructor ( options ) { let g = global as Partial < { Vue : typeof VueConstructor ; } > ; if ( ! Vue && typeof g !== 'undefined' && g . Vue ) { install ( g . Vue ) ; } if ( process . env . NODE_ENV !== 'production' ) { assert ( ! ! Vue , 'must call Vue.use(VueAccessControl) before creating a Access instance.' ) ; } const { notLoginRoleName } = ( this . options = extend ( { } , Access . defaultOptions ) ) ; this . accessData = extend ( Object . create ( null ) , { key : createUniqueId ( ) , userOptions : { roles : [ { role : notLoginRoleName , } , ] , permissions : [ ] , userId : undefined , isLogin : undefined , } , extendData : { } , } ) as AccessVmData ; this . _vm = resetUserInfoVm ( this , this . accessData ) ; if ( Access . defaultOptions . vueRouter ) { this . accessRouterMiddleware = new RouterMiddleware ( this , { routes : options . routes || [ ] , } ) ; } } param { RoleTypes } role param { string [ ] } permission public setRole ( role , permission ? ) { let newRoles = getRole ( role , permission ) ; if ( newRoles . length <= 1 && typeof role === 'string' && permission ) { this . accessData . userOptions . permissions = permission ; } this . accessData . userOptions . roles = newRoles ; } param { RoleTypes } role param { string [ ] } permission public appendRole ( role , permission ? ) { let oldRoles = this . accessData . userOptions . roles ; let newRole = getRole ( role , permission ) ; this . accessData . userOptions . roles = oldRoles . concat ( newRole ) ; if ( newRole . length <= 1 && typeof role === 'string' && permission ) { this . accessData . userOptions . permissions = permission ; } } param { string | string [ ] } permissions public setPermission ( permissions ) { this . accessData . userOptions . permissions = standardize ( permissions ) ; } param { string | string [ ] } permissions public appendPermission ( permissions ) { this . accessData . userOptions . permissions = this . accessData . userOptions . permissions . concat ( standardize ( permissions ) ) ; } param { Post } post param { string } key returns { boolean } public owns ( post , key = 'user_id' ) { let user = this . getUser ( ) ; if ( user ) { return user . owns ( post , key ) ; } return false ; } param { StringOrStringArray } role param { boolean } requiredAll returns { boolean } public hasRole ( role , requiredAll = false ) { let user = this . getUser ( ) ; if ( user ) { return user . hasRole ( role , requiredAll ) ; } return false ; } param { string | string [ ] } permission param { boolean } requiredAll returns { boolean } public can ( permission , requiredAll = false ) { let user = this . getUser ( ) ; if ( user ) { return user . can ( permission , requiredAll ) ; } return false ; } param { string | string [ ] } permission param { boolean } requiredAll returns { boolean } public hasPermission ( permission , requiredAll = false ) { return this . can ( permission , requiredAll ) ; } param { string | string [ ] } permission param { boolean } requiredAll returns { boolean } public isAbleTo ( permission , requiredAll = false ) { return this . can ( permission , requiredAll ) ; } param router param to param current param append public isCanTo ( router , to , current ? , append = false ) { const resolvedRoute = router . resolve ( to , current , append ) ; const matched = resolvedRoute . route . matched ; const middleware = flatten ( map ( matched , it => get ( it , 'meta.middleware' , [ ] ) ) ) ; const accessRouterMiddleware = this . accessRouterMiddleware ; assert ( ! ! accessRouterMiddleware , 'the method isCanTo can be called when useRouter is true' ) ; return new Promise ( ( resolve , reject ) => { ( accessRouterMiddleware as RouterMiddleware ) . runMiddleware ( { middleware : middleware , next : ( result ) => { resolve ( result === undefined || result === true ) ; } , terminal : true , } , router , resolvedRoute . route , current ) ; } ) ; } param { StringOrStringArray } permissions param { Post } post param { RoleAndOwnsOptions } options returns { boolean } public canAndOwns ( permissions , post , options = { requireAll : false , foreignKeyName : 'user_id' , } ) { let user = this . getUser ( ) ; if ( user ) { return user . canAndOwns ( permissions , post , options ) ; } return false ; } param { StringOrStringArray } roles param { StringOrStringArray } permissions param { AbilityOptions } options returns { boolean | { validateAll ? : boolean ; roles : MapKeyStringValueBoolean ; permissions : MapKeyStringValueBoolean } } public ability ( roles , permissions , options = { validateAll : false , returnType : 'both' , } ) { let user = this . getUser ( ) ; if ( user ) { return user . ability ( roles , permissions , options ) ; } return false ; } /**
     * user is login
     */ public isLogin ( ) { return this . accessData . userOptions . isLogin ; } param { string } event param args returns { this } public $emit ( event , ... args ) { this . _vm . $emit ( event , ... args ) ; return this ; } param { string | string [ ] } event param { Function } callback returns { this } public $on ( event , callback ) { this . _vm . $on ( event , callback ) ; return this ; } param { string | string [ ] } event param { Function } callback returns { this } public $once ( event , callback ) { this . _vm . $on ( event , callback ) ; return this ; } param { string | string [ ] } event param { Function } callback returns { this } public $off ( event ? , callback ? ) { this . _vm . $off ( event , callback ) ; return this ; } returns { boolean | User } private getUser ( ) { let _vm = this . _vm ; if ( _vm && _vm . user ) { return _vm . user as User ; } return false ; } param obj public setExtendInfo ( obj ) { this . accessData . extendData = extend ( { } , this . accessData . extendData , obj ) ; return this ; } /**
     * get extend info from extend data
     */ public getExtendInfo ( key ? ) { if ( key ) { return get ( this . accessData . extendData , key ) ; } return this . accessData . extendData ; } param accessInfo public setLoginUserInfo ( accessInfo ) { let info = pick ( accessInfo , [ 'roles' , 'permissions' , 'userId' , 'isLogin' ] ) ; extend ( this . accessData . userOptions , info ) ; return this ; } /**
     * reset login status
     */ public reset ( ) { this . setLoginUserInfo ( { roles : [ Access . defaultOptions . notLoginRoleName ] , permissions : [ ] , userId : undefined , isLogin : undefined , } ) ; return this ; } } param { Access } access param { AccessUserOptions } accessVmData returns { Vue } function resetUserInfoVm ( access , accessVmData ) { const silent = Vue . config . silent ; Vue . config . silent = true ; let vm = new Vue ( { data : { access : accessVmData , user : undefined , } as { access : AccessVmData ; user ? : User ; } , watch : { 'access.userOptions' : { handler ( current , last ? ) { this . user = new User ( current . roles , current . permissions , current . userId ) ; this . access . key = createUniqueId ( ) ; } , deep : true , } , } , created ( ) { this . user = new User ( accessVmData . userOptions . roles , accessVmData . userOptions . permissions , accessVmData . userOptions . userId ) ; } , } ) ; Vue . config . silent = silent ; return vm ; } param { typeof VueConstructor } _Vue param Options export const install = function ( _Vue , Options ? ) { if ( Vue && Vue === _Vue ) { if ( process . env . NODE_ENV !== 'production' ) { console . error ( '[vue.access.control] already installed. Vue.use(VueAccessControl) should be called only once.' ) ; } return ; } Vue = _Vue ; if ( Options ) { extend ( Access . defaultOptions , Options ) ; } if ( Access . defaultOptions . globalMiddleware ) { RouterMiddleware . setGlobalMiddleWares ( Access . defaultOptions . globalMiddleware ) ; } if ( Access . defaultOptions . loginRoute ) { LoginMiddleware . loginName = Access . defaultOptions . loginRoute ; } if ( Access . defaultOptions . defaultRoute ) { LoginMiddleware . defaultRoute = Access . defaultOptions . defaultRoute ; } if ( Access . defaultOptions . permissionDenyRedirectRoute ) { AccessRoleMiddleware . permissionDenyRedirectRoute = Access . defaultOptions . permissionDenyRedirectRoute ; } ApplyMixin ( Vue ) ; installFn ( Vue , Access . defaultOptions . vueRouter ) ; } ;