!13 LDAP优化增强

* cursorrules
* fixed: ldap同步的部门记录name记录错误
* 主题色一致
* changelog
* admin接入ldap同步数据统计
* ldap同步数据记录接口合并
* fixed: 已同步被禁用用户的DN更新
* 已经同步的LDAP用户被禁止可以继续更新
* 优化代码
* 新增LDAP同步的详细记录
* 新增LDAP禁止用户的数据量统计
* 优化LDAP拉取数据的重复使用
* 优化LDAP同步
* ldap同步记录
* cursor rules
This commit is contained in:
白书科技
2025-05-19 06:25:34 +00:00
parent b9f600d3bc
commit c206fa4bf2
40 changed files with 2588 additions and 39 deletions

View File

@@ -334,8 +334,26 @@ public class DepartmentController {
@Log(title = "部门-LDAP同步", businessType = BusinessTypeConstant.INSERT)
@SneakyThrows
public JsonResponse ldapSync() {
ldapBus.departmentSync();
ldapBus.userSync();
return JsonResponse.success();
try {
// 检查是否启用LDAP
if (!ldapBus.enabledLDAP()) {
return JsonResponse.error("未配置LDAP服务");
}
// 检查是否有进行中的同步任务
if (ldapBus.hasSyncInProgress()) {
return JsonResponse.error("有正在进行的LDAP同步任务请稍后再试");
}
// 使用当前管理员ID执行同步
Integer recordId = ldapBus.syncAndRecord(BCtx.getId());
Map<String, Object> data = new HashMap<>();
data.put("record_id", recordId);
return JsonResponse.data(data);
} catch (Exception e) {
return JsonResponse.error("LDAP同步失败: " + e.getMessage());
}
}
}

View File

