feat: 集成jar 集成前端

dev_na
chenhao 2026-03-17 15:31:09 +08:00
parent af5c658bd9
commit 2b1d7b8a2e
185 changed files with 6036 additions and 10666 deletions

View File

@ -524,8 +524,8 @@ INSERT INTO sys_param ("param_id", "param_key", "param_value", "param_type", "st
INSERT INTO sys_param ("param_id", "param_key", "param_value", "param_type", "status", "is_system", "description", "is_deleted", "created_at", "updated_at") VALUES (1, 'security.token.access_ttl_minutes', '120', 'int', 1, 1, 'Access Token 有效期(分钟)', 0, '2026-02-09 09:54:21.888052', '2026-03-10 10:15:39.55035');
INSERT INTO sys_user ("user_id", "username", "display_name", "email", "phone", "password_hash", "status", "is_deleted", "created_at", "updated_at", "is_platform_admin", "pwd_reset_required")
VALUES (1, 'admin', '管理员', 'admin', NULL, '$2a$10$BOm1iCFj3ObfBeyQxOvjVO659vXvIRGOd4YR62r0TUHqSusWW5bFS', 1, 0, '2026-02-09 09:54:21.880637', '2026-02-28 17:57:32.63338', 't', NULL);
INSERT INTO sys_user ( "username", "display_name", "email", "phone", "password_hash", "status", "is_deleted", "created_at", "updated_at", "is_platform_admin", "pwd_reset_required")
VALUES ( 'admin', '管理员', 'admin', NULL, '$2a$10$BOm1iCFj3ObfBeyQxOvjVO659vXvIRGOd4YR62r0TUHqSusWW5bFS', 1, 0, '2026-02-09 09:54:21.880637', '2026-02-28 17:57:32.63338', 't', NULL);
INSERT INTO "sys_dict_type" ("dict_type_id", "type_code", "type_name", "status", "remark", "created_at", "updated_at") VALUES (9, 'biz_hotword_category', '热词类别', 1, '语音识别纠错分类', '2026-02-28 17:08:52.362532', '2026-02-28 17:08:52.362532');

View File

@ -124,6 +124,11 @@
<artifactId>jsoup</artifactId>
<version>1.17.2</version>
</dependency>
<dependency>
<groupId>com.unisbase</groupId>
<artifactId>unisbase-spring-boot-starter</artifactId>
<version>0.1.0</version>
</dependency>
</dependencies>
<build>

View File

@ -1,168 +0,0 @@
package com.imeeting.auth;
import com.imeeting.common.RedisKeys;
import com.imeeting.entity.SysTenant;
import com.imeeting.entity.SysUser;
import com.imeeting.security.LoginUser;
import com.imeeting.service.AuthScopeService;
import com.imeeting.service.AuthVersionService;
import com.imeeting.service.SysParamService;
import com.imeeting.service.SysPermissionService;
import com.imeeting.mapper.SysTenantMapper;
import com.imeeting.mapper.SysUserMapper;
import io.jsonwebtoken.Claims;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.Set;
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtTokenProvider jwtTokenProvider;
private final SysPermissionService sysPermissionService;
private final SysTenantMapper sysTenantMapper;
private final SysUserMapper sysUserMapper;
private final SysParamService sysParamService;
private final StringRedisTemplate redisTemplate;
private final AuthScopeService authScopeService;
private final AuthVersionService authVersionService;
public JwtAuthenticationFilter(JwtTokenProvider jwtTokenProvider,
@Lazy SysPermissionService sysPermissionService,
SysTenantMapper sysTenantMapper,
SysUserMapper sysUserMapper,
@Lazy SysParamService sysParamService,
StringRedisTemplate redisTemplate,
AuthScopeService authScopeService,
AuthVersionService authVersionService) {
this.jwtTokenProvider = jwtTokenProvider;
this.sysPermissionService = sysPermissionService;
this.sysTenantMapper = sysTenantMapper;
this.sysUserMapper = sysUserMapper;
this.sysParamService = sysParamService;
this.redisTemplate = redisTemplate;
this.authScopeService = authScopeService;
this.authVersionService = authVersionService;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String uri = request.getRequestURI();
// Skip filter for public endpoints
if (uri.startsWith("/auth/") || uri.equals("/api/params/value")) {
filterChain.doFilter(request, response);
return;
}
String authHeader = request.getHeader("Authorization");
if (authHeader != null && authHeader.startsWith("Bearer ")) {
String token = authHeader.substring(7);
try {
Claims claims = jwtTokenProvider.parseToken(token);
String username = claims.get("username", String.class);
String displayName = claims.get("displayName", String.class);
Long userId = claims.get("userId", Long.class);
Long tenantId = claims.get("tenantId", Long.class);
Number tokenAuthVersionNum = claims.get("authVersion", Number.class);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
// 1. Validate User Status (Ignore Tenant isolation here)
SysUser user = sysUserMapper.selectByIdIgnoreTenant(userId);
if (user == null || user.getStatus() != 1 || user.getIsDeleted() != 0) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\"code\":\"401\",\"msg\":\"User account is disabled or deleted\"}");
return;
}
// 2. Validate Tenant Status & Grace Period
// Skip validation for system platform tenant (ID=0)
Long activeTenantId = tenantId;
if (activeTenantId != null && !Long.valueOf(0).equals(activeTenantId)) {
SysTenant tenant = sysTenantMapper.selectByIdIgnoreTenant(activeTenantId);
if (tenant == null || tenant.getStatus() != 1) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\"code\":\"401\",\"msg\":\"Tenant is disabled\"}");
return;
}
if (tenant.getExpireTime() != null) {
LocalDateTime now = LocalDateTime.now();
if (now.isAfter(tenant.getExpireTime())) {
String graceDaysStr = sysParamService.getParamValue("sys.tenant.grace_period_days", "0");
int graceDays = Integer.parseInt(graceDaysStr);
if (now.isAfter(tenant.getExpireTime().plusDays(graceDays))) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\"code\":\"401\",\"msg\":\"Tenant subscription expired\"}");
return;
}
}
}
}
long currentAuthVersion = authVersionService.getVersion(userId, activeTenantId);
long requestAuthVersion = tokenAuthVersionNum == null ? 0L : tokenAuthVersionNum.longValue();
if (currentAuthVersion != requestAuthVersion) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\"code\":\"401\",\"msg\":\"Token revoked\"}");
return;
}
// 3. Get Permissions (With Redis Cache, Key must include tenantId)
String permKey = RedisKeys.authPermKey(userId, activeTenantId, currentAuthVersion);
Set<String> permissions;
String cachedPerms = redisTemplate.opsForValue().get(permKey);
if (cachedPerms != null && !cachedPerms.trim().isEmpty()) {
permissions = Set.of(cachedPerms.split(","));
} else {
permissions = sysPermissionService.listPermissionCodesByUserId(userId, activeTenantId);
if (permissions != null && !permissions.isEmpty()) {
redisTemplate.opsForValue().set(permKey, String.join(",", permissions), java.time.Duration.ofHours(2));
} else {
permissions = Collections.emptySet();
}
}
boolean isTenantAdmin = authScopeService.isTenantAdmin(userId, activeTenantId);
LoginUser loginUser = new LoginUser(userId, activeTenantId, username, displayName,user.getIsPlatformAdmin(), isTenantAdmin, permissions);
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
} catch (io.jsonwebtoken.ExpiredJwtException e) {
SecurityContextHolder.clearContext();
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\"code\":\"401\",\"msg\":\"Token expired\"}");
return;
} catch (io.jsonwebtoken.JwtException e) {
SecurityContextHolder.clearContext();
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\"code\":\"401\",\"msg\":\"Invalid token\"}");
return;
} catch (Exception ignored) {
SecurityContextHolder.clearContext();
}
}
filterChain.doFilter(request, response);
}
}

View File

@ -1,37 +0,0 @@
package com.imeeting.auth;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.util.Date;
import java.util.Map;
@Component
public class JwtTokenProvider {
private final Key key;
public JwtTokenProvider(@Value("${security.jwt.secret}") String secret) {
this.key = Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8));
}
public String createToken(Map<String, Object> claims, long ttlMillis) {
Date now = new Date();
Date exp = new Date(now.getTime() + ttlMillis);
return Jwts.builder()
.setClaims(claims)
.setIssuedAt(now)
.setExpiration(exp)
.signWith(key, SignatureAlgorithm.HS256)
.compact();
}
public Claims parseToken(String token) {
return Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token).getBody();
}
}

View File

@ -1,11 +0,0 @@
package com.imeeting.auth.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class CaptchaResponse {
private String captchaId;
private String imageBase64;
}

View File

@ -1,15 +0,0 @@
package com.imeeting.auth.dto;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
@Data
public class DeviceCodeRequest {
@NotBlank
private String username;
@NotBlank
private String password;
private String captchaId;
private String captchaCode;
private String deviceName;
}

View File

@ -1,16 +0,0 @@
package com.imeeting.auth.dto;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
@Data
public class LoginRequest {
private String tenantCode;
@NotBlank
private String username;
@NotBlank
private String password;
private String captchaId;
private String captchaCode;
private String deviceCode;
}

View File

@ -1,10 +0,0 @@
package com.imeeting.auth.dto;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
@Data
public class RefreshRequest {
@NotBlank
private String refreshToken;
}

View File

@ -1,24 +0,0 @@
package com.imeeting.auth.dto;
import lombok.Builder;
import lombok.Data;
import java.util.List;
@Data
@Builder
public class TokenResponse {
private String accessToken;
private String refreshToken;
private long accessExpiresInMinutes;
private long refreshExpiresInDays;
private Integer pwdResetRequired;
private List<TenantInfo> availableTenants;
@Data
@Builder
public static class TenantInfo {
private Long tenantId;
private String tenantCode;
private String tenantName;
}
}

View File

@ -1,22 +0,0 @@
package com.imeeting.common;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ApiResponse<T> {
private String code;
private String msg;
private T data;
public static <T> ApiResponse<T> ok(T data) {
return new ApiResponse<>("0", "OK", data);
}
public static <T> ApiResponse<T> error(String msg) {
return new ApiResponse<>("-1", msg, null);
}
}

View File

@ -1,29 +0,0 @@
package com.imeeting.common;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(IllegalArgumentException.class)
public ApiResponse<Void> handleIllegalArgument(IllegalArgumentException ex) {
log.warn("Business error: {}", ex.getMessage());
return ApiResponse.error(ex.getMessage());
}
@ExceptionHandler(org.springframework.security.access.AccessDeniedException.class)
public ApiResponse<Void> handleAccessDenied(org.springframework.security.access.AccessDeniedException ex) {
log.warn("Access denied: {}", ex.getMessage());
return ApiResponse.error("无权限操作");
}
@ExceptionHandler(Exception.class)
public ApiResponse<Void> handleGeneric(Exception ex) {
log.error("Unhandled exception", ex);
return ApiResponse.error("系统异常");
}
}

View File

@ -1,9 +0,0 @@
package com.imeeting.common;
import lombok.Data;
@Data
public class PageResult<T> {
private long total;
private T records;
}

View File

@ -1,11 +0,0 @@
package com.imeeting.common.annotation;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
String value() default ""; // 操作描述
String type() default ""; // 资源类型/模块名
}

View File

@ -1,111 +0,0 @@
package com.imeeting.common.aspect;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.imeeting.common.annotation.Log;
import com.imeeting.entity.SysLog;
import com.imeeting.security.LoginUser;
import com.imeeting.service.SysLogService;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
@Aspect
@Component
public class LogAspect {
private final SysLogService sysLogService;
private final ObjectMapper objectMapper;
public LogAspect(SysLogService sysLogService, ObjectMapper objectMapper) {
this.sysLogService = sysLogService;
this.objectMapper = objectMapper;
}
@Around("@annotation(com.imeeting.common.annotation.Log)")
public Object around(ProceedingJoinPoint point) throws Throwable {
long start = System.currentTimeMillis();
Object result = null;
Exception exception = null;
try {
result = point.proceed();
return result;
} catch (Exception e) {
exception = e;
throw e;
} finally {
saveLog(point, result, exception, System.currentTimeMillis() - start);
}
}
private void saveLog(ProceedingJoinPoint joinPoint, Object result, Exception e, long duration) {
try {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes == null) return;
HttpServletRequest request = attributes.getRequest();
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
Log logAnnotation = method.getAnnotation(Log.class);
SysLog sysLog = new SysLog();
sysLog.setLogType("OPERATION");
sysLog.setOperation(logAnnotation.value());
sysLog.setMethod(request.getMethod() + " " + request.getRequestURI());
sysLog.setDuration(duration);
sysLog.setIp(request.getRemoteAddr());
sysLog.setCreatedAt(LocalDateTime.now());
// 仅保留请求参数,移除响应结果
sysLog.setParams(getArgsJson(joinPoint));
// 获取当前租户和用户信息
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null && auth.getPrincipal() instanceof LoginUser) {
LoginUser user = (LoginUser) auth.getPrincipal();
sysLog.setUserId(user.getUserId());
sysLog.setTenantId(user.getTenantId());
sysLog.setUsername(user.getUsername());
}
sysLog.setStatus(e != null ? 0 : 1);
sysLogService.recordLog(sysLog);
} catch (Exception ex) {
ex.printStackTrace();
}
}
private String getArgsJson(ProceedingJoinPoint joinPoint) {
try {
Object[] args = joinPoint.getArgs();
if (args == null || args.length == 0) return null;
StringBuilder sb = new StringBuilder();
for (Object arg : args) {
if (arg instanceof jakarta.servlet.ServletRequest
|| arg instanceof jakarta.servlet.ServletResponse
|| arg instanceof org.springframework.web.multipart.MultipartFile) {
continue;
}
try {
sb.append(objectMapper.writeValueAsString(arg)).append(" ");
} catch (Exception e) {
sb.append("[Unserializable Argument] ");
}
}
return sb.toString().trim();
} catch (Exception e) {
return "[Error capturing params]";
}
}
}

