<?php
/**
 * @link      http://www.u-bo.com
 * @copyright 南京友博网络科技有限公司 
 * @license   http://www.u-bo.com/license/
 */

namespace qcbase\models;

use Yii;
use yii\db\Query;
use common\components\Tree;
use common\models\PermissionScope;

/**
 * This is the model class for table "{{%auth_item}}".
 *
 * 角色权限操作
 *
 * @property string $name  (授权项目)
 * @property integer $type  (授权类型 1为角色 2为权限项目)
 * @property text $description  (描述)
 * @property string $rule_name  (额外规则名称)
 * @property text $data  (规则数据)
 * @property integer $created_at  (新增时间)
 * @property integer $updated_at  (更新时间)
 *
 * @author hulimin http://blog.u-bo.com
 * @since 0.1
 */
class Auth extends \yii\db\ActiveRecord
{

    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return '{{%auth_item}}';
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['name', 'type'], 'required'],
            ['name', 'unique'],
            [['type', 'created_at', 'updated_at'], 'integer'],
            [['description', 'data'], 'string'],
            [['name', 'rule_name'], 'string', 'max' => 64]
        ];
    }

    /**
     * @inheritdoc
     */
    public function attributeLabels()
    {
        return [
            'name' => '名称',
            'type' => '类型', // 1为角色 2为权限项目
            'description' => '描述',
            'rule_name' => '额外规则名称',
            'data' => '规则数据',
            'created_at' => '新增时间',
            'updated_at' => '更新时间',
        ];
    }

    /**
     * 公共搜索所需信息
     */
    public function search()
    {
        return [
            'name' => '角色名称',
        ];
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getAuthAssignments()
    {
        return $this->hasMany(AuthAssignment::className(), ['item_name' => 'name']);
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getRuleName()
    {
        return $this->hasOne(AuthRule::className(), ['name' => 'rule_name']);
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getAuthItemChildren()
    {
        return $this->hasMany(AuthItemChild::className(), ['child' => 'name']);
    }

    /**
     * 获取所有的角色
     *
     * @return type
     */
    public static function getRoles($name = '')
    {
        $authManager = Yii::$app->authManager;
        $query = new Query();
        $query = $query
            ->from($authManager->itemTable . 'as item')
            ->select('item.* , itemChild.parent')
            ->where(['type' => \yii\rbac\Item::TYPE_ROLE])
            ->orderBy(['created_at' => SORT_ASC]);
        if (!empty($name)) {
            $query->andWhere(['item.name' => $name]);
        }
        $roles = $query
            ->leftJoin($authManager->itemChildTable . 'as itemChild', 'item.name = itemChild.child')
            ->all();
        return $roles;
    }

    /**
     * 获取角色checkbox所用列表
     *
     * @return type
     */
    public static function getBoxRoleList()
    {
        $roles = self::getRoles();
        $list = [];
        foreach ($roles as $role) {
            $list[$role['name']] = $role['name'];
        }
        return $list;
    }

    /**
     * 获取角色下拉列表
     */
    public static function getDropDownRoleList($needTop = false)
    {
        $list = [];
        $rows = self::getRoleList();
        //\common\components\Tool::dump($rows);
        $needTop && $list[''] = '----顶级角色----';
        foreach ($rows as $row) {
            $list[$row['name']] = str_replace('&nbsp;', ' ', $row['tree_spacer']) . $row['name'];
        }
        return $list;
    }

    public static function getRoleList()
    {
        $roles = self::getRoles();
        $roles = Tree::getList($roles, 'name', 'parent', '_child', null);
        //\common\components\Tool::dump($roles);

        return $roles;
    }

    /**
     * 分配角色
     * @param type $userId 用户id
     * @param type $roles 所有角色
     */
    public static function assignRole($userId, $roles)
    {
        $auth = Yii::$app->authManager;
        $auth->revokeAll($userId);
        foreach ($roles as $role) {
            $role = $auth->createRole($role);
            $auth->assign($role, $userId);
        }
    }

    public static function getRolesByUser($userId)
    {
        $auth = Yii::$app->authManager;
        return $auth->getRolesByUser($userId);
    }

    /**
     * 获取用户菜单
     *
     * @param type $userId 用户ID
     */
    public static function getAuthMenuByUser($userId = 0)
    {
        $roles = [];
        $userId = empty($userId) ? Yii::$app->user->id : $userId;
        $userRoles = static::getRolesByUser($userId);
        if (!empty($userRoles)) {
            $roleArr = [];
            foreach ($userRoles as $role) {
                $roleArr[] = $role->name;
            }
            if (!empty($roleArr)) {
//获取用户角色权限节点
                $roles = (new Query())
                    ->select('child')
                    ->from(Yii::$app->authManager->itemChildTable)
                    ->where(['in', 'parent', $roleArr])
                    ->createCommand()
                    ->queryColumn();
            }
        }
        return $roles;
    }

    /**
     *
     * @param type $url  权限节点 如：admin/Index/index
     * @param $description 节点描述
     * @param type $type 1新建或更新 2删除
     * @param type $name 需要更新的节点
     */
    public function authItem($url = '', $description = '', $type = 1, $name = '')
    {
        $auth = Yii::$app->authManager;
        $createAuth = $auth->createPermission($url);
        $createAuth->description = $description;
        $result = true;
        switch ($type) {
            case 1:
                $authByName = $auth->getPermission($name);
                if (!empty($authByName)) {
                    $result = $auth->update($name, $createAuth);
                } else {
                    $authByUrl = $auth->getPermission($url);
                    if (empty($authByUrl)) {
                        $result = $auth->add($createAuth);
                    }
                }
                break;
            case 2:
                $result = $auth->remove($createAuth);
                break;
        }
        return $result;
    }

    /**
     * 新建或更新角色
     *
     * @param type $insert  true新建 false 更新
     * @param type $dataRole 提交的数据
     * @param type $name 更新的角色名
     */
    public function createRole($insert = TRUE, $dataRole, $name = [])
    {
        $auth = Yii::$app->authManager;
        $authName = $dataRole['name'];
        $createRole = $auth->createRole($authName);
        $createRole->description = $dataRole['description'];
        //获取父级角色
        $parentRole = (empty($dataRole['parent'])) ? null : $auth->getRole($dataRole['parent']);

        $result = true;
        if ($insert) {
            $result = $auth->add($createRole);
            //复制角色权限
            if ($result && !empty($dataRole['copy_role'])) {
                self::copyRole($dataRole['copy_role'], $authName);
            }
            if ($parentRole !== null) {
                $auth->addChild($parentRole, $createRole);
            }
        } else {
            $result = $auth->update($name, $createRole);
            if ($dataRole['old_parent'] != $dataRole['parent']) {

                if (($oldParentRole = $auth->getRole($dataRole['old_parent'])) !== null) {
                    $auth->removeChild($oldParentRole, $createRole);
                }
                if ($parentRole !== null) {
                    $auth->addChild($parentRole, $createRole);
                }
            }
            //更新权限范围表
            if (isset($dataRole['old_role']) && $dataRole['old_role'] != $dataRole['name']) {
                Yii::$app->db->createCommand()->update(
                    PermissionScope::tableName(), ['role' => $dataRole['name']], 'role = :role', [':role' => $dataRole['old_role']]
                )->execute();
            }
        }


        return $result;
    }

    /**
     * 复制角色
     */
    public static function copyRole($sourceRole, $targetRole)
    {
        $auth = Yii::$app->authManager;
        $permissions = $auth->getPermissionsByRole($sourceRole);
        $targetRole = $auth->getRole($targetRole);
        //复制角色权限
        foreach ($permissions as $permission) {
            $permission = $auth->getPermission($permission->name);
            $permission !== null && $auth->addChild($targetRole, $permission);
        }
        //复制权限范围
        $scopes = PermissionScope::find()->where(['role' => $sourceRole])->all();
        foreach ($scopes as $scope) {
            $permissionScope = new PermissionScope();
            $permissionScope->role = $targetRole->name;
            $permissionScope->permission = $scope['permission'];
            $permissionScope->scope = $scope['scope'];
            $permissionScope->save();
        }
    }

    /**
     * 给角色授权
     * @property string $role (角色)
     * @property string $menuIds (包含菜单id)
     */
    public static function authRole($app_name, $role, $permissions)
    {
        set_time_limit(120);
        $roleInfo = self::getRoles($role);
        if (empty($roleInfo)) {
            return FALSE;
        }
        $appMenus = Menu::find()
            ->where(['app_name' => $app_name, 'is_auth' => 1])
            ->asArray()
            ->indexBy('auth_url')
            ->all();
        $appPermissions = array_unique(array_keys($appMenus));

        $newPermissions = array_unique($permissions);

        $auth = Yii::$app->authManager;
        //先删除角色对应应用下的所有权限
        $role = $auth->createRole($role);
        /*
          foreach ($appPermissions as $permission) {
          $permission = $auth->getPermission($permission);
          $permission !== null && $auth->removeChild($role, $permission);
          }
         */
        //由于使用authManager的removeChild接口太慢了，这里暂时用db处理
        Yii::$app->db->createCommand()
            ->delete($auth->itemChildTable, ['parent' => $role->name, 'child' => $appPermissions])
            ->execute();
        //\common\components\Tool::dump($newPermissions);
        //exit();
        //授权
        if (!empty($newPermissions)) {
            foreach ($newPermissions as $permission) {
                $permission = $auth->getPermission($permission);
                $permission !== null && $auth->addChild($role, $permission);
            }
        }
        return true;
    }

    /**
     * 检测用户指定操作的权限
     * @param type $url     操作URL
     * @param type $user_id 用户ID
     * @return boolean
     */
    public static function checkAccess($url = NULL, $user_id = 0)
    {
        $auth = Yii::$app->authManager;

        empty($user_id) ? $user_id = \Yii::$app->user->id : $user_id;

        if (empty($url) || empty($user_id)) {
            return FALSE;
        }
        //非超级管理员，需要检测权限
        if (Yii::$app->session->get('isSuperAdmin')) {
            return true;
        } else {
            return $auth->checkAccess($user_id, $url);
        }
    }

    /**
     * 授权权限范围
     *
     * @param string $app_name 应用名称
     * @param string $role 角色名称
     * @param array $permissions 给角色授权的权限
     * @param array $scopes 给角色授权的权限范围
     */
    public static function authScope($app_name, $role, $permissions, $scopes)
    {
        $auth = Yii::$app->authManager;
        $db = Yii::$app->db;
        $appMenus = Menu::find()
            ->where(['app_name' => $app_name, 'is_auth' => 1, 'show_scope' => 1])
            ->asArray()
            ->indexBy('auth_url')
            ->all();
        $appPermissions = array_unique(array_keys($appMenus));

        //先删除所有应用的权限范围
        $db->createCommand()
            ->delete('{{%role_permission_scope}}', ['role' => $role, 'permission' => $appPermissions])
            ->execute();

        //授权
        $data = [];
        if (!empty($scopes) && !empty($permissions)) {
            foreach ($scopes as $permission => $scope) {
                if (in_array($permission, $permissions)) {
                    $permission = $auth->getPermission($permission);
                    if ($permission !== null) {
                        $data[] = [$role, $permission->name, $scope];
                    }
                }
            }
            $db->createCommand()->batchInsert('{{%role_permission_scope}}', ['role', 'permission', 'scope'], $data)->execute();
        }
        return true;
    }

    /**
     * 检测菜单权限
     * 
     * @param type $menus  菜单
     * @param type $user_id  用户ID
     */
    public static function checkMenuAccess($menus = [], $user_id = 0)
    {
        if (!empty($menus)) {
            $user_id = empty($user_id) ? Yii::$app->user->identity->user_id : $user_id;
            foreach ($menus as $vo) {
                if (static::checkAccess($vo['auth_url'], $user_id)) {
                    return true;
                }
            }
        }
    }

    /**
     * 检测指定用户指定操作的权限
     * @param type $url     操作URL
     * @param type $user_id 用户ID
     * 
     * @return boolean
     *
     * @author Strief
     */
    public static function checkAccessById($url = NULL, $user_id = 0)
    {
        $roles = static::getRolesByUser($user_id);
        //判断指定用户是否是超级管理员
        if (array_key_exists(Yii::$app->params['auth']['superAdminRole'], $roles)) {
            return true;
        }

        //判断指定用户是否拥有某项操作权限
        $roleList = static::getAuthMenuByUser($user_id);
        if (in_array($url, $roleList)) {
            return true;
        }
        return false;
    }

    /**
     * 获取父级ID集
     */
    public static function getRoleTree()
    {
        $roles = self::getRoles();
        foreach ($roles as &$role) {
            $role['childs'] = self::getChilds($role['name'], $roles, true);
        }
        return $roles;
    }

    /**
     * 获取树子集
     */
    public static function getChilds($name, $roles, $clear = false)
    {
        static $childs = [];
        $childs = ($clear) ? [] : $childs;
        foreach ($roles as $role) {
            if ($role['parent'] == $name) {
                $childs[] = $role['name'];
                self::getChilds($role['name'], $roles);
            }
        }
        return $childs;
    }
}