@@ -0,0 +1,95 @@
/*
* Copyright (C) 2023 杭州白书科技有限公司
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package xyz.playedu.api.controller.backend;
import java.util.HashMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import xyz.playedu.common.annotation.BackendPermission;
import xyz.playedu.common.annotation.Log;
import xyz.playedu.common.constant.BPermissionConstant;
import xyz.playedu.common.constant.BusinessTypeConstant;
import xyz.playedu.common.domain.LdapSyncRecord;
import xyz.playedu.common.service.AppConfigService;
import xyz.playedu.common.service.LdapSyncRecordService;
import xyz.playedu.common.types.JsonResponse;
import xyz.playedu.common.types.config.S3Config;
import xyz.playedu.common.types.paginate.PaginationResult;
import xyz.playedu.common.util.S3Util;
@RestController
@RequestMapping("/backend/v1/ldap")
public class LdapController {
@Autowired private LdapSyncRecordService ldapSyncRecordService;
@Autowired private AppConfigService appConfigService;
@BackendPermission(slug = BPermissionConstant.DEPARTMENT_CUD)
@GetMapping("/sync-records")
@Log(title = "LDAP-同步记录列表", businessType = BusinessTypeConstant.GET)
public JsonResponse syncRecords(
@RequestParam(value = "page", defaultValue = "1") Integer page,
@RequestParam(value = "size", defaultValue = "10") Integer size) {
PaginationResult<LdapSyncRecord> result = ldapSyncRecordService.paginate(page, size);
HashMap<String, Object> data = new HashMap<>();
data.put("data", result.getData());
data.put("total", result.getTotal());
return JsonResponse.data(data);
}
@BackendPermission(slug = BPermissionConstant.DEPARTMENT_CUD)
@GetMapping("/sync-records/{id}")
@Log(title = "LDAP-同步记录详情", businessType = BusinessTypeConstant.GET)
public JsonResponse syncRecordDetail(@PathVariable Integer id) {
LdapSyncRecord record = ldapSyncRecordService.getById(id);
if (record == null) {
return JsonResponse.error("记录不存在");
}
return JsonResponse.data(record);
}
@BackendPermission(slug = BPermissionConstant.DEPARTMENT_CUD)
@GetMapping("/sync-records/{id}/download")
@Log(title = "LDAP-同步记录下载", businessType = BusinessTypeConstant.GET)
public JsonResponse syncRecordDownload(@PathVariable Integer id) {
LdapSyncRecord record = ldapSyncRecordService.getById(id);
if (record == null) {
return JsonResponse.error("记录不存在");
}
if (record.getS3FilePath() == null || record.getS3FilePath().isEmpty()) {
return JsonResponse.error("同步记录文件不存在");
}
try {
// 生成下载URL
S3Config s3Config = appConfigService.getS3Config();
S3Util s3Util = new S3Util(s3Config);
String url = s3Util.generateEndpointPreSignUrl(record.getS3FilePath());
HashMap<String, Object> data = new HashMap<>();
data.put("url", url);
return JsonResponse.data(data);
} catch (Exception e) {
return JsonResponse.error("生成下载链接失败: " + e.getMessage());
}
}
}

View File

@@ -0,0 +1,91 @@
/*
* Copyright (C) 2023 杭州白书科技有限公司
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package xyz.playedu.api.controller.backend;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import xyz.playedu.common.annotation.BackendPermission;
import xyz.playedu.common.constant.BPermissionConstant;
import xyz.playedu.common.domain.LdapSyncDepartmentDetail;
import xyz.playedu.common.domain.LdapSyncUserDetail;
import xyz.playedu.common.service.LdapSyncDepartmentDetailService;
import xyz.playedu.common.service.LdapSyncUserDetailService;
import xyz.playedu.common.types.JsonResponse;
/** LDAP同步详情控制器 */
@RestController
@RequestMapping("/backend/v1/ldap")
public class LdapSyncDetailController {
@Autowired private LdapSyncDepartmentDetailService ldapSyncDepartmentDetailService;
@Autowired private LdapSyncUserDetailService ldapSyncUserDetailService;
/**
* 获取同步详情
*
* @param id 同步记录ID
* @param type 详情类型department-部门user-用户
* @param action 操作类型:
* - 部门1-新增2-更新3-删除4-无变化
* - 用户1-新增2-更新3-删除4-无变化5-禁止
* @param page 页码
* @param size 每页数量
* @return 分页结果
*/
@BackendPermission(slug = BPermissionConstant.DEPARTMENT_CUD)
@GetMapping("/sync-records/{id}/details")
public JsonResponse getDetails(
@PathVariable Integer id,
@RequestParam String type,
@RequestParam(defaultValue = "0") Integer action,
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer size) {
if ("department".equals(type)) {
// 部门同步详情
QueryWrapper<LdapSyncDepartmentDetail> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("record_id", id);
if (action > 0) {
queryWrapper.eq("action", action);
}
queryWrapper.orderByDesc("id");
IPage<LdapSyncDepartmentDetail> pageResult =
ldapSyncDepartmentDetailService.page(new Page<>(page, size), queryWrapper);
return JsonResponse.data(pageResult);
} else if ("user".equals(type)) {
// 用户同步详情
QueryWrapper<LdapSyncUserDetail> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("record_id", id);
if (action > 0) {
queryWrapper.eq("action", action);
}
queryWrapper.orderByDesc("id");
IPage<LdapSyncUserDetail> pageResult =
ldapSyncUserDetailService.page(new Page<>(page, size), queryWrapper);
return JsonResponse.data(pageResult);
}
return JsonResponse.error("不支持的详情类型");
}
}

View File

@@ -43,17 +43,11 @@ public class LDAPSchedule {
}
try {
ldapBus.departmentSync();
// 使用新的同步记录功能
ldapBus.syncAndRecord(0); // 0表示系统自动执行
log.info("LDAP同步成功");
} catch (Exception e) {
log.error("LDAP-部门同步失败", e);
log.error("LDAP同步失败", e);
}
try {
ldapBus.userSync();
} catch (Exception e) {
log.error("LDAP-学员同步失败", e);
}
log.info("LDAP同步成功");
}
}