View File

@ -1,29 +0,0 @@
package com.imeeting.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
@Configuration
public class CacheConfig {
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofHours(1)) // Default TTL
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))
.disableCachingNullValues();
return RedisCacheManager.builder(connectionFactory)
.cacheDefaults(config)
.build();
}
}

View File

@ -1,90 +0,0 @@
package com.imeeting.config;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import com.imeeting.security.LoginUser;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import java.time.LocalDateTime;
import java.util.List;
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(new TenantLineHandler() {
@Override
public Expression getTenantId() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null && auth.getPrincipal() instanceof LoginUser) {
LoginUser user = (LoginUser) auth.getPrincipal();
if (user.getTenantId() != null) {
return new LongValue(user.getTenantId());
}
}
// If no tenant context (e.g. system task or error), return 0
return new LongValue(0);
}
@Override
public String getTenantIdColumn() {
return "tenant_id";
}
@Override
public boolean ignoreTable(String tableName) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null && auth.getPrincipal() instanceof LoginUser) {
LoginUser user = (LoginUser) auth.getPrincipal();
// 只有当平台管理员处于系统租户(0)时,才忽略所有过滤。
// 如果他切换到了具体租户(>0),则必须接受过滤,确保只能看到当前租户数据。
if (Boolean.TRUE.equals(user.getIsPlatformAdmin()) && Long.valueOf(0).equals(user.getTenantId())) {
return true;
}
}
// 公共表始终忽略过滤
return List.of("sys_tenant","sys_platform_config", "sys_user", "sys_tenant_user", "sys_permission", "sys_role_permission", "sys_user_role", "sys_dict_type", "sys_dict_item", "sys_param", "biz_speakers", "biz_prompt_templates", "biz_asr_models", "biz_llm_models", "biz_meetings", "biz_meeting_transcripts", "biz_ai_tasks").contains(tableName.toLowerCase());
}
}));
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return interceptor;
}
@Bean
public MetaObjectHandler metaObjectHandler() {
return new MetaObjectHandler() {
@Override
public void insertFill(MetaObject metaObject) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null && auth.getPrincipal() instanceof LoginUser) {
LoginUser user = (LoginUser) auth.getPrincipal();
strictInsertFill(metaObject, "tenantId", Long.class, user.getTenantId());
} else {
strictInsertFill(metaObject, "tenantId", Long.class, 0L);
}
strictInsertFill(metaObject, "createdAt", LocalDateTime::now, LocalDateTime.class);
strictInsertFill(metaObject, "updatedAt", LocalDateTime::now, LocalDateTime.class);
strictInsertFill(metaObject, "status", () -> 1, Integer.class);
strictInsertFill(metaObject, "isDeleted", () -> 0, Integer.class);
}
@Override
public void updateFill(MetaObject metaObject) {
strictUpdateFill(metaObject, "updatedAt", LocalDateTime::now, LocalDateTime.class);
}
};
}
}

View File

