content: package org.ruoyi.helper;
  
  import cn.dev33.satoken.context.SaHolder;
  import cn.dev33.satoken.context.model.SaStorage;
  import cn.hutool.core.collection.CollectionUtil;
  import cn.hutool.core.util.ObjectUtil;
  import com.baomidou.mybatisplus.core.plugins.IgnoreStrategy;
  import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
  import lombok.AccessLevel;
  import lombok.NoArgsConstructor;
  import org.ruoyi.annotation.DataPermission;
  import org.ruoyi.common.core.utils.reflect.ReflectUtils;
  
  import java.util.HashMap;
  import java.util.Map;
  import java.util.Stack;
  import java.util.function.Supplier;
  
  /**
   * 数据权限助手
   *
   * @author Lion Li
   * @version 3.5.0
   */
  @NoArgsConstructor(access = AccessLevel.PRIVATE)
  @SuppressWarnings("unchecked cast")
  public class DataPermissionHelper {
  
      private static final String DATA_PERMISSION_KEY = "data:permission";
  
      private static final ThreadLocal<Stack<Integer>> REENTRANT_IGNORE = ThreadLocal.withInitial(Stack::new);
  
      private static final ThreadLocal<DataPermission> PERMISSION_CACHE = new ThreadLocal<>();
  
      /**
       * 获取当前执行mapper权限注解
       *
       * @return 返回当前执行mapper权限注解
       */
      public static DataPermission getPermission() {
          return PERMISSION_CACHE.get();
      }
  
      /**
       * 设置当前执行mapper权限注解
       *
       * @param dataPermission   数据权限注解
       */
      public static void setPermission(DataPermission dataPermission) {
          PERMISSION_CACHE.set(dataPermission);
      }
  
      /**
       * 删除当前执行mapper权限注解
       */
      public static void removePermission() {
          PERMISSION_CACHE.remove();
      }
  
      /**
       * 从上下文中获取指定键的变量值，并将其转换为指定的类型
       *
       * @param key 变量的键
       * @param <T> 变量值的类型
       * @return 指定键的变量值，如果不存在则返回 null
       */
      public static <T> T getVariable(String key) {
          Map<String, Object> context = getContext();
          return (T) context.get(key);
      }
  
      /**
       * 向上下文中设置指定键的变量值
       *
       * @param key   要设置的变量的键
       * @param value 要设置的变量值
       */
      public static void setVariable(String key, Object value) {
          Map<String, Object> context = getContext();
          context.put(key, value);
      }
  
      /**
       * 获取数据权限上下文
       *
       * @return 存储在SaStorage中的Map对象，用于存储数据权限相关的上下文信息
       * @throws NullPointerException 如果数据权限上下文类型异常，则抛出NullPointerException
       */
      public static Map<String, Object> getContext() {
          SaStorage saStorage = SaHolder.getStorage();
          Object attribute = saStorage.get(DATA_PERMISSION_KEY);
          if (ObjectUtil.isNull(attribute)) {
              saStorage.set(DATA_PERMISSION_KEY, new HashMap<>());
              attribute = saStorage.get(DATA_PERMISSION_KEY);
          }
          if (attribute instanceof Map map) {
              return map;
          }
          throw new NullPointerException("data permission context type exception");
      }
  
      private static IgnoreStrategy getIgnoreStrategy() {
          Object ignoreStrategyLocal = ReflectUtils.getStaticFieldValue(ReflectUtils.getField(InterceptorIgnoreHelper.class, "IGNORE_STRATEGY_LOCAL"));
          if (ignoreStrategyLocal instanceof ThreadLocal<?> IGNORE_STRATEGY_LOCAL) {
              if (IGNORE_STRATEGY_LOCAL.get() instanceof IgnoreStrategy ignoreStrategy) {
                  return ignoreStrategy;
              }
          }
          return null;
      }
  
      /**
       * 开启忽略数据权限(开启后需手动调用 {@link #disableIgnore()} 关闭)
       */
      public static void enableIgnore() {
          IgnoreStrategy ignoreStrategy = getIgnoreStrategy();
          if (ObjectUtil.isNull(ignoreStrategy)) {
              InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().dataPermission(true).build());
          } else {
              ignoreStrategy.setDataPermission(true);
          }
          Stack<Integer> reentrantStack = REENTRANT_IGNORE.get();
          reentrantStack.push(reentrantStack.size() + 1);
      }
  
      /**
       * 关闭忽略数据权限
       */
      public static void disableIgnore() {
          IgnoreStrategy ignoreStrategy = getIgnoreStrategy();
          if (ObjectUtil.isNotNull(ignoreStrategy)) {
              boolean noOtherIgnoreStrategy = !Boolean.TRUE.equals(ignoreStrategy.getDynamicTableName())
                  && !Boolean.TRUE.equals(ignoreStrategy.getBlockAttack())
                  && !Boolean.TRUE.equals(ignoreStrategy.getIllegalSql())
                  && !Boolean.TRUE.equals(ignoreStrategy.getTenantLine())
                  && CollectionUtil.isEmpty(ignoreStrategy.getOthers());
              Stack<Integer> reentrantStack = REENTRANT_IGNORE.get();
              boolean empty = reentrantStack.isEmpty() || reentrantStack.pop() == 1;
              if (noOtherIgnoreStrategy && empty) {
                  InterceptorIgnoreHelper.clearIgnoreStrategy();
              } else if (empty) {
                  ignoreStrategy.setDataPermission(false);
              }
  
          }
      }
  
      /**
       * 在忽略数据权限中执行
       *
       * @param handle 处理执行方法
       */
      public static void ignore(Runnable handle) {
          enableIgnore();
          try {
              handle.run();
          } finally {
              disableIgnore();
          }
      }
  
      /**
       * 在忽略数据权限中执行
       *
       * @param handle 处理执行方法
       */
      public static <T> T ignore(Supplier<T> handle) {
          enableIgnore();
          try {
              return handle.get();
          } finally {
              disableIgnore();
          }
      }
  
  }
  