|
|
@@ -12,62 +12,84 @@ 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 String ALPHABETS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
|
private final Random random = new Random();
|
|
|
|
|
|
@Override
|
|
|
public ForkVO forkProject(ForkVO forkVO) {
|
|
|
+ if (forkVO == null || forkVO.getProjectId() == null) {
|
|
|
+ log.error("fork 参数非法, forkVO={}", forkVO);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ if (SecurityContextHolder.getContext().getAuthentication() == null
|
|
|
+ || !(SecurityContextHolder.getContext().getAuthentication().getPrincipal() instanceof UserPO)) {
|
|
|
+ log.error("未登录或登录态异常, projectId={}", forkVO.getProjectId());
|
|
|
+ return null;
|
|
|
+ }
|
|
|
UserPO principal = (UserPO) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
|
|
Integer userId = principal.getId();
|
|
|
try {
|
|
|
ProjectPO oldProject = projectMapper.getProjectById(forkVO.getProjectId());
|
|
|
if (oldProject == null) {
|
|
|
- log.error("不存在想要 Fork 的项目 id: " + forkVO.getProjectId());
|
|
|
+ log.error("不存在想要 Fork 的项目 id={}", forkVO.getProjectId());
|
|
|
return null;
|
|
|
}
|
|
|
- StringBuilder sb = new StringBuilder(oldProject.getName() + "-");
|
|
|
- for (int i = 0; i < 6; ++i) {
|
|
|
- sb.append(ALPHABETS.charAt(random.nextInt(ALPHABETS.length())));
|
|
|
- }
|
|
|
- String newName = sb.toString();
|
|
|
+
|
|
|
List<com.nju.edu.gitlab.vo.ProjectVO> allProjects = gitlabApi.getAllProjectsByUserId(userId);
|
|
|
- // 检测是否已经有重名项目
|
|
|
- for (com.nju.edu.gitlab.vo.ProjectVO project: allProjects) {
|
|
|
- if (Objects.equals(project.getProjectName(), newName)) {
|
|
|
- log.error("存在重名项目,项目名:" + newName);
|
|
|
- return null;
|
|
|
+ if (allProjects == null) {
|
|
|
+ log.error("获取用户项目列表失败, userId={}", userId);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Set<String> existingNames = new HashSet<>();
|
|
|
+ for (com.nju.edu.gitlab.vo.ProjectVO project : allProjects) {
|
|
|
+ if (project != null && project.getProjectName() != null) {
|
|
|
+ existingNames.add(project.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);
|
|
|
+ if (newProjectId == null) {
|
|
|
+ log.error("Fork API 未返回项目 id, sourceProjectId={}, userId={}", forkVO.getProjectId(), userId);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
allProjects = gitlabApi.getAllProjectsByUserId(userId);
|
|
|
// 拿 Fork 出来的项目的对象,主要是要拿到它的 Web URL
|
|
|
- com.nju.edu.gitlab.vo.ProjectVO newProject = null;
|
|
|
- for (com.nju.edu.gitlab.vo.ProjectVO project: allProjects) {
|
|
|
- if (Objects.equals(project.getProjectId(), newProjectId)) {
|
|
|
- newProject = project;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
+ com.nju.edu.gitlab.vo.ProjectVO newProject = allProjects.stream()
|
|
|
+ .filter(Objects::nonNull)
|
|
|
+ .filter(project -> Objects.equals(project.getProjectId(), newProjectId))
|
|
|
+ .findFirst()
|
|
|
+ .orElse(null);
|
|
|
if (newProject == null) {
|
|
|
- log.error("未知错误,貌似没有成功创建 Fork 出来的项目,新项目不存在,新 id: " + newProjectId);
|
|
|
+ log.error("未知错误,貌似没有成功创建 Fork 出来的项目,新项目不存在,新 id={}", newProjectId);
|
|
|
return null;
|
|
|
}
|
|
|
+
|
|
|
// 向 Devcloud 数据库中插入新项目的 PO
|
|
|
// 添加 Gitlab Web Hook 回调
|
|
|
ProjectPO projectPO = new ProjectPO(newProjectId,
|
|
|
- newName,
|
|
|
+ newProject.getProjectName() == null ? newName : newProject.getProjectName(),
|
|
|
newProject.getWebUrl(),
|
|
|
oldProject.getDescription(),
|
|
|
false);
|
|
|
@@ -84,4 +106,21 @@ public class ForkServiceImpl implements ForkService {
|
|
|
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;
|
|
|
+ }
|
|
|
}
|