@ -1,62 +0,0 @@
package com.imeeting.config;
import com.imeeting.auth.JwtAuthenticationFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import java.util.List;
@Configuration
@EnableMethodSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http, JwtAuthenticationFilter jwtAuthenticationFilter) throws Exception {
http.csrf(csrf -> csrf.disable())
.cors(cors -> cors.configurationSource(corsConfigurationSource()))
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/auth/**").permitAll()
.requestMatchers("/api/open/**").permitAll()
.requestMatchers("/api/static/**").permitAll()
.requestMatchers("/api/params/value").permitAll()
.anyRequest().authenticated()
)
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
return configuration.getAuthenticationManager();
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOriginPatterns(List.of("*"));
config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
config.setAllowedHeaders(List.of("*"));
config.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
}

View File

@ -1,20 +0,0 @@
package com.imeeting.config;
import com.imeeting.service.SysParamService;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
@Component
public class SysParamCacheInitializer implements ApplicationRunner {
private final SysParamService sysParamService;
public SysParamCacheInitializer(SysParamService sysParamService) {
this.sysParamService = sysParamService;
}
@Override
public void run(ApplicationArguments args) {
sysParamService.syncAllToCache();
}
}

View File

@ -1,22 +0,0 @@
package com.imeeting.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Value("${app.upload-path}")
private String uploadPath;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
String base = uploadPath.endsWith("/") ? uploadPath : uploadPath + "/";
String audioPath = "file:" + base + "audio/";
registry.addResourceHandler("/api/static/audio/**")
.addResourceLocations(audioPath);
}
}

View File

@ -10,10 +10,10 @@ import java.io.File;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Value("${app.upload-path}")
@Value("${unisbase.app.upload-path}")
private String uploadPath;
@Value("${app.resource-prefix}")
@Value("${unisbase.app.resource-prefix}")
private String resourcePrefix;
@Override

View File

@ -1,100 +0,0 @@
package com.imeeting.controller;
import com.imeeting.auth.JwtTokenProvider;
import com.imeeting.auth.dto.CaptchaResponse;
import com.imeeting.auth.dto.DeviceCodeRequest;
import com.imeeting.auth.dto.LoginRequest;
import com.imeeting.auth.dto.RefreshRequest;
import com.imeeting.auth.dto.TokenResponse;
import com.imeeting.common.ApiResponse;
import com.imeeting.common.RedisKeys;
import com.imeeting.common.SysParamKeys;
import com.imeeting.service.SysParamService;
import com.imeeting.service.AuthService;
import com.wf.captcha.SpecCaptcha;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;
import java.time.Duration;
import java.util.UUID;
@RestController
@RequestMapping("/auth")
public class AuthController {
private final AuthService authService;
private final StringRedisTemplate stringRedisTemplate;
private final JwtTokenProvider jwtTokenProvider;
private final SysParamService sysParamService;
@Value("${app.captcha.ttl-seconds:120}")
private long captchaTtlSeconds;
public AuthController(AuthService authService, StringRedisTemplate stringRedisTemplate,
JwtTokenProvider jwtTokenProvider, SysParamService sysParamService) {
this.authService = authService;
this.stringRedisTemplate = stringRedisTemplate;
this.jwtTokenProvider = jwtTokenProvider;
this.sysParamService = sysParamService;
}
@GetMapping("/captcha")
public ApiResponse<CaptchaResponse> captcha() {
if (!isCaptchaEnabled()) {
return ApiResponse.error("Captcha disabled");
}
SpecCaptcha captcha = new SpecCaptcha(130, 48, 4);
String code = captcha.text();
String imageBase64 = captcha.toBase64();
String captchaId = UUID.randomUUID().toString().replace("-", "");
stringRedisTemplate.opsForValue().set(RedisKeys.captchaKey(captchaId), code, Duration.ofSeconds(captchaTtlSeconds));
return ApiResponse.ok(new CaptchaResponse(captchaId, imageBase64));
}
@PostMapping("/device-code")
public ApiResponse<String> deviceCode(@Valid @RequestBody DeviceCodeRequest request) {
LoginRequest loginRequest = new LoginRequest();
loginRequest.setUsername(request.getUsername());
loginRequest.setPassword(request.getPassword());
loginRequest.setCaptchaId(request.getCaptchaId());
loginRequest.setCaptchaCode(request.getCaptchaCode());
String deviceCode = authService.createDeviceCode(loginRequest, request.getDeviceName());
return ApiResponse.ok(deviceCode);
}
@PostMapping("/login")
public ApiResponse<TokenResponse> login(@Valid @RequestBody LoginRequest request) {
return ApiResponse.ok(authService.login(request));
}
@PostMapping("/refresh")
public ApiResponse<TokenResponse> refresh(@Valid @RequestBody RefreshRequest request) {
return ApiResponse.ok(authService.refresh(request.getRefreshToken()));
}
@PostMapping("/switch-tenant")
public ApiResponse<TokenResponse> switchTenant(@RequestParam Long tenantId, @RequestHeader("Authorization") String authorization) {
String token = authorization.replace("Bearer ", "");
var claims = jwtTokenProvider.parseToken(token);
Long userId = claims.get("userId", Long.class);
String deviceCode = claims.get("deviceCode", String.class);
return ApiResponse.ok(authService.switchTenant(userId, tenantId, deviceCode));
}
@PostMapping("/logout")
public ApiResponse<Void> logout(@RequestHeader("Authorization") String authorization) {
String token = authorization.replace("Bearer ", "");
var claims = jwtTokenProvider.parseToken(token);
Long userId = claims.get("userId", Long.class);
String deviceCode = claims.get("deviceCode", String.class);
authService.logout(userId, deviceCode);
return ApiResponse.ok(null);
}
private boolean isCaptchaEnabled() {
String value = sysParamService.getCachedParamValue(SysParamKeys.CAPTCHA_ENABLED, "true");
return Boolean.parseBoolean(value);
}
}

View File

@ -1,44 +0,0 @@
package com.imeeting.controller;
import com.imeeting.common.ApiResponse;
import com.imeeting.entity.Device;
import com.imeeting.service.DeviceService;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/devices")
public class DeviceController {
private final DeviceService deviceService;
public DeviceController(DeviceService deviceService) {
this.deviceService = deviceService;
}
@GetMapping
public ApiResponse<List<Device>> list() {
return ApiResponse.ok(deviceService.list());
}
@GetMapping("/{id}")
public ApiResponse<Device> get(@PathVariable Long id) {
return ApiResponse.ok(deviceService.getById(id));
}
@PostMapping
public ApiResponse<Boolean> create(@RequestBody Device device) {
return ApiResponse.ok(deviceService.save(device));
}
@PutMapping("/{id}")
public ApiResponse<Boolean> update(@PathVariable Long id, @RequestBody Device device) {
device.setDeviceId(id);
return ApiResponse.ok(deviceService.updateById(device));
}
@DeleteMapping("/{id}")
public ApiResponse<Boolean> delete(@PathVariable Long id) {
return ApiResponse.ok(deviceService.removeById(id));
}
}

View File

@ -1,62 +0,0 @@
package com.imeeting.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.imeeting.common.ApiResponse;
import com.imeeting.entity.SysDictItem;
import com.imeeting.service.SysDictItemService;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/dict-items")
public class DictItemController {
private final SysDictItemService sysDictItemService;
public DictItemController(SysDictItemService sysDictItemService) {
this.sysDictItemService = sysDictItemService;
}
@GetMapping
@PreAuthorize("@ss.hasPermi('sys_dict:list')")
public ApiResponse<List<SysDictItem>> list(@RequestParam(required = false) String typeCode) {
LambdaQueryWrapper<SysDictItem> queryWrapper = new LambdaQueryWrapper<>();
if (typeCode != null && !typeCode.isEmpty()) {
queryWrapper.eq(SysDictItem::getTypeCode, typeCode);
}
queryWrapper.orderByAsc(SysDictItem::getSortOrder);
return ApiResponse.ok(sysDictItemService.list(queryWrapper));
}
@GetMapping("/{id}")
@PreAuthorize("@ss.hasPermi('sys_dict:query')")
public ApiResponse<SysDictItem> get(@PathVariable Long id) {
return ApiResponse.ok(sysDictItemService.getById(id));
}
@PostMapping
@PreAuthorize("@ss.hasPermi('sys_dict:create')")
public ApiResponse<Boolean> create(@RequestBody SysDictItem dictItem) {
return ApiResponse.ok(sysDictItemService.save(dictItem));
}
@PutMapping("/{id}")
@PreAuthorize("@ss.hasPermi('sys_dict:update')")
public ApiResponse<Boolean> update(@PathVariable Long id, @RequestBody SysDictItem dictItem) {
dictItem.setDictItemId(id);
return ApiResponse.ok(sysDictItemService.updateById(dictItem));
}
@DeleteMapping("/{id}")
@PreAuthorize("@ss.hasPermi('sys_dict:delete')")
public ApiResponse<Boolean> delete(@PathVariable Long id) {
return ApiResponse.ok(sysDictItemService.removeById(id));
}
@GetMapping("/type/{typeCode}")
// @PreAuthorize("@ss.hasPermi('sys_dict:query')")
public ApiResponse<List<SysDictItem>> getByType(@PathVariable String typeCode) {
return ApiResponse.ok(sysDictItemService.getItemsByTypeCode(typeCode));
}
}

View File

@ -1,63 +0,0 @@
package com.imeeting.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.imeeting.common.ApiResponse;
import com.imeeting.entity.SysDictType;
import com.imeeting.service.SysDictTypeService;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/dict-types")
public class DictTypeController {
private final SysDictTypeService sysDictTypeService;
public DictTypeController(SysDictTypeService sysDictTypeService) {
this.sysDictTypeService = sysDictTypeService;
}
@GetMapping
@PreAuthorize("@ss.hasPermi('sys_dict:list')")
public ApiResponse<Page<SysDictType>> list(
@RequestParam(defaultValue = "1") Integer current,
@RequestParam(defaultValue = "10") Integer size,
@RequestParam(required = false) String typeCode,
@RequestParam(required = false) String typeName) {
Page<SysDictType> page = new Page<>(current, size);
LambdaQueryWrapper<SysDictType> queryWrapper = new LambdaQueryWrapper<>();
if (typeCode != null && !typeCode.isEmpty()) {
queryWrapper.like(SysDictType::getTypeCode, typeCode);
}
if (typeName != null && !typeName.isEmpty()) {
queryWrapper.like(SysDictType::getTypeName, typeName);
}
queryWrapper.orderByAsc(SysDictType::getTypeCode);
return ApiResponse.ok(sysDictTypeService.page(page, queryWrapper));
}
@GetMapping("/{id}")
@PreAuthorize("@ss.hasPermi('sys_dict:query')")
public ApiResponse<SysDictType> get(@PathVariable Long id) {
return ApiResponse.ok(sysDictTypeService.getById(id));
}
@PostMapping
@PreAuthorize("@ss.hasPermi('sys_dict:create')")
public ApiResponse<Boolean> create(@RequestBody SysDictType dictType) {
return ApiResponse.ok(sysDictTypeService.save(dictType));
}
@PutMapping("/{id}")
@PreAuthorize("@ss.hasPermi('sys_dict:update')")
public ApiResponse<Boolean> update(@PathVariable Long id, @RequestBody SysDictType dictType) {
dictType.setDictTypeId(id);
return ApiResponse.ok(sysDictTypeService.updateById(dictType));
}
@DeleteMapping("/{id}")
@PreAuthorize("@ss.hasPermi('sys_dict:delete')")
public ApiResponse<Boolean> delete(@PathVariable Long id) {
return ApiResponse.ok(sysDictTypeService.removeById(id));
}
}

View File

@ -1,231 +0,0 @@
package com.imeeting.controller;
import com.imeeting.common.ApiResponse;
import com.imeeting.dto.PermissionNode;
import com.imeeting.entity.SysPermission;
import com.imeeting.entity.SysRole;
import com.imeeting.mapper.SysRolePermissionMapper;
import com.imeeting.mapper.SysUserRoleMapper;
import com.imeeting.service.AuthVersionService;
import com.imeeting.service.SysPermissionService;
import com.imeeting.service.SysRoleService;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/api/permissions")
public class PermissionController {
private final SysPermissionService sysPermissionService;
private final SysRolePermissionMapper sysRolePermissionMapper;
private final SysUserRoleMapper sysUserRoleMapper;
private final SysRoleService sysRoleService;
private final AuthVersionService authVersionService;
public PermissionController(SysPermissionService sysPermissionService,
SysRolePermissionMapper sysRolePermissionMapper, SysUserRoleMapper sysUserRoleMapper,
SysRoleService sysRoleService, AuthVersionService authVersionService) {
this.sysPermissionService = sysPermissionService;
this.sysRolePermissionMapper = sysRolePermissionMapper;
this.sysUserRoleMapper = sysUserRoleMapper;
this.sysRoleService = sysRoleService;
this.authVersionService = authVersionService;
}
@GetMapping
@PreAuthorize("@ss.hasPermi('sys:permission:list')")
public ApiResponse<List<SysPermission>> list() {
Long tenantId = getCurrentTenantId();
// 平台管理员查询所有
if (Long.valueOf(0).equals(tenantId)) {
return ApiResponse.ok(sysPermissionService.list());
}
// 非平台管理员只能查询自己拥有的权限
return ApiResponse.ok(sysPermissionService.listByUserId(getCurrentUserId(), tenantId));
}
@GetMapping("/me")
public ApiResponse<List<SysPermission>> myPermissions() {
return ApiResponse.ok(sysPermissionService.listByUserId(getCurrentUserId(), getCurrentTenantId()));
}
@GetMapping("/tree")
@PreAuthorize("@ss.hasPermi('sys:permission:list')")
public ApiResponse<List<PermissionNode>> tree() {
Long tenantId = getCurrentTenantId();
List<SysPermission> list;
if (Long.valueOf(0).equals(tenantId)) {
list = sysPermissionService.list();
} else {
list = sysPermissionService.listByUserId(getCurrentUserId(), tenantId);
}
return ApiResponse.ok(buildTree(list));
}
@GetMapping("/tree/me")
public ApiResponse<List<PermissionNode>> myTree() {
return ApiResponse.ok(buildTree(sysPermissionService.listByUserId(getCurrentUserId(), getCurrentTenantId())));
}
@GetMapping("/{id}")
@PreAuthorize("@ss.hasPermi('sys:permission:query')")
public ApiResponse<SysPermission> get(@PathVariable Long id) {
return ApiResponse.ok(sysPermissionService.getById(id));
}
@PostMapping
@PreAuthorize("@ss.hasPermi('sys:permission:create')")
public ApiResponse<Boolean> create(@RequestBody SysPermission perm) {
String error = validateParent(perm);
if (error != null) {
return ApiResponse.error(error);
}
return ApiResponse.ok(sysPermissionService.save(perm));
}
@PutMapping("/{id}")
@PreAuthorize("@ss.hasPermi('sys:permission:update')")
public ApiResponse<Boolean> update(@PathVariable Long id, @RequestBody SysPermission perm) {
List<Long> roleIds = sysRolePermissionMapper.selectRoleIdsByPermId(id);
perm.setPermId(id);
String error = validateParent(perm);
if (error != null) {
return ApiResponse.error(error);
}
boolean updated = sysPermissionService.updateById(perm);
if (perm.getLevel() != null && perm.getLevel() == 1) {
sysPermissionService.lambdaUpdate()
.set(SysPermission::getParentId, null)
.eq(SysPermission::getPermId, id)
.update();
}
if (updated) {
invalidateRoleUsers(roleIds);
}
return ApiResponse.ok(updated);
}
@DeleteMapping("/{id}")
@PreAuthorize("@ss.hasPermi('sys:permission:delete')")
public ApiResponse<Boolean> delete(@PathVariable Long id) {
List<Long> roleIds = sysRolePermissionMapper.selectRoleIdsByPermId(id);
boolean removed = sysPermissionService.removeById(id);
if (removed) {
invalidateRoleUsers(roleIds);
}
return ApiResponse.ok(removed);
}
private Long getCurrentUserId() {
org.springframework.security.core.Authentication authentication = org.springframework.security.core.context.SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication.getPrincipal() instanceof com.imeeting.security.LoginUser) {
return ((com.imeeting.security.LoginUser) authentication.getPrincipal()).getUserId();
}
return null;
}
private Long getCurrentTenantId() {
org.springframework.security.core.Authentication authentication = org.springframework.security.core.context.SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication.getPrincipal() instanceof com.imeeting.security.LoginUser) {
return ((com.imeeting.security.LoginUser) authentication.getPrincipal()).getTenantId();
}
return null;
}
private String validateParent(SysPermission perm) {
if (perm.getLevel() == null) {
return null;
}
if (perm.getPermType() != null && "button".equalsIgnoreCase(perm.getPermType())) {
if (perm.getCode() == null || perm.getCode().trim().isEmpty()) {
return "Code required for button permission";
}
}
if (perm.getLevel() == 1) {
perm.setParentId(null);
return null;
}
if (perm.getLevel() == 2) {
if (perm.getParentId() == null) {
return "ParentId required for level 2";
}
SysPermission parent = sysPermissionService.getById(perm.getParentId());
if (parent == null) {
return "Parent not found";
}
if (parent.getLevel() == null || parent.getLevel() != 1) {
return "Parent must be level 1";
}
}
return null;
}
private List<PermissionNode> buildTree(List<SysPermission> list) {
Map<Long, PermissionNode> map = new HashMap<>();
List<PermissionNode> roots = new ArrayList<>();
for (SysPermission p : list) {
PermissionNode node = toNode(p);
map.put(node.getPermId(), node);
}
for (PermissionNode node : map.values()) {
Long parentId = node.getParentId();
if (parentId != null && map.containsKey(parentId)) {
map.get(parentId).getChildren().add(node);
} else {
roots.add(node);
}
}
sortTree(roots);
return roots;
}
private void sortTree(List<PermissionNode> nodes) {
nodes.sort(Comparator.comparingInt(n -> n.getSortOrder() == null ? 0 : n.getSortOrder()));
for (PermissionNode node : nodes) {
if (node.getChildren() != null && !node.getChildren().isEmpty()) {
sortTree(node.getChildren());
}
}
}
private PermissionNode toNode(SysPermission p) {
PermissionNode node = new PermissionNode();
node.setPermId(p.getPermId());
node.setParentId(p.getParentId());
node.setName(p.getName());
node.setCode(p.getCode());
node.setPermType(p.getPermType());
node.setLevel(p.getLevel());
node.setPath(p.getPath());
node.setComponent(p.getComponent());
node.setIcon(p.getIcon());
node.setSortOrder(p.getSortOrder());
node.setIsVisible(p.getIsVisible());
node.setStatus(p.getStatus());
node.setDescription(p.getDescription());
node.setMeta(p.getMeta());
return node;
}
private void invalidateRoleUsers(List<Long> roleIds) {
if (roleIds == null || roleIds.isEmpty()) {
return;
}
for (Long roleId : roleIds) {
if (roleId == null) {
continue;
}
SysRole role = sysRoleService.getById(roleId);
if (role == null || role.getTenantId() == null) {
continue;
}
List<Long> userIds = sysUserRoleMapper.selectUserIdsByRoleId(roleId);
authVersionService.invalidateUsersTenantAuth(userIds, role.getTenantId());
}
}
}

View File

@ -1,55 +0,0 @@
package com.imeeting.controller;
import com.imeeting.common.ApiResponse;
import com.imeeting.dto.PlatformConfigVO;
import com.imeeting.entity.SysPlatformConfig;
import com.imeeting.service.SysPlatformConfigService;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@RestController
@RequestMapping("/api")
public class PlatformConfigController {
private final SysPlatformConfigService platformConfigService;
public PlatformConfigController(SysPlatformConfigService platformConfigService) {
this.platformConfigService = platformConfigService;
}
/**
* (favicon)
*/
@GetMapping("/open/platform/config")
public ApiResponse<PlatformConfigVO> getOpenConfig() {
return ApiResponse.ok(platformConfigService.getConfig());
}
/**
* ()
*/
@GetMapping("/admin/platform/config")
@PreAuthorize("isAuthenticated()")
public ApiResponse<PlatformConfigVO> getAdminConfig() {
return ApiResponse.ok(platformConfigService.getConfig());
}
/**
* ()
*/
@PutMapping("/admin/platform/config")
@PreAuthorize("hasRole('ADMIN') or @ss.hasPermi('sys_platform:config:update')")
public ApiResponse<Boolean> updateConfig(@RequestBody SysPlatformConfig config) {
return ApiResponse.ok(platformConfigService.updateConfig(config));
}
/**
* ()
*/
@PostMapping("/admin/platform/config/upload")
@PreAuthorize("hasRole('ADMIN') or @ss.hasPermi('sys_platform:config:update')")
public ApiResponse<String> upload(@RequestParam("file") MultipartFile file) {
return ApiResponse.ok(platformConfigService.uploadAsset(file));
}
}

View File

