content: package com.ctrip.framework.apollo.portal.spi.defaultimpl;
  
  import com.ctrip.framework.apollo.portal.component.config.PortalConfig;
  import com.ctrip.framework.apollo.portal.entity.bo.UserInfo;
  import com.ctrip.framework.apollo.portal.entity.po.Permission;
  import com.ctrip.framework.apollo.portal.entity.po.Role;
  import com.ctrip.framework.apollo.portal.entity.po.RolePermission;
  import com.ctrip.framework.apollo.portal.entity.po.UserRole;
  import com.ctrip.framework.apollo.portal.repository.PermissionRepository;
  import com.ctrip.framework.apollo.portal.repository.RolePermissionRepository;
  import com.ctrip.framework.apollo.portal.repository.RoleRepository;
  import com.ctrip.framework.apollo.portal.repository.UserRoleRepository;
  import com.ctrip.framework.apollo.portal.service.RolePermissionService;
  import com.google.common.base.Preconditions;
  import com.google.common.collect.FluentIterable;
  import com.google.common.collect.HashMultimap;
  import com.google.common.collect.Multimap;
  import com.google.common.collect.Sets;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.transaction.annotation.Transactional;
  import org.springframework.util.CollectionUtils;
  
  import java.util.*;
  
  /**
   * Created by timothy on 2017/4/26.
   */
  public class DefaultRolePermissionService implements RolePermissionService {
      @Autowired
      private RoleRepository roleRepository;
      @Autowired
      private RolePermissionRepository rolePermissionRepository;
      @Autowired
      private UserRoleRepository userRoleRepository;
      @Autowired
      private PermissionRepository permissionRepository;
      @Autowired
      private PortalConfig portalConfig;
  
  
      /**
       * Create role with permissions, note that role name should be unique
       */
      @Transactional
      public Role createRoleWithPermissions(Role role, Set<Long> permissionIds) {
          Role current = findRoleByRoleName(role.getRoleName());
          Preconditions.checkState(current == null, "Role %s already exists!", role.getRoleName());
  
          Role createdRole = roleRepository.save(role);
  
          if (!CollectionUtils.isEmpty(permissionIds)) {
              Iterable<RolePermission> rolePermissions = FluentIterable.from(permissionIds).transform(
                      permissionId -> {
                          RolePermission rolePermission = new RolePermission();
                          rolePermission.setRoleId(createdRole.getId());
                          rolePermission.setPermissionId(permissionId);
                          rolePermission.setDataChangeCreatedBy(createdRole.getDataChangeCreatedBy());
                          rolePermission.setDataChangeLastModifiedBy(createdRole.getDataChangeLastModifiedBy());
                          return rolePermission;
                      });
              rolePermissionRepository.save(rolePermissions);
          }
  
          return createdRole;
      }
  
      /**
       * Assign role to users
       *
       * @return the users assigned roles
       */
      @Transactional
      public Set<String> assignRoleToUsers(String roleName, Set<String> userIds,
                                           String operatorUserId) {
          Role role = findRoleByRoleName(roleName);
          Preconditions.checkState(role != null, "Role %s doesn't exist!", roleName);
  
          List<UserRole> existedUserRoles =
                  userRoleRepository.findByUserIdInAndRoleId(userIds, role.getId());
          Set<String> existedUserIds =
                  FluentIterable.from(existedUserRoles).transform(userRole -> userRole.getUserId()).toSet();
  
          Set<String> toAssignUserIds = Sets.difference(userIds, existedUserIds);
  
          Iterable<UserRole> toCreate = FluentIterable.from(toAssignUserIds).transform(userId -> {
              UserRole userRole = new UserRole();
              userRole.setRoleId(role.getId());
              userRole.setUserId(userId);
              userRole.setDataChangeCreatedBy(operatorUserId);
              userRole.setDataChangeLastModifiedBy(operatorUserId);
              return userRole;
          });
  
          userRoleRepository.save(toCreate);
          return toAssignUserIds;
      }
  
      /**
       * Remove role from users
       */
      @Transactional
      public void removeRoleFromUsers(String roleName, Set<String> userIds, String operatorUserId) {
          Role role = findRoleByRoleName(roleName);
          Preconditions.checkState(role != null, "Role %s doesn't exist!", roleName);
  
          List<UserRole> existedUserRoles =
                  userRoleRepository.findByUserIdInAndRoleId(userIds, role.getId());
  
          for (UserRole userRole : existedUserRoles) {
              userRole.setDeleted(true);
              userRole.setDataChangeLastModifiedTime(new Date());
              userRole.setDataChangeLastModifiedBy(operatorUserId);
          }
  
          userRoleRepository.save(existedUserRoles);
      }
  
      /**
       * Query users with role
       */
      public Set<UserInfo> queryUsersWithRole(String roleName) {
          Role role = findRoleByRoleName(roleName);
  
          if (role == null) {
              return Collections.emptySet();
          }
  
          List<UserRole> userRoles = userRoleRepository.findByRoleId(role.getId());
  
          Set<UserInfo> users = FluentIterable.from(userRoles).transform(userRole -> {
              UserInfo userInfo = new UserInfo();
              userInfo.setUserId(userRole.getUserId());
              return userInfo;
          }).toSet();
  
          return users;
      }
  
      /**
       * Find role by role name, note that roleName should be unique
       */
      public Role findRoleByRoleName(String roleName) {
          return roleRepository.findTopByRoleName(roleName);
      }
  
      /**
       * Check whether user has the permission
       */
      public boolean userHasPermission(String userId, String permissionType, String targetId) {
          Permission permission =
                  permissionRepository.findTopByPermissionTypeAndTargetId(permissionType, targetId);
          if (permission == null) {
              return false;
          }
  
          if (isSuperAdmin(userId)) {
              return true;
          }
  
          List<UserRole> userRoles = userRoleRepository.findByUserId(userId);
          if (CollectionUtils.isEmpty(userRoles)) {
              return false;
          }
  
          Set<Long> roleIds =
                  FluentIterable.from(userRoles).transform(userRole -> userRole.getRoleId()).toSet();
          List<RolePermission> rolePermissions = rolePermissionRepository.findByRoleIdIn(roleIds);
          if (CollectionUtils.isEmpty(rolePermissions)) {
              return false;
          }
  
          for (RolePermission rolePermission : rolePermissions) {
              if (rolePermission.getPermissionId() == permission.getId()) {
                  return true;
              }
          }
  
          return false;
      }
  
      public boolean isSuperAdmin(String userId) {
          return portalConfig.superAdmins().contains(userId);
      }
  
      /**
       * Create permission, note that permissionType + targetId should be unique
       */
      @Transactional
      public Permission createPermission(Permission permission) {
          String permissionType = permission.getPermissionType();
          String targetId = permission.getTargetId();
          Permission current =
                  permissionRepository.findTopByPermissionTypeAndTargetId(permissionType, targetId);
          Preconditions.checkState(current == null,
                  "Permission with permissionType %s targetId %s already exists!", permissionType, targetId);
  
          return permissionRepository.save(permission);
      }
  
      /**
       * Create permissions, note that permissionType + targetId should be unique
       */
      @Transactional
      public Set<Permission> createPermissions(Set<Permission> permissions) {
          Multimap<String, String> targetIdPermissionTypes = HashMultimap.create();
          for (Permission permission : permissions) {
              targetIdPermissionTypes.put(permission.getTargetId(), permission.getPermissionType());
          }
  
          for (String targetId : targetIdPermissionTypes.keySet()) {
              Collection<String> permissionTypes = targetIdPermissionTypes.get(targetId);
              List<Permission> current =
                      permissionRepository.findByPermissionTypeInAndTargetId(permissionTypes, targetId);
              Preconditions.checkState(CollectionUtils.isEmpty(current),
                      "Permission with permissionType %s targetId %s already exists!", permissionTypes,
                      targetId);
          }
  
          Iterable<Permission> results = permissionRepository.save(permissions);
          return FluentIterable.from(results).toSet();
      }
  
  }
  