|
|
@@ -12,23 +12,16 @@ import lombok.extern.slf4j.Slf4j;
|
|
|
import org.springframework.security.core.context.SecurityContextHolder;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
-import java.util.HashSet;
|
|
|
import java.util.List;
|
|
|
import java.util.Objects;
|
|
|
-import java.util.Random;
|
|
|
-import java.util.Set;
|
|
|
|
|
|
@RequiredArgsConstructor
|
|
|
@Service
|
|
|
@Slf4j
|
|
|
public class ForkServiceImpl implements ForkService {
|
|
|
- private static final String ALPHABETS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
|
- private static final int FORK_NAME_SUFFIX_LEN = 6;
|
|
|
- private static final int MAX_RETRY = 10;
|
|
|
private final SeecoderGitlabApi gitlabApi;
|
|
|
private final ProjectMapper projectMapper;
|
|
|
private final ApplicationProperties properties;
|
|
|
- private final Random random = new Random();
|
|
|
|
|
|
@Override
|
|
|
public ForkVO forkProject(ForkVO forkVO) {
|
|
|
@@ -55,18 +48,31 @@ public class ForkServiceImpl implements ForkService {
|
|
|
log.error("获取用户项目列表失败, userId={}", userId);
|
|
|
return null;
|
|
|
}
|
|
|
+ // Fallback流程
|
|
|
+ for (com.nju.edu.gitlab.vo.ProjectVO projectVO : allProjects) {
|
|
|
+ if (projectVO == null || projectVO.getProjectName() == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (Objects.equals(projectVO.getProjectName(), oldProject.getName())) {
|
|
|
+ log.warn("该项目已被 fork, sourceProjectId={}, userId={}, existedProjectId={}",
|
|
|
+ forkVO.getProjectId(), userId, projectVO.getProjectId());
|
|
|
+ Integer existedProjectId = projectVO.getProjectId();
|
|
|
|
|
|
- Set<String> existingNames = new HashSet<>();
|
|
|
- for (com.nju.edu.gitlab.vo.ProjectVO project : allProjects) {
|
|
|
- if (project != null && project.getProjectName() != null) {
|
|
|
- existingNames.add(project.getProjectName());
|
|
|
+ // 检查 Devcloud 数据库中是否有该 fork 项目;缺失时补写。
|
|
|
+ ProjectPO existedProject = projectMapper.getProjectByIdIncludeDeleted(existedProjectId);
|
|
|
+ if (existedProject == null) {
|
|
|
+ ProjectPO projectPO = new ProjectPO(existedProjectId,
|
|
|
+ projectVO.getProjectName(),
|
|
|
+ projectVO.getWebUrl(),
|
|
|
+ oldProject.getDescription(),
|
|
|
+ false);
|
|
|
+ projectMapper.insertProject(projectPO);
|
|
|
+ } else if (Boolean.TRUE.equals(existedProject.getIsDeleted())) {
|
|
|
+ projectMapper.recoverProjectById(existedProjectId);
|
|
|
+ }
|
|
|
+ return new ForkVO(existedProjectId, projectVO.getProjectName());
|
|
|
}
|
|
|
}
|
|
|
- String newName = generateAvailableForkName(oldProject.getName(), existingNames);
|
|
|
- if (newName == null) {
|
|
|
- log.error("生成 Fork 项目名失败, baseName={}", oldProject.getName());
|
|
|
- return null;
|
|
|
- }
|
|
|
|
|
|
// TODO 软工二没有userName与examId,这里先传null
|
|
|
Integer newProjectId = gitlabApi.forkProject(forkVO.getProjectId(), userId, null, null);
|
|
|
@@ -75,6 +81,10 @@ public class ForkServiceImpl implements ForkService {
|
|
|
return null;
|
|
|
}
|
|
|
allProjects = gitlabApi.getAllProjectsByUserId(userId);
|
|
|
+ if (allProjects == null) {
|
|
|
+ log.error("Fork 后获取用户项目列表失败, sourceProjectId={}, userId={}", forkVO.getProjectId(), userId);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
// 拿 Fork 出来的项目的对象,主要是要拿到它的 Web URL
|
|
|
com.nju.edu.gitlab.vo.ProjectVO newProject = allProjects.stream()
|
|
|
.filter(Objects::nonNull)
|
|
|
@@ -89,7 +99,7 @@ public class ForkServiceImpl implements ForkService {
|
|
|
// 向 Devcloud 数据库中插入新项目的 PO
|
|
|
// 添加 Gitlab Web Hook 回调
|
|
|
ProjectPO projectPO = new ProjectPO(newProjectId,
|
|
|
- newProject.getProjectName() == null ? newName : newProject.getProjectName(),
|
|
|
+ newProject.getProjectName(),
|
|
|
newProject.getWebUrl(),
|
|
|
oldProject.getDescription(),
|
|
|
false);
|
|
|
@@ -99,27 +109,10 @@ public class ForkServiceImpl implements ForkService {
|
|
|
true,
|
|
|
false,
|
|
|
false);
|
|
|
- return new ForkVO(newProjectId, newName);
|
|
|
+ return new ForkVO(newProjectId, newProject.getProjectName());
|
|
|
} catch (Exception e) {
|
|
|
log.error("Fork API failed, projectId={}, userId={}, exceptionType={}",
|
|
|
forkVO.getProjectId(), userId, e.getClass().getName(), e);
|
|
|
- return null;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private String generateAvailableForkName(String baseName, Set<String> existingNames) {
|
|
|
- if (baseName == null || baseName.isEmpty()) {
|
|
|
- return null;
|
|
|
- }
|
|
|
- for (int i = 0; i < MAX_RETRY; i++) {
|
|
|
- StringBuilder sb = new StringBuilder(baseName).append('-');
|
|
|
- for (int j = 0; j < FORK_NAME_SUFFIX_LEN; ++j) {
|
|
|
- sb.append(ALPHABETS.charAt(random.nextInt(ALPHABETS.length())));
|
|
|
- }
|
|
|
- String candidate = sb.toString();
|
|
|
- if (!existingNames.contains(candidate)) {
|
|
|
- return candidate;
|
|
|
- }
|
|
|
}
|
|
|
return null;
|
|
|
}
|