@ -1,344 +0,0 @@
package com.imeeting.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.imeeting.common.ApiResponse;
import com.imeeting.common.annotation.Log;
import com.imeeting.entity.SysRole;
import com.imeeting.entity.SysRolePermission;
import com.imeeting.entity.SysUser;
import com.imeeting.entity.SysUserRole;
import com.imeeting.mapper.SysRolePermissionMapper;
import com.imeeting.mapper.SysUserRoleMapper;
import com.imeeting.service.AuthScopeService;
import com.imeeting.service.AuthVersionService;
import com.imeeting.service.SysRoleService;
import com.imeeting.service.SysUserService;
import com.imeeting.service.SysPermissionService;
import com.imeeting.service.SysTenantUserService;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.Set;
@RestController
@RequestMapping("/api/roles")
public class RoleController {
private final SysRoleService sysRoleService;
private final SysUserService sysUserService;
private final SysRolePermissionMapper sysRolePermissionMapper;
private final SysUserRoleMapper sysUserRoleMapper;
private final SysPermissionService sysPermissionService;
private final AuthScopeService authScopeService;
private final AuthVersionService authVersionService;
private final SysTenantUserService sysTenantUserService;
public RoleController(SysRoleService sysRoleService, SysUserService sysUserService,
SysRolePermissionMapper sysRolePermissionMapper, SysUserRoleMapper sysUserRoleMapper,
SysPermissionService sysPermissionService,
AuthScopeService authScopeService,
AuthVersionService authVersionService,
SysTenantUserService sysTenantUserService) {
this.sysRoleService = sysRoleService;
this.sysUserService = sysUserService;
this.sysRolePermissionMapper = sysRolePermissionMapper;
this.sysUserRoleMapper = sysUserRoleMapper;
this.sysPermissionService = sysPermissionService;
this.authScopeService = authScopeService;
this.authVersionService = authVersionService;
this.sysTenantUserService = sysTenantUserService;
}
@GetMapping
@PreAuthorize("@ss.hasPermi('sys:role:list')")
public ApiResponse<List<SysRole>> list(@RequestParam(required = false) Long tenantId) {
QueryWrapper<SysRole> wrapper = new QueryWrapper<>();
if (authScopeService.isCurrentPlatformAdmin()) {
if (tenantId != null) {
wrapper.eq("tenant_id", tenantId);
}
} else {
Long currentTenantId = getCurrentTenantId();
wrapper.eq("tenant_id", currentTenantId);
}
return ApiResponse.ok(sysRoleService.list(wrapper));
}
@GetMapping("/{id}/users")
@PreAuthorize("@ss.hasPermi('sys:role:query')")
public ApiResponse<List<SysUser>> listUsers(@PathVariable Long id) {
SysRole role = sysRoleService.getById(id);
if (role == null) {
return ApiResponse.error("角色不存在");
}
if (!canAccessTenant(role.getTenantId())) {
return ApiResponse.error("禁止跨租户查看角色用户");
}
return ApiResponse.ok(sysUserService.listUsersByRoleId(id));
}
@GetMapping("/{id}")
@PreAuthorize("@ss.hasPermi('sys:role:query')")
public ApiResponse<SysRole> get(@PathVariable Long id) {
SysRole role = sysRoleService.getById(id);
if (role == null) {
return ApiResponse.error("角色不存在");
}
if (!canAccessTenant(role.getTenantId())) {
return ApiResponse.error("禁止跨租户查看角色");
}
return ApiResponse.ok(role);
}
@PostMapping
@PreAuthorize("@ss.hasPermi('sys:role:create')")
@Log(value = "新增角色", type = "角色管理")
public ApiResponse<Boolean> create(@RequestBody SysRole role) {
Long currentTenantId = getCurrentTenantId();
if (currentTenantId == null) {
return ApiResponse.error("Tenant ID required");
}
if (!authScopeService.isCurrentPlatformAdmin()) {
role.setTenantId(currentTenantId);
} else if (role.getTenantId() == null) {
return ApiResponse.error("tenantId required for platform role creation");
}
return ApiResponse.ok(sysRoleService.save(role));
}
@PutMapping("/{id}")
@PreAuthorize("@ss.hasPermi('sys:role:update')")
@Log(value = "修改角色", type = "角色管理")
public ApiResponse<Boolean> update(@PathVariable Long id, @RequestBody SysRole role) {
SysRole existing = sysRoleService.getById(id);
if (existing == null) {
return ApiResponse.error("角色不存在");
}
if (!canAccessTenant(existing.getTenantId())) {
return ApiResponse.error("禁止跨租户修改角色");
}
role.setRoleId(id);
role.setTenantId(existing.getTenantId());
return ApiResponse.ok(sysRoleService.updateById(role));
}
@DeleteMapping("/{id}")
@PreAuthorize("@ss.hasPermi('sys:role:delete')")
@Log(value = "删除角色", type = "角色管理")
public ApiResponse<Boolean> delete(@PathVariable Long id) {
SysRole existing = sysRoleService.getById(id);
if (existing == null) {
return ApiResponse.error("角色不存在");
}
if (!canAccessTenant(existing.getTenantId())) {
return ApiResponse.error("禁止跨租户删除角色");
}
if ("TENANT_ADMIN".equalsIgnoreCase(existing.getRoleCode()) && !authScopeService.isCurrentPlatformAdmin()) {
return ApiResponse.error("租户管理员角色只能由平台管理员删除");
}
List<Long> userIds = sysUserRoleMapper.selectUserIdsByRoleId(id);
boolean removed = sysRoleService.removeById(id);
if (removed) {
authVersionService.invalidateUsersTenantAuth(userIds, existing.getTenantId());
}
return ApiResponse.ok(removed);
}
@GetMapping("/{id}/permissions")
@PreAuthorize("@ss.hasPermi('sys:role:permission:list')")
public ApiResponse<List<Long>> listRolePermissions(@PathVariable Long id) {
SysRole targetRole = sysRoleService.getById(id);
if (targetRole == null) {
return ApiResponse.error("角色不存在");
}
if (!canAccessTenant(targetRole.getTenantId())) {
return ApiResponse.error("禁止跨租户查看角色权限");
}
List<SysRolePermission> rows = sysRolePermissionMapper.selectList(
new QueryWrapper<SysRolePermission>().eq("role_id", id)
);
List<Long> permIds = new ArrayList<>();
for (SysRolePermission row : rows) {
if (row.getPermId() != null) {
permIds.add(row.getPermId());
}
}
return ApiResponse.ok(permIds);
}
@PostMapping("/{id}/permissions")
@PreAuthorize("@ss.hasPermi('sys:role:permission:save')")
@Transactional(rollbackFor = Exception.class)
public ApiResponse<Boolean> saveRolePermissions(@PathVariable Long id, @RequestBody PermissionBindingPayload payload) {
List<Long> permIds = payload == null ? null : payload.getPermIds();
// 权限越权校验
Long currentTenantId = getCurrentTenantId();
if (currentTenantId == null) {
return ApiResponse.error("Tenant ID required");
}
SysRole targetRole = sysRoleService.getById(id);
if (targetRole == null) {
return ApiResponse.error("角色不存在");
}
// 关键校验:只有平台管理员可以修改 TENANT_ADMIN 角色的权限
if ("TENANT_ADMIN".equalsIgnoreCase(targetRole.getRoleCode())) {
if (!authScopeService.isCurrentPlatformAdmin()) {
return ApiResponse.error("租户管理员角色的权限只能由平台管理员修改");
}
}
if (!canAccessTenant(targetRole.getTenantId())) {
return ApiResponse.error("禁止跨租户修改角色权限");
}
if (!authScopeService.isCurrentPlatformAdmin()) {
List<com.imeeting.entity.SysPermission> myPerms = sysPermissionService.listByUserId(getCurrentUserId(), currentTenantId);
Set<Long> myPermIds = myPerms.stream()
.map(com.imeeting.entity.SysPermission::getPermId)
.collect(Collectors.toSet());
if (permIds != null) {
for (Long pId : permIds) {
if (!myPermIds.contains(pId)) {
return ApiResponse.error("越权分配权限:" + pId);
}
}
}
}
sysRolePermissionMapper.delete(new QueryWrapper<SysRolePermission>().eq("role_id", id));
if (permIds == null || permIds.isEmpty()) {
authVersionService.invalidateUsersTenantAuth(sysUserRoleMapper.selectUserIdsByRoleId(id), targetRole.getTenantId());
return ApiResponse.ok(true);
}
for (Long permId : permIds) {
if (permId == null) {
continue;
}
SysRolePermission item = new SysRolePermission();
item.setRoleId(id);
item.setPermId(permId);
sysRolePermissionMapper.insert(item);
}
authVersionService.invalidateUsersTenantAuth(sysUserRoleMapper.selectUserIdsByRoleId(id), targetRole.getTenantId());
return ApiResponse.ok(true);
}
@PostMapping("/{id}/users")
@PreAuthorize("@ss.hasPermi('sys:role:update')")
@Log(value = "角色关联用户", type = "角色管理")
@Transactional(rollbackFor = Exception.class)
public ApiResponse<Boolean> bindUsers(@PathVariable Long id, @RequestBody UserBindingPayload payload) {
if (payload == null || payload.getUserIds() == null) {
return ApiResponse.ok(true);
}
SysRole role = sysRoleService.getById(id);
if (role == null || role.getRoleId() == null || role.getTenantId() == null) {
return ApiResponse.error("角色不存在");
}
if (!canAccessTenant(role.getTenantId())) {
return ApiResponse.error("禁止跨租户绑定用户");
}
List<Long> toInsertUserIds = new ArrayList<>();
for (Long userId : payload.getUserIds()) {
if (userId == null) {
continue;
}
// 修复:处理逻辑删除导致的唯一键冲突
// 执行物理删除,彻底清除旧记录(包括已逻辑删除的)
sysUserRoleMapper.physicalDelete(id, userId, role.getTenantId());
// 确保该用户属于该租户
boolean hasMembership = sysTenantUserService.count(
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.imeeting.entity.SysTenantUser>()
.eq(com.imeeting.entity.SysTenantUser::getUserId, userId)
.eq(com.imeeting.entity.SysTenantUser::getTenantId, role.getTenantId())
) > 0;
if (!hasMembership) {
return ApiResponse.error("用户不属于角色所在租户:" + role.getTenantId());
}
toInsertUserIds.add(userId);
}
for (Long userId : toInsertUserIds) {
SysUserRole ur = new SysUserRole();
ur.setTenantId(role.getTenantId());
ur.setRoleId(id);
ur.setUserId(userId);
sysUserRoleMapper.insert(ur);
authVersionService.invalidateUserTenantAuth(userId, role.getTenantId());
}
return ApiResponse.ok(true);
}
@DeleteMapping("/{id}/users/{userId}")
@PreAuthorize("@ss.hasPermi('sys:role:update')")
@Log(value = "角色取消关联用户", type = "角色管理")
@Transactional(rollbackFor = Exception.class)
public ApiResponse<Boolean> unbindUser(@PathVariable Long id, @PathVariable Long userId) {
SysRole role = sysRoleService.getById(id);
if (role == null || role.getRoleId() == null || role.getTenantId() == null) {
return ApiResponse.error("角色不存在");
}
if (!canAccessTenant(role.getTenantId())) {
return ApiResponse.error("禁止跨租户解绑用户");
}
sysUserRoleMapper.physicalDelete(id, userId, role.getTenantId());
authVersionService.invalidateUserTenantAuth(userId, role.getTenantId());
return ApiResponse.ok(true);
}
private Long getCurrentUserId() {
org.springframework.security.core.Authentication authentication = org.springframework.security.core.context.SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication.getPrincipal() instanceof com.imeeting.security.LoginUser) {
return ((com.imeeting.security.LoginUser) authentication.getPrincipal()).getUserId();
}
return null;
}
private Long getCurrentTenantId() {
org.springframework.security.core.Authentication authentication = org.springframework.security.core.context.SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication.getPrincipal() instanceof com.imeeting.security.LoginUser) {
return ((com.imeeting.security.LoginUser) authentication.getPrincipal()).getTenantId();
}
return null;
}
private boolean canAccessTenant(Long targetTenantId) {
if (targetTenantId == null) {
return false;
}
if (authScopeService.isCurrentPlatformAdmin()) {
return true;
}
Long currentTenantId = getCurrentTenantId();
return currentTenantId != null && currentTenantId.equals(targetTenantId);
}
public static class UserBindingPayload {
private List<Long> userIds;
public List<Long> getUserIds() { return userIds; }
public void setUserIds(List<Long> userIds) { this.userIds = userIds; }
}
public static class PermissionBindingPayload {
private List<Long> permIds;
public List<Long> getPermIds() {
return permIds;
}
public void setPermIds(List<Long> permIds) {
this.permIds = permIds;
}
}
}

View File

@ -1,87 +0,0 @@
package com.imeeting.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.imeeting.common.ApiResponse;
import com.imeeting.entity.SysLog;
import com.imeeting.security.LoginUser;
import com.imeeting.service.SysLogService;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/logs")
public class SysLogController {
private final SysLogService sysLogService;
public SysLogController(SysLogService sysLogService) {
this.sysLogService = sysLogService;
}
@GetMapping
@PreAuthorize("@ss.hasPermi('sys_log:list')")
public ApiResponse<IPage<SysLog>> list(
@RequestParam(defaultValue = "1") Integer current,
@RequestParam(defaultValue = "10") Integer size,
@RequestParam(required = false) String username,
@RequestParam(required = false) String logType,
@RequestParam(required = false) String operation,
@RequestParam(required = false) Integer status,
@RequestParam(required = false) String startDate,
@RequestParam(required = false) String endDate,
@RequestParam(required = false) String sortField,
@RequestParam(required = false) String sortOrder
) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
LoginUser loginUser = (LoginUser) auth.getPrincipal();
// 判定平台管理员: isPlatformAdmin=true 且 tenantId=0
boolean isPlatformAdmin = Boolean.TRUE.equals(loginUser.getIsPlatformAdmin()) && Long.valueOf(0).equals(loginUser.getTenantId());
QueryWrapper<SysLog> query = new QueryWrapper<>();
// 只有联表查询才需要前缀 'l.'
String prefix = isPlatformAdmin ? "l." : "";
if (logType != null && !logType.isEmpty()) {
query.eq(prefix + "log_type", logType);
}
if (username != null && !username.isEmpty()) {
query.like(prefix + "username", username);
}
if (operation != null && !operation.isEmpty()) {
query.like(prefix + "operation", operation);
}
if (status != null) {
query.eq(prefix + "status", status);
}
if (startDate != null && !startDate.isEmpty()) {
query.ge(prefix + "created_at", startDate + " 00:00:00");
}
if (endDate != null && !endDate.isEmpty()) {
query.le(prefix + "created_at", endDate + " 23:59:59");
}
// 动态排序逻辑
if (sortField != null && !sortField.isEmpty()) {
String column = "created_at";
if ("duration".equals(sortField)) column = "duration";
if ("ascend".equals(sortOrder)) {
query.orderByAsc(prefix + column);
} else {
query.orderByDesc(prefix + column);
}
} else {
query.orderByDesc(prefix + "created_at");
}
if (isPlatformAdmin) {
return ApiResponse.ok(sysLogService.selectPageWithTenant(new Page<>(current, size), query));
} else {
return ApiResponse.ok(sysLogService.page(new Page<>(current, size), query));
}
}
}

View File

@ -1,60 +0,0 @@
package com.imeeting.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.imeeting.common.ApiResponse;
import com.imeeting.common.annotation.Log;
import com.imeeting.entity.SysOrg;
import com.imeeting.service.SysOrgService;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/orgs")
public class SysOrgController {
private final SysOrgService sysOrgService;
public SysOrgController(SysOrgService sysOrgService) {
this.sysOrgService = sysOrgService;
}
@GetMapping
@PreAuthorize("@ss.hasPermi('sys:org:list')")
public ApiResponse<List<SysOrg>> list(@RequestParam(required = false) Long tenantId) {
return ApiResponse.ok(sysOrgService.listTree(tenantId));
}
@GetMapping("/{id}")
@PreAuthorize("@ss.hasPermi('sys:org:query')")
public ApiResponse<SysOrg> get(@PathVariable Long id) {
return ApiResponse.ok(sysOrgService.getById(id));
}
@PostMapping
@PreAuthorize("@ss.hasPermi('sys:org:create')")
@Log(value = "新增组织", type = "组织管理")
public ApiResponse<Boolean> create(@RequestBody SysOrg org) {
return ApiResponse.ok(sysOrgService.save(org));
}
@PutMapping("/{id}")
@PreAuthorize("@ss.hasPermi('sys:org:update')")
@Log(value = "修改组织", type = "组织管理")
public ApiResponse<Boolean> update(@PathVariable Long id, @RequestBody SysOrg org) {
org.setId(id);
return ApiResponse.ok(sysOrgService.updateById(org));
}
@DeleteMapping("/{id}")
@PreAuthorize("@ss.hasPermi('sys:org:delete')")
@Log(value = "删除组织", type = "组织管理")
public ApiResponse<Boolean> delete(@PathVariable Long id) {
// Check if has children
long count = sysOrgService.count(new LambdaQueryWrapper<SysOrg>().eq(SysOrg::getParentId, id));
if (count > 0) {
return ApiResponse.error("存在下级组织,无法删除");
}
return ApiResponse.ok(sysOrgService.removeById(id));
}
}

View File

@ -1,94 +0,0 @@
package com.imeeting.controller;
import com.imeeting.common.ApiResponse;
import com.imeeting.common.PageResult;
import com.imeeting.dto.SysParamQueryDTO;
import com.imeeting.dto.SysParamVO;
import com.imeeting.entity.SysParam;
import com.imeeting.service.SysParamService;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/api/params")
public class SysParamController {
private final SysParamService sysParamService;
public SysParamController(SysParamService sysParamService) {
this.sysParamService = sysParamService;
}
@GetMapping("/page")
@PreAuthorize("@ss.hasPermi('sys_param:list')")
public ApiResponse<PageResult<List<SysParamVO>>> page(SysParamQueryDTO query) {
return ApiResponse.ok(sysParamService.page(query));
}
@GetMapping
@PreAuthorize("@ss.hasPermi('sys_param:list')")
public ApiResponse<List<SysParamVO>> list() {
return ApiResponse.ok(sysParamService.list().stream().map(this::toVO).collect(Collectors.toList()));
}
@GetMapping("/{id}")
@PreAuthorize("@ss.hasPermi('sys_param:query')")
public ApiResponse<SysParamVO> get(@PathVariable Long id) {
return ApiResponse.ok(toVO(sysParamService.getById(id)));
}
@PostMapping
@PreAuthorize("@ss.hasPermi('sys_param:create')")
public ApiResponse<Boolean> create(@RequestBody SysParam param) {
boolean saved = sysParamService.save(param);
if (saved) {
sysParamService.syncParamToCache(param);
}
return ApiResponse.ok(saved);
}
@PutMapping("/{id}")
@PreAuthorize("@ss.hasPermi('sys_param:update')")
public ApiResponse<Boolean> update(@PathVariable Long id, @RequestBody SysParam param) {
param.setParamId(id);
boolean updated = sysParamService.updateById(param);
if (updated) {
sysParamService.syncParamToCache(param);
}
return ApiResponse.ok(updated);
}
@DeleteMapping("/{id}")
@PreAuthorize("@ss.hasPermi('sys_param:delete')")
public ApiResponse<Boolean> delete(@PathVariable Long id) {
SysParam param = sysParamService.getById(id);
boolean removed = sysParamService.removeById(id);
if (removed && param != null) {
sysParamService.deleteParamCache(param.getParamKey());
}
return ApiResponse.ok(removed);
}
@GetMapping("/value")
public ApiResponse<String> getValue(@RequestParam("key") String key,
@RequestParam(value = "defaultValue", required = false) String defaultValue) {
return ApiResponse.ok(sysParamService.getCachedParamValue(key, defaultValue));
}
private SysParamVO toVO(SysParam entity) {
if (entity == null) return null;
SysParamVO vo = new SysParamVO();
vo.setParamId(entity.getParamId());
vo.setParamKey(entity.getParamKey());
vo.setParamValue(entity.getParamValue());
vo.setParamType(entity.getParamType());
vo.setIsSystem(entity.getIsSystem());
vo.setDescription(entity.getDescription());
vo.setStatus(entity.getStatus());
vo.setCreatedAt(entity.getCreatedAt());
vo.setUpdatedAt(entity.getUpdatedAt());
return vo;
}
}

View File

@ -1,69 +0,0 @@
package com.imeeting.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.imeeting.common.ApiResponse;
import com.imeeting.common.annotation.Log;
import com.imeeting.entity.SysTenant;
import com.imeeting.service.SysTenantService;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/tenants")
public class SysTenantController {
private final SysTenantService sysTenantService;
public SysTenantController(SysTenantService sysTenantService) {
this.sysTenantService = sysTenantService;
}
@GetMapping
@PreAuthorize("@ss.hasPermi('sys_tenant:list')")
public ApiResponse<Page<SysTenant>> list(
@RequestParam(defaultValue = "1") Integer current,
@RequestParam(defaultValue = "10") Integer size,
@RequestParam(required = false) String name,
@RequestParam(required = false) String code
) {
LambdaQueryWrapper<SysTenant> query = new LambdaQueryWrapper<>();
if (name != null && !name.isEmpty()) {
query.like(SysTenant::getTenantName, name);
}
if (code != null && !code.isEmpty()) {
query.like(SysTenant::getTenantCode, code);
}
query.orderByDesc(SysTenant::getCreatedAt);
return ApiResponse.ok(sysTenantService.page(new Page<>(current, size), query));
}
@GetMapping("/{id}")
@PreAuthorize("@ss.hasPermi('sys_tenant:query')")
public ApiResponse<SysTenant> get(@PathVariable Long id) {
return ApiResponse.ok(sysTenantService.getById(id));
}
@PostMapping
@PreAuthorize("@ss.hasPermi('sys_tenant:create')")
@Log(value = "新增租户", type = "租户管理")
public ApiResponse<Long> create(@RequestBody com.imeeting.dto.CreateTenantDTO tenantDto) {
return ApiResponse.ok(sysTenantService.createTenantWithAdmin(tenantDto));
}
@PutMapping("/{id}")
@PreAuthorize("@ss.hasPermi('sys_tenant:update')")
@Log(value = "修改租户", type = "租户管理")
public ApiResponse<Boolean> update(@PathVariable Long id, @RequestBody SysTenant tenant) {
tenant.setId(id);
return ApiResponse.ok(sysTenantService.updateById(tenant));
}
@DeleteMapping("/{id}")
@PreAuthorize("@ss.hasPermi('sys_tenant:delete')")
@Log(value = "删除租户", type = "租户管理")
public ApiResponse<Boolean> delete(@PathVariable Long id) {
return ApiResponse.ok(sysTenantService.removeById(id));
}
}

View File

@ -1,371 +0,0 @@
package com.imeeting.controller;
import com.imeeting.common.ApiResponse;
import com.imeeting.dto.PasswordUpdateDTO;
import com.imeeting.dto.UserProfile;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.imeeting.security.LoginUser;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.imeeting.entity.SysUser;
import com.imeeting.entity.SysUserRole;
import com.imeeting.mapper.SysUserRoleMapper;
import com.imeeting.service.AuthScopeService;
import com.imeeting.service.AuthVersionService;
import com.imeeting.service.SysUserService;
import com.imeeting.common.annotation.Log;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping("/api/users")
public class UserController {
private final SysUserService sysUserService;
private final PasswordEncoder passwordEncoder;
private final SysUserRoleMapper sysUserRoleMapper;
private final com.imeeting.service.SysTenantUserService sysTenantUserService;
private final com.imeeting.service.SysRoleService sysRoleService;
private final AuthScopeService authScopeService;
private final AuthVersionService authVersionService;
public UserController(SysUserService sysUserService, PasswordEncoder passwordEncoder,
SysUserRoleMapper sysUserRoleMapper,
com.imeeting.service.SysTenantUserService sysTenantUserService,
com.imeeting.service.SysRoleService sysRoleService,
AuthScopeService authScopeService,
AuthVersionService authVersionService) {
this.sysUserService = sysUserService;
this.passwordEncoder = passwordEncoder;
this.sysUserRoleMapper = sysUserRoleMapper;
this.sysTenantUserService = sysTenantUserService;
this.sysRoleService = sysRoleService;
this.authScopeService = authScopeService;
this.authVersionService = authVersionService;
}
@GetMapping
// @PreAuthorize("@ss.hasPermi('sys:user:list')")
public ApiResponse<List<SysUser>> list(@RequestParam(required = false) Long tenantId, @RequestParam(required = false) Long orgId) {
Long currentTenantId = getCurrentTenantId();
List<SysUser> users;
Long targetTenantId = null;
if (Long.valueOf(0).equals(currentTenantId) && tenantId == null) {
users = sysUserService.list();
} else {
targetTenantId = tenantId != null ? tenantId : currentTenantId;
if (targetTenantId == null) {
return ApiResponse.error("Tenant ID required");
}
users = sysUserService.listUsersByTenant(targetTenantId, orgId);
}
if (users != null && !users.isEmpty()) {
for (SysUser user : users) {
// 加载租户关系
user.setMemberships(sysTenantUserService.listByUserId(user.getUserId()));
// 加载角色信息
QueryWrapper<SysUserRole> roleQuery = new QueryWrapper<SysUserRole>().eq("user_id", user.getUserId());
if (targetTenantId != null) {
roleQuery.eq("tenant_id", targetTenantId);
}
List<SysUserRole> userRoles = sysUserRoleMapper.selectList(roleQuery);
if (userRoles != null && !userRoles.isEmpty()) {
List<Long> roleIds = userRoles.stream()
.map(SysUserRole::getRoleId)
.collect(java.util.stream.Collectors.toList());
user.setRoles(sysRoleService.listByIds(roleIds));
}
}
}
return ApiResponse.ok(users);
}
@GetMapping("/me")
public ApiResponse<UserProfile> me() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || !(authentication.getPrincipal() instanceof LoginUser)) {
return ApiResponse.error("Unauthorized");
}
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
Long userId = loginUser.getUserId();
SysUser user = sysUserService.getByIdIgnoreTenant(userId);
if (user == null) {
return ApiResponse.error("User not found");
}
UserProfile profile = new UserProfile();
profile.setUserId(user.getUserId());
profile.setUsername(user.getUsername());
profile.setDisplayName(user.getDisplayName());
profile.setEmail(user.getEmail());
profile.setPhone(user.getPhone());
profile.setStatus(user.getStatus());
profile.setAdmin(userId == 1L);
profile.setIsPlatformAdmin(user.getIsPlatformAdmin());
profile.setIsTenantAdmin(loginUser.getIsTenantAdmin());
profile.setPwdResetRequired(user.getPwdResetRequired());
return ApiResponse.ok(profile);
}
@GetMapping("/{id}")
@PreAuthorize("@ss.hasPermi('sys:user:query')")
public ApiResponse<SysUser> get(@PathVariable Long id) {
Long currentTenantId = getCurrentTenantId();
if (currentTenantId == null) {
return ApiResponse.error("Tenant ID required");
}
if (!authScopeService.isCurrentPlatformAdmin() && !isUserInTenant(id, currentTenantId)) {
return ApiResponse.error("禁止跨租户查看用户");
}
SysUser user = sysUserService.getByIdIgnoreTenant(id);
if (user != null) {
user.setMemberships(sysTenantUserService.listByUserId(id));
}
return ApiResponse.ok(user);
}
private Long getCurrentTenantId() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null && auth.getPrincipal() instanceof LoginUser) {
return ((LoginUser) auth.getPrincipal()).getTenantId();
}
return null;
}
@PostMapping
@PreAuthorize("@ss.hasPermi('sys:user:create')")
@Log(value = "新增用户", type = "用户管理")
public ApiResponse<Boolean> create(@RequestBody SysUser user) {
Long currentTenantId = getCurrentTenantId();
if (currentTenantId == null) {
return ApiResponse.error("Tenant ID required");
}
// 非平台管理员强制设置为当前租户
if (!Long.valueOf(0).equals(currentTenantId)) {
if (user.getMemberships() != null && !user.getMemberships().isEmpty()) {
user.getMemberships().forEach(m -> m.setTenantId(currentTenantId));
} else {
// 如果没传身份,补齐当前租户身份
List<com.imeeting.entity.SysTenantUser> memberships = new java.util.ArrayList<>();
com.imeeting.entity.SysTenantUser m = new com.imeeting.entity.SysTenantUser();
m.setTenantId(currentTenantId);
memberships.add(m);
user.setMemberships(memberships);
}
}
if (user.getPasswordHash() != null && !user.getPasswordHash().isEmpty()) {
user.setPasswordHash(passwordEncoder.encode(user.getPasswordHash()));
}
boolean saved = sysUserService.save(user);
if (saved) {
sysTenantUserService.syncMemberships(user.getUserId(), user.getMemberships());
}
return ApiResponse.ok(saved);
}
@PutMapping("/{id}")
@PreAuthorize("@ss.hasPermi('sys:user:update')")
@Log(value = "修改用户", type = "用户管理")
public ApiResponse<Boolean> update(@PathVariable Long id, @RequestBody SysUser user) {
Long currentTenantId = getCurrentTenantId();
if (currentTenantId == null) {
return ApiResponse.error("Tenant ID required");
}
user.setUserId(id);
if (!authScopeService.isCurrentPlatformAdmin() && !isUserInTenant(id, currentTenantId)) {
return ApiResponse.error("禁止跨租户修改用户");
}
// 非平台管理员强制约束租户身份
if (!Long.valueOf(0).equals(currentTenantId)) {
if (user.getMemberships() != null) {
user.getMemberships().forEach(m -> m.setTenantId(currentTenantId));
}
}
if (user.getPasswordHash() != null && !user.getPasswordHash().isEmpty()) {
user.setPasswordHash(passwordEncoder.encode(user.getPasswordHash()));
}
boolean updated = sysUserService.updateById(user);
if (updated) {
sysTenantUserService.syncMemberships(id, user.getMemberships());
}
return ApiResponse.ok(updated);
}
@DeleteMapping("/{id}")
@PreAuthorize("@ss.hasPermi('sys:user:delete')")
@Log(value = "删除用户", type = "用户管理")
public ApiResponse<Boolean> delete(@PathVariable Long id) {
Long currentTenantId = getCurrentTenantId();
if (currentTenantId == null) {
return ApiResponse.error("Tenant ID required");
}
if (!authScopeService.isCurrentPlatformAdmin() && !isUserInTenant(id, currentTenantId)) {
return ApiResponse.error("禁止跨租户删除用户");
}
return ApiResponse.ok(sysUserService.removeById(id));
}
@PutMapping("/profile")
public ApiResponse<Boolean> updateProfile(@RequestBody SysUser user) {
Long userId = getCurrentUserId();
SysUser existing = sysUserService.getByIdIgnoreTenant(userId);
if (existing == null) return ApiResponse.error("用户不存在");
existing.setDisplayName(user.getDisplayName());
existing.setEmail(user.getEmail());
existing.setPhone(user.getPhone());
return ApiResponse.ok(sysUserService.updateById(existing));
}
@PutMapping("/password")
public ApiResponse<Boolean> updatePassword(@RequestBody PasswordUpdateDTO dto) {
Long userId = getCurrentUserId();
SysUser user = sysUserService.getByIdIgnoreTenant(userId);
if (user == null) return ApiResponse.error("用户不存在");
if (!passwordEncoder.matches(dto.getOldPassword(), user.getPasswordHash())) {
return ApiResponse.error("旧密码不正确");
}
user.setPasswordHash(passwordEncoder.encode(dto.getNewPassword()));
user.setPwdResetRequired(0); // 重置标志位
return ApiResponse.ok(sysUserService.updateById(user));
}
private Long getCurrentUserId() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null && auth.getPrincipal() instanceof LoginUser) {
return ((LoginUser) auth.getPrincipal()).getUserId();
}
return null;
}
@GetMapping("/{id}/roles")
@PreAuthorize("@ss.hasPermi('sys:user:role:list')")
public ApiResponse<List<Long>> listUserRoles(@PathVariable Long id) {
Long currentTenantId = getCurrentTenantId();
if (currentTenantId == null) {
return ApiResponse.error("Tenant ID required");
}
if (!authScopeService.isCurrentPlatformAdmin() && !isUserInTenant(id, currentTenantId)) {
return ApiResponse.error("禁止跨租户查看用户角色");
}
QueryWrapper<SysUserRole> query = new QueryWrapper<SysUserRole>().eq("user_id", id);
if (!authScopeService.isCurrentPlatformAdmin()) {
query.eq("tenant_id", currentTenantId);
}
List<SysUserRole> rows = sysUserRoleMapper.selectList(query);
List<Long> roleIds = new ArrayList<>();
for (SysUserRole row : rows) {
if (row.getRoleId() != null) {
roleIds.add(row.getRoleId());
}
}
return ApiResponse.ok(roleIds);
}
@PostMapping("/{id}/roles")
@PreAuthorize("@ss.hasPermi('sys:user:role:save')")
@Transactional(rollbackFor = Exception.class)
public ApiResponse<Boolean> saveUserRoles(@PathVariable Long id, @RequestBody RoleBindingPayload payload) {
Long currentTenantId = getCurrentTenantId();
if (currentTenantId == null) {
return ApiResponse.error("Tenant ID required");
}
if (!authScopeService.isCurrentPlatformAdmin() && !isUserInTenant(id, currentTenantId)) {
return ApiResponse.error("禁止跨租户分配角色");
}
List<Long> roleIds = payload == null ? null : payload.getRoleIds();
List<com.imeeting.entity.SysRole> rolesToBind = new ArrayList<>();
if (roleIds != null) {
for (Long roleId : roleIds) {
if (roleId == null) {
continue;
}
com.imeeting.entity.SysRole role = sysRoleService.getById(roleId);
if (role == null || role.getRoleId() == null || role.getTenantId() == null) {
return ApiResponse.error("角色不存在:" + roleId);
}
Long roleTenantId = role.getTenantId();
if (!authScopeService.isCurrentPlatformAdmin() && !currentTenantId.equals(roleTenantId)) {
return ApiResponse.error("禁止跨租户分配角色:" + roleId);
}
boolean hasMembership = sysTenantUserService.count(
new LambdaQueryWrapper<com.imeeting.entity.SysTenantUser>()
.eq(com.imeeting.entity.SysTenantUser::getUserId, id)
.eq(com.imeeting.entity.SysTenantUser::getTenantId, roleTenantId)
) > 0;
if (!hasMembership) {
return ApiResponse.error("用户不属于角色所在租户:" + roleTenantId);
}
rolesToBind.add(role);
}
}
QueryWrapper<SysUserRole> scopeQuery = new QueryWrapper<SysUserRole>().eq("user_id", id);
if (!authScopeService.isCurrentPlatformAdmin()) {
scopeQuery.eq("tenant_id", currentTenantId);
}
List<SysUserRole> existingRows = sysUserRoleMapper.selectList(scopeQuery);
java.util.Set<Long> affectedTenantIds = new java.util.HashSet<>();
for (SysUserRole row : existingRows) {
if (row.getTenantId() != null) {
affectedTenantIds.add(row.getTenantId());
}
}
for (com.imeeting.entity.SysRole role : rolesToBind) {
if (role.getTenantId() != null) {
affectedTenantIds.add(role.getTenantId());
}
}
sysUserRoleMapper.delete(scopeQuery);
for (com.imeeting.entity.SysRole role : rolesToBind) {
SysUserRole item = new SysUserRole();
item.setTenantId(role.getTenantId());
item.setUserId(id);
item.setRoleId(role.getRoleId());
sysUserRoleMapper.insert(item);
}
for (Long tenantId : affectedTenantIds) {
authVersionService.invalidateUserTenantAuth(id, tenantId);
}
return ApiResponse.ok(true);
}
private boolean isUserInTenant(Long userId, Long tenantId) {
if (userId == null || tenantId == null) {
return false;
}
return sysTenantUserService.count(
new LambdaQueryWrapper<com.imeeting.entity.SysTenantUser>()
.eq(com.imeeting.entity.SysTenantUser::getUserId, userId)
.eq(com.imeeting.entity.SysTenantUser::getTenantId, tenantId)
) > 0;
}
public static class RoleBindingPayload {
private List<Long> roleIds;
public List<Long> getRoleIds() {
return roleIds;
}
public void setRoleIds(List<Long> roleIds) {
this.roleIds = roleIds;
}
}
}

View File

@ -1,11 +1,13 @@
package com.imeeting.controller.biz;
import com.imeeting.common.ApiResponse;
import com.imeeting.common.PageResult;
import com.imeeting.dto.biz.AiModelDTO;
import com.imeeting.dto.biz.AiModelVO;
import com.imeeting.security.LoginUser;
import com.imeeting.service.biz.AiModelService;
import com.unisbase.common.ApiResponse;
import com.unisbase.dto.PageResult;
import com.unisbase.security.LoginUser;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;

View File

@ -1,9 +1,11 @@
package com.imeeting.controller.biz;
import com.imeeting.common.ApiResponse;
import com.imeeting.dto.biz.MeetingVO;
import com.imeeting.security.LoginUser;
import com.imeeting.service.biz.MeetingService;
import com.unisbase.common.ApiResponse;
import com.unisbase.security.LoginUser;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;

View File

@ -2,13 +2,15 @@ package com.imeeting.controller.biz;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.imeeting.common.ApiResponse;
import com.imeeting.common.PageResult;
import com.imeeting.dto.biz.HotWordDTO;
import com.imeeting.dto.biz.HotWordVO;
import com.imeeting.entity.biz.HotWord;
import com.imeeting.security.LoginUser;
import com.imeeting.service.biz.HotWordService;
import com.unisbase.common.ApiResponse;
import com.unisbase.dto.PageResult;
import com.unisbase.security.LoginUser;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;

View File

@ -1,7 +1,6 @@
package com.imeeting.controller.biz;
import com.imeeting.common.ApiResponse;
import com.imeeting.common.PageResult;
import com.imeeting.common.RedisKeys;
import com.imeeting.dto.biz.MeetingDTO;
import com.imeeting.dto.biz.MeetingTranscriptVO;
@ -10,11 +9,14 @@ import com.imeeting.dto.biz.RealtimeMeetingCompleteDTO;
import com.imeeting.dto.biz.RealtimeTranscriptItemDTO;
import com.imeeting.entity.biz.AiTask;
import com.imeeting.entity.biz.Meeting;
import com.imeeting.security.LoginUser;
import com.imeeting.service.biz.AiTaskService;
import com.imeeting.service.biz.MeetingService;
import com.imeeting.service.biz.PromptTemplateService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.unisbase.common.ApiResponse;
import com.unisbase.dto.PageResult;
import com.unisbase.security.LoginUser;
import org.apache.fontbox.ttf.TrueTypeCollection;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
@ -67,17 +69,20 @@ public class MeetingController {
private final PromptTemplateService promptTemplateService;
private final StringRedisTemplate redisTemplate;
private final String uploadPath;
private final String resourcePrefix;
public MeetingController(MeetingService meetingService,
AiTaskService aiTaskService,
PromptTemplateService promptTemplateService,
StringRedisTemplate redisTemplate,
@Value("${app.upload-path}") String uploadPath) {
@Value("${unisbase.app.upload-path}") String uploadPath,
@Value("${unisbase.app.resource-prefix}") String resourcePrefix) {
this.meetingService = meetingService;
this.aiTaskService = aiTaskService;
this.promptTemplateService = promptTemplateService;
this.redisTemplate = redisTemplate;
this.uploadPath = uploadPath;
this.resourcePrefix = resourcePrefix;
}
@GetMapping("/{id}/progress")
@ -120,8 +125,8 @@ public class MeetingController {
String fileName = UUID.randomUUID() + "_" + file.getOriginalFilename();
file.transferTo(new File(uploadDir + fileName));
return ApiResponse.ok("/api/static/audio/" + fileName);
String baseResourcePrefix = resourcePrefix.endsWith("/") ? resourcePrefix : resourcePrefix + "/";
return ApiResponse.ok(baseResourcePrefix+"audio/" + fileName);
}
@PostMapping

View File

@ -1,12 +1,14 @@
package com.imeeting.controller.biz;
import com.imeeting.common.ApiResponse;
import com.imeeting.common.PageResult;
import com.imeeting.dto.biz.PromptTemplateDTO;
import com.imeeting.dto.biz.PromptTemplateVO;
import com.imeeting.entity.biz.PromptTemplate;
import com.imeeting.security.LoginUser;
import com.imeeting.service.biz.PromptTemplateService;
import com.unisbase.common.ApiResponse;
import com.unisbase.dto.PageResult;
import com.unisbase.security.LoginUser;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;

View File

@ -1,12 +1,14 @@
package com.imeeting.controller.biz;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.imeeting.common.ApiResponse;
import com.imeeting.dto.biz.SpeakerRegisterDTO;
import com.imeeting.dto.biz.SpeakerVO;
import com.imeeting.entity.biz.Speaker;
import com.imeeting.security.LoginUser;
import com.imeeting.service.biz.SpeakerService;
import com.unisbase.common.ApiResponse;
import com.unisbase.security.LoginUser;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;

View File

@ -1,14 +0,0 @@
package com.imeeting.dto;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class CreateTenantDTO {
private String tenantCode;
private String tenantName;
private String contactName;
private String contactPhone;
private String remark;
private LocalDateTime expireTime;
}

View File

@ -1,9 +0,0 @@
package com.imeeting.dto;
import lombok.Data;
@Data
public class PasswordUpdateDTO {
private String oldPassword;
private String newPassword;
}

View File

@ -1,25 +0,0 @@
package com.imeeting.dto;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class PermissionNode {
private Long permId;
private Long parentId;
private String name;
private String code;
private String permType;
private Integer level;
private String path;
private String component;
private String icon;
private Integer sortOrder;
private Integer isVisible;
private Integer status;
private String description;
private String meta;
private List<PermissionNode> children = new ArrayList<>();
}

View File

@ -1,15 +0,0 @@
package com.imeeting.dto;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class PlatformConfigVO {
private String projectName;
private String logoUrl;
private String iconUrl;
private String loginBgUrl;
private String icpInfo;
private String copyrightInfo;
private String systemDescription;
}

View File

@ -1,12 +0,0 @@
package com.imeeting.dto;
import lombok.Data;
@Data
public class SysParamQueryDTO {
private String paramKey;
private String paramType;
private String description;
private Integer pageNum = 1;
private Integer pageSize = 10;
}

View File

@ -1,17 +0,0 @@
package com.imeeting.dto;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class SysParamVO {
private Long paramId;
private String paramKey;
private String paramValue;
private String paramType;
private Integer isSystem;
private String description;
private Integer status;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}

View File

@ -1,19 +0,0 @@
package com.imeeting.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class UserProfile {
private Long userId;
private String username;
private String displayName;
private String email;
private String phone;
private Integer status;
@JsonProperty("isAdmin")
private boolean isAdmin;
private Boolean isPlatformAdmin;
private Boolean isTenantAdmin;
private Integer pwdResetRequired;
}

View File

@ -1,25 +0,0 @@
package com.imeeting.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableLogic;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class BaseEntity {
@TableField(fill = FieldFill.INSERT)
private Long tenantId;
private Integer status;
@TableLogic(value = "0", delval = "1")
private Integer isDeleted;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createdAt;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updatedAt;
}

View File

@ -1,16 +0,0 @@
package com.imeeting.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("device_info")
public class Device extends BaseEntity {
@TableId(value = "device_id", type = IdType.AUTO)
private Long deviceId;
private Long userId;
private String deviceCode;
private String deviceName;
}

View File

@ -1,26 +0,0 @@
package com.imeeting.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("sys_dict_item")
public class SysDictItem extends BaseEntity {
@TableId(value = "dict_item_id", type = IdType.AUTO)
private Long dictItemId;
private String typeCode;
private String itemLabel;
private String itemValue;
private Integer sortOrder;
private String remark;
@TableField(exist = false)
private Long tenantId;
@TableField(exist = false)
private Integer isDeleted;
}

View File

@ -1,24 +0,0 @@
package com.imeeting.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("sys_dict_type")
public class SysDictType extends BaseEntity {
@TableId(value = "dict_type_id", type = IdType.AUTO)
private Long dictTypeId;
private String typeCode;
private String typeName;
private String remark;
@TableField(exist = false)
private Long tenantId;
@TableField(exist = false)
private Integer isDeleted;
}

View File

@ -1,29 +0,0 @@
package com.imeeting.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("sys_log")
public class SysLog {
@TableId(type = IdType.AUTO)
private Long id;
private Long tenantId;
private Long userId;
private String username;
private String logType; // LOGIN, OPERATION
private String operation;
private String method;
private String params;
private Integer status;
private String ip;
private Long duration;
private LocalDateTime createdAt;
@TableField(exist = false)
private String tenantName;
}

View File

@ -1,24 +0,0 @@
package com.imeeting.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("sys_org")
public class SysOrg extends BaseEntity {
@TableId(type = IdType.AUTO)
private Long id;
private Long tenantId;
private Long parentId;
private String orgName;
private String orgCode;
private String orgPath;
private Integer sortOrder;
}

View File

@ -1,29 +0,0 @@
package com.imeeting.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("sys_param")
public class SysParam extends BaseEntity {
@TableId(value = "param_id", type = IdType.AUTO)
private Long paramId;
private String paramKey;
private String paramValue;
private String paramType;
private Integer isSystem;
private String description;
@TableField(exist = false)
private Long tenantId;
}

View File

@ -1,35 +0,0 @@
package com.imeeting.entity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("sys_permission")
public class SysPermission {
@TableId(value = "perm_id", type = IdType.AUTO)
private Long permId;
private Long parentId;
private String name;
private String code;
private String permType;
private Integer level;
private String path;
private String component;
private String icon;
private Integer sortOrder;
private Integer isVisible;
private String description;
private String meta;
private Integer status;
@TableLogic
private Boolean isDeleted;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createdAt;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updatedAt;
}

View File

@ -1,23 +0,0 @@
package com.imeeting.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@TableName("sys_platform_config")
public class SysPlatformConfig {
@TableId
private Long id;
private String projectName;
private String logoUrl;
private String iconUrl;
private String loginBgUrl;
private String icpInfo;
private String copyrightInfo;
private String systemDescription;
}

View File

@ -1,16 +0,0 @@
package com.imeeting.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("sys_role")
public class SysRole extends BaseEntity {
@TableId(value = "role_id", type = IdType.AUTO)
private Long roleId;
private String roleCode;
private String roleName;
private String remark;
}

View File

@ -1,25 +0,0 @@
package com.imeeting.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("sys_role_permission")
public class SysRolePermission {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
private Long roleId;
private Long permId;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createdAt;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updatedAt;
}

View File

@ -1,27 +0,0 @@
package com.imeeting.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.LocalDateTime;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("sys_tenant")
public class SysTenant extends BaseEntity {
@TableId(type = IdType.AUTO)
private Long id;
private String tenantCode;
private String tenantName;
private LocalDateTime expireTime;
private String contactName;
private String contactPhone;
private String remark;
@TableField(exist = false)
private Long tenantId;
}

View File

@ -1,25 +0,0 @@
package com.imeeting.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("sys_tenant_user")
public class SysTenantUser extends BaseEntity {
@TableId(type = IdType.AUTO)
private Long id;
private Long userId;
private Long tenantId;
private Long orgId;
@com.baomidou.mybatisplus.annotation.TableField(exist = false)
private String orgName;
@com.baomidou.mybatisplus.annotation.TableLogic(value = "0", delval = "0")
@com.baomidou.mybatisplus.annotation.TableField(exist = false)
private Integer isDeleted;
}

View File

@ -1,33 +0,0 @@
package com.imeeting.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("sys_user")
public class SysUser extends BaseEntity {
@TableId(value = "user_id", type = IdType.AUTO)
private Long userId;
private String username;
private String displayName;
private String email;
private String phone;
private String passwordHash;
private Integer pwdResetRequired;
private Boolean isPlatformAdmin;
@com.baomidou.mybatisplus.annotation.TableField(exist = false)
private Long tenantId;
@com.baomidou.mybatisplus.annotation.TableField(exist = false)
private Long orgId;
@com.baomidou.mybatisplus.annotation.TableField(exist = false)
private java.util.List<SysTenantUser> memberships;
@com.baomidou.mybatisplus.annotation.TableField(exist = false)
private java.util.List<SysRole> roles;
}

View File

@ -1,29 +0,0 @@
package com.imeeting.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("sys_user_role")
public class SysUserRole {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
private Long tenantId;
private Long userId;
private Long roleId;
@TableLogic(value = "0", delval = "1")
private Integer isDeleted;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createdAt;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updatedAt;
}

View File

@ -5,7 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import com.imeeting.entity.BaseEntity;
import com.unisbase.entity.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;

View File

@ -5,7 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import com.imeeting.entity.BaseEntity;
import com.unisbase.entity.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;

View File

@ -3,7 +3,7 @@ package com.imeeting.entity.biz;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.imeeting.entity.BaseEntity;
import com.unisbase.entity.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;

View File

@ -4,13 +4,11 @@ import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import com.imeeting.entity.BaseEntity;
import com.unisbase.entity.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.LocalDateTime;
import java.util.List;
@Data
@EqualsAndHashCode(callSuper = true)

View File

@ -3,7 +3,7 @@ package com.imeeting.entity.biz;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.imeeting.entity.BaseEntity;
import com.unisbase.entity.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;

View File

@ -3,7 +3,7 @@ package com.imeeting.entity.biz;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.imeeting.entity.BaseEntity;
import com.unisbase.entity.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;

View File

@ -4,7 +4,7 @@ import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.imeeting.entity.BaseEntity;
import com.unisbase.entity.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;

View File

@ -1,8 +0,0 @@
package com.imeeting.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.imeeting.entity.Device;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface DeviceMapper extends BaseMapper<Device> {}

View File

@ -1,9 +0,0 @@
package com.imeeting.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.imeeting.entity.SysDictItem;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface SysDictItemMapper extends BaseMapper<SysDictItem> {
}

View File

@ -1,9 +0,0 @@
package com.imeeting.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.imeeting.entity.SysDictType;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface SysDictTypeMapper extends BaseMapper<SysDictType> {
}

View File

@ -1,24 +0,0 @@
package com.imeeting.mapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.imeeting.entity.SysLog;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
@Mapper
public interface SysLogMapper extends BaseMapper<SysLog> {
@Override
@InterceptorIgnore(tenantLine = "true")
int insert(SysLog entity);
@Select("SELECT l.*, t.tenant_name FROM sys_log l " +
"LEFT JOIN sys_tenant t ON l.tenant_id = t.id " +
"${ew.customSqlSegment}")
IPage<SysLog> selectPageWithTenant(IPage<SysLog> page, @Param(Constants.WRAPPER) Wrapper<SysLog> queryWrapper);
}

View File

@ -1,9 +0,0 @@
package com.imeeting.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.imeeting.entity.SysOrg;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface SysOrgMapper extends BaseMapper<SysOrg> {
}

View File

@ -1,8 +0,0 @@
package com.imeeting.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.imeeting.entity.SysParam;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface SysParamMapper extends BaseMapper<SysParam> {}

View File

@ -1,28 +0,0 @@
package com.imeeting.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.imeeting.entity.SysPermission;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper
public interface SysPermissionMapper extends BaseMapper<SysPermission> {
@com.baomidou.mybatisplus.annotation.InterceptorIgnore(tenantLine = "true")
@Select("""
SELECT DISTINCT p.*
FROM sys_permission p
JOIN sys_role_permission rp ON rp.perm_id = p.perm_id
JOIN sys_role r ON r.role_id = rp.role_id
JOIN sys_user_role ur ON ur.role_id = r.role_id
WHERE p.is_deleted = 0
AND r.is_deleted = 0
AND ur.is_deleted = 0
AND ur.user_id = #{userId}
AND r.tenant_id = #{tenantId}
AND (ur.tenant_id = #{tenantId} OR ur.tenant_id IS NULL)
""")
List<SysPermission> selectByUserId(@Param("userId") Long userId, @Param("tenantId") Long tenantId);
}

View File

@ -1,9 +0,0 @@
package com.imeeting.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.imeeting.entity.SysPlatformConfig;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface SysPlatformConfigMapper extends BaseMapper<SysPlatformConfig> {
}

View File

@ -1,8 +0,0 @@
package com.imeeting.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.imeeting.entity.SysRole;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface SysRoleMapper extends BaseMapper<SysRole> {}

View File

@ -1,19 +0,0 @@
package com.imeeting.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.imeeting.entity.SysRolePermission;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface SysRolePermissionMapper extends BaseMapper<SysRolePermission> {
@Select("""
SELECT DISTINCT role_id
FROM sys_role_permission
WHERE perm_id = #{permId}
""")
List<Long> selectRoleIdsByPermId(@Param("permId") Long permId);
}

View File

@ -1,15 +0,0 @@
package com.imeeting.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.imeeting.entity.SysTenant;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Param;
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
@Mapper
public interface SysTenantMapper extends BaseMapper<SysTenant> {
@InterceptorIgnore(tenantLine = "true")
@Select("SELECT * FROM sys_tenant WHERE id = #{id}")
SysTenant selectByIdIgnoreTenant(@Param("id") Long id);
}

View File

@ -1,9 +0,0 @@
package com.imeeting.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.imeeting.entity.SysTenantUser;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface SysTenantUserMapper extends BaseMapper<SysTenantUser> {
}

View File

@ -1,52 +0,0 @@
package com.imeeting.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.imeeting.entity.SysUser;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Param;
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
import java.util.List;
@Mapper
public interface SysUserMapper extends BaseMapper<SysUser> {
@Select("""
SELECT u.*
FROM sys_user u
JOIN sys_user_role ur ON u.user_id = ur.user_id
WHERE ur.role_id = #{roleId}
AND ur.is_deleted = 0
AND u.is_deleted = 0
""")
List<SysUser> selectUsersByRoleId(@Param("roleId") Long roleId);
@InterceptorIgnore(tenantLine = "true")
@Select("SELECT * FROM sys_user WHERE username = #{username} AND is_deleted = 0")
SysUser selectByUsernameIgnoreTenant(@Param("username") String username);
@InterceptorIgnore(tenantLine = "true")
@Select("SELECT * FROM sys_user WHERE user_id = #{userId} AND is_deleted = 0")
SysUser selectByIdIgnoreTenant(@Param("userId") Long userId);
@InterceptorIgnore(tenantLine = "true")
@Select("<script>" +
"SELECT u.*, tu.org_id as orgId, tu.tenant_id as tenantId " +
"FROM sys_user u " +
"JOIN sys_tenant_user tu ON u.user_id = tu.user_id " +
"WHERE tu.tenant_id = #{tenantId} " +
"<if test='orgId != null'> AND tu.org_id = #{orgId} </if> " +
"AND u.is_deleted = 0 AND tu.is_deleted = 0" +
"</script>")
List<SysUser> selectUsersByTenant(@Param("tenantId") Long tenantId, @Param("orgId") Long orgId);
@InterceptorIgnore(tenantLine = "true")
@Select("""
SELECT t.id as tenantId, t.tenant_code as tenantCode, t.tenant_name as tenantName
FROM sys_tenant t
JOIN sys_tenant_user tu ON t.id = tu.tenant_id
JOIN sys_user u ON u.user_id = tu.user_id
WHERE u.username = #{username} AND u.is_deleted = 0 AND t.is_deleted = 0
ORDER BY t.id ASC
""")
List<com.imeeting.auth.dto.TokenResponse.TenantInfo> selectTenantsByUsername(@Param("username") String username);
}

View File

@ -1,51 +0,0 @@
package com.imeeting.mapper;
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.imeeting.entity.SysUserRole;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface SysUserRoleMapper extends BaseMapper<SysUserRole> {
@Delete("""
DELETE FROM sys_user_role
WHERE role_id = #{roleId} AND user_id = #{userId} AND tenant_id = #{tenantId}
""")
int physicalDelete(@Param("roleId") Long roleId, @Param("userId") Long userId, @Param("tenantId") Long tenantId);
@InterceptorIgnore(tenantLine = "true")
@Select("""
SELECT COUNT(1)
FROM sys_user_role ur
JOIN sys_role r ON r.role_id = ur.role_id
WHERE ur.user_id = #{userId}
AND (ur.tenant_id = #{tenantId} OR ur.tenant_id IS NULL)
AND ur.is_deleted = 0
AND r.is_deleted = 0
AND r.tenant_id = #{tenantId}
AND r.role_code = 'TENANT_ADMIN'
""")
Long countTenantAdminRole(@Param("userId") Long userId, @Param("tenantId") Long tenantId);
@Select("""
SELECT DISTINCT ur.user_id
FROM sys_user_role ur
WHERE ur.role_id = #{roleId}
AND ur.is_deleted = 0
""")
List<Long> selectUserIdsByRoleId(@Param("roleId") Long roleId);
@Select("""
SELECT ur.role_id
FROM sys_user_role ur
WHERE ur.user_id = #{userId}
AND ur.tenant_id = #{tenantId}
AND ur.is_deleted = 0
""")
List<Long> selectRoleIdsByUserIdAndTenantId(@Param("userId") Long userId, @Param("tenantId") Long tenantId);
}

View File

@ -1,63 +0,0 @@
package com.imeeting.security;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
import java.util.Set;
import java.util.stream.Collectors;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class LoginUser implements UserDetails {
private Long userId;
private Long tenantId;
private String username;
private String displayName;
private Boolean isPlatformAdmin;
private Boolean isTenantAdmin;
private Set<String> permissions;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
if (permissions == null) return null;
return permissions.stream()
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
}
@Override
public String getPassword() {
return null;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}

View File

@ -1,41 +0,0 @@
package com.imeeting.security;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.Set;
@Service("ss")
public class PermissionService {
/**
*
*
* @param permission
* @return
*/
public boolean hasPermi(String permission) {
if (permission == null || permission.isEmpty()) {
return false;
}
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || !(authentication.getPrincipal() instanceof LoginUser)) {
return false;
}
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
// 平台管理员在系统租户(0)下放行全部权限点
if (Boolean.TRUE.equals(loginUser.getIsPlatformAdmin())
&& Long.valueOf(0L).equals(loginUser.getTenantId())) {
return true;
}
Set<String> permissions = loginUser.getPermissions();
if (CollectionUtils.isEmpty(permissions)) {
return false;
}
return permissions.contains(permission);
}
}

View File

@ -1,9 +0,0 @@
package com.imeeting.service;
public interface AuthScopeService {
boolean isCurrentPlatformAdmin();
boolean isCurrentTenantAdmin();
boolean isTenantAdmin(Long userId, Long tenantId);
}

View File

@ -1,12 +0,0 @@
package com.imeeting.service;
import com.imeeting.auth.dto.LoginRequest;
import com.imeeting.auth.dto.TokenResponse;
public interface AuthService {
TokenResponse login(LoginRequest request);
TokenResponse refresh(String refreshToken);
void logout(Long userId, String deviceCode);
String createDeviceCode(LoginRequest request, String deviceName);
TokenResponse switchTenant(Long userId, Long targetTenantId, String deviceCode);
}

View File

@ -1,11 +0,0 @@
package com.imeeting.service;
import java.util.Collection;
public interface AuthVersionService {
long getVersion(Long userId, Long tenantId);
void invalidateUserTenantAuth(Long userId, Long tenantId);
void invalidateUsersTenantAuth(Collection<Long> userIds, Long tenantId);
}

View File

@ -1,6 +0,0 @@
package com.imeeting.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.imeeting.entity.Device;
public interface DeviceService extends IService<Device> {}

View File

@ -1,10 +0,0 @@
package com.imeeting.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.imeeting.entity.SysDictItem;
import java.util.List;
public interface SysDictItemService extends IService<SysDictItem> {
List<SysDictItem> getItemsByTypeCode(String typeCode);
}

View File

@ -1,7 +0,0 @@
package com.imeeting.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.imeeting.entity.SysDictType;
public interface SysDictTypeService extends IService<SysDictType> {
}

View File

@ -1,12 +0,0 @@
package com.imeeting.service;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.imeeting.entity.SysLog;
public interface SysLogService extends IService<SysLog> {
void recordLog(SysLog log);
IPage<SysLog> selectPageWithTenant(IPage<SysLog> page, Wrapper<SysLog> queryWrapper);
}

View File

@ -1,9 +0,0 @@
package com.imeeting.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.imeeting.entity.SysOrg;
import java.util.List;
public interface SysOrgService extends IService<SysOrg> {
List<SysOrg> listTree(Long tenantId);
}

View File

@ -1,23 +0,0 @@
package com.imeeting.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.imeeting.common.PageResult;
import com.imeeting.dto.SysParamQueryDTO;
import com.imeeting.dto.SysParamVO;
import com.imeeting.entity.SysParam;
import java.util.List;
public interface SysParamService extends IService<SysParam> {
PageResult<List<SysParamVO>> page(SysParamQueryDTO query);
String getParamValue(String key, String defaultValue);
String getCachedParamValue(String key, String defaultValue);
void syncParamToCache(SysParam param);
void deleteParamCache(String key);
void syncAllToCache();
}

View File

@ -1,13 +0,0 @@
package com.imeeting.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.imeeting.entity.SysPermission;
import java.util.List;
import java.util.Set;
public interface SysPermissionService extends IService<SysPermission> {
List<SysPermission> listByUserId(Long userId, Long tenantId);
Set<String> listPermissionCodesByUserId(Long userId, Long tenantId);
}

View File

@ -1,12 +0,0 @@
package com.imeeting.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.imeeting.entity.SysPlatformConfig;
import com.imeeting.dto.PlatformConfigVO;
import org.springframework.web.multipart.MultipartFile;
public interface SysPlatformConfigService extends IService<SysPlatformConfig> {
PlatformConfigVO getConfig();
boolean updateConfig(SysPlatformConfig config);
String uploadAsset(MultipartFile file);
}

View File

@ -1,6 +0,0 @@
package com.imeeting.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.imeeting.entity.SysRole;
public interface SysRoleService extends IService<SysRole> {}

View File

@ -1,14 +0,0 @@
package com.imeeting.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.imeeting.dto.CreateTenantDTO;
import com.imeeting.entity.SysTenant;
public interface SysTenantService extends IService<SysTenant> {
/**
*
* @param dto
* @return ID
*/
Long createTenantWithAdmin(CreateTenantDTO dto);
}

View File

@ -1,11 +0,0 @@
package com.imeeting.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.imeeting.entity.SysTenantUser;
import java.util.List;
public interface SysTenantUserService extends IService<SysTenantUser> {
List<SysTenantUser> listByUserId(Long userId);
void saveTenantUser(Long userId, Long tenantId, Long orgId);
void syncMemberships(Long userId, List<SysTenantUser> memberships);
}

View File

@ -1,25 +0,0 @@
package com.imeeting.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.imeeting.entity.SysUser;
import java.util.List;
public interface SysUserService extends IService<SysUser> {
List<SysUser> listUsersByRoleId(Long roleId);
SysUser getByIdIgnoreTenant(Long userId);
List<SysUser> listUsersByTenant(Long tenantId, Long orgId);
}

View File

@ -1,8 +1,9 @@
package com.imeeting.service.biz;
import com.imeeting.common.PageResult;
import com.imeeting.dto.biz.AiModelDTO;
import com.imeeting.dto.biz.AiModelVO;
import com.unisbase.dto.PageResult;
import java.util.List;

View File

@ -1,12 +1,13 @@
package com.imeeting.service.biz;
import com.baomidou.mybatisplus.extension.service.IService;
import com.imeeting.common.PageResult;
import com.imeeting.dto.biz.MeetingDTO;
import com.imeeting.dto.biz.RealtimeTranscriptItemDTO;
import com.imeeting.dto.biz.MeetingTranscriptVO;
import com.imeeting.dto.biz.MeetingVO;
import com.imeeting.entity.biz.Meeting;
import com.unisbase.dto.PageResult;
import java.util.List;

Some files were not shown because too many files have changed in this diff Show More