org.dromara.jpom.controller.build.RepositoryController Maven / Gradle / Ivy
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Code Technology Studio
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package org.dromara.jpom.controller.build;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.io.BomReader;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.Tuple;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.text.csv.*;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.db.Entity;
import cn.hutool.db.Page;
import cn.hutool.extra.servlet.ServletUtil;
import cn.keepbx.jpom.IJsonMessage;
import cn.keepbx.jpom.model.JsonMessage;
import cn.keepbx.jpom.plugins.IPlugin;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.dromara.jpom.build.BuildUtil;
import org.dromara.jpom.common.BaseServerController;
import org.dromara.jpom.common.ServerConst;
import org.dromara.jpom.common.validator.ValidatorItem;
import org.dromara.jpom.controller.build.repository.ImportRepoUtil;
import org.dromara.jpom.model.PageResultDto;
import org.dromara.jpom.model.data.RepositoryModel;
import org.dromara.jpom.model.enums.GitProtocolEnum;
import org.dromara.jpom.permission.ClassFeature;
import org.dromara.jpom.permission.Feature;
import org.dromara.jpom.permission.MethodFeature;
import org.dromara.jpom.permission.SystemPermission;
import org.dromara.jpom.plugin.PluginFactory;
import org.dromara.jpom.service.dblog.BuildInfoService;
import org.dromara.jpom.service.dblog.RepositoryService;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* Repository controller
*
* @author Hotstrip
*/
@RestController
@Feature(cls = ClassFeature.BUILD_REPOSITORY)
@Slf4j
public class RepositoryController extends BaseServerController {
private final RepositoryService repositoryService;
private final BuildInfoService buildInfoService;
public RepositoryController(RepositoryService repositoryService,
BuildInfoService buildInfoService) {
this.repositoryService = repositoryService;
this.buildInfoService = buildInfoService;
}
/**
* load repository list
*
* @return json
*/
@PostMapping(value = "/build/repository/list")
@Feature(method = MethodFeature.LIST)
public Object loadRepositoryList(HttpServletRequest request) {
PageResultDto pageResult = repositoryService.listPage(request);
return JsonMessage.success("获取成功", pageResult);
}
/**
* load build list with params
*
* @return json
*/
@GetMapping(value = "/build/repository/list-group", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.LIST)
public IJsonMessage> getBuildGroupAll() {
// load list with page
List group = repositoryService.listGroup();
return JsonMessage.success("", group);
}
/**
* 下载导入模板
*/
@GetMapping(value = "/build/repository/import-template", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.LIST)
public void importTemplate(HttpServletResponse response) throws IOException {
String fileName = "仓库信息导入模板.csv";
this.setApplicationHeader(response, fileName);
//
CsvWriter writer = CsvUtil.getWriter(response.getWriter());
writer.writeLine("name", "address", "type", "protocol", "share", "private rsa", "username", "password", "timeout(s)");
writer.flush();
}
/**
* export repository by csv
*/
@GetMapping(value = "/build/repository/export")
@Feature(method = MethodFeature.DOWNLOAD)
@SystemPermission
public void exportRepositoryList(HttpServletRequest request, HttpServletResponse response) throws IOException {
String fileName = "导出的 仓库信息 数据 " + DateTime.now().toString(DatePattern.NORM_DATE_FORMAT) + ".csv";
this.setApplicationHeader(response, fileName);
CsvWriter writer = CsvUtil.getWriter(response.getWriter());
int pageInt = 0;
Map paramMap = ServletUtil.getParamMap(request);
writer.writeLine("name", "group", "address", "type", "protocol", "private rsa", "username", "password", "timeout(s)");
while (true) {
// 下一页
paramMap.put("page", String.valueOf(++pageInt));
PageResultDto listPage = repositoryService.listPage(paramMap, false);
if (listPage.isEmpty()) {
break;
}
listPage.getResult()
.stream()
.map((Function>) repositoryModel -> CollUtil.newArrayList(
repositoryModel.getName(),
repositoryModel.getGroup(),
repositoryModel.getGitUrl(),
EnumUtil.likeValueOf(RepositoryModel.RepoType.class, repositoryModel.getRepoType()),
EnumUtil.likeValueOf(GitProtocolEnum.class, repositoryModel.getProtocol()),
repositoryModel.getRsaPrv(),
repositoryModel.getUserName(),
repositoryModel.getPassword(),
repositoryModel.getTimeout()
))
.map(objects -> objects.stream().map(StrUtil::toStringOrNull).toArray(String[]::new))
.forEach(writer::writeLine);
if (ObjectUtil.equal(listPage.getPage(), listPage.getTotalPage())) {
// 最后一页
break;
}
}
writer.flush();
}
/**
* 导入数据
*
* @return json
*/
@PostMapping(value = "/build/repository/import-data", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.UPLOAD)
@SystemPermission
public IJsonMessage importData(MultipartFile file, HttpServletRequest request) throws IOException {
Assert.notNull(file, "没有上传文件");
String originalFilename = file.getOriginalFilename();
String extName = FileUtil.extName(originalFilename);
Assert.state(StrUtil.endWithIgnoreCase(extName, "csv"), "不允许的文件格式");
BomReader bomReader = IoUtil.getBomReader(file.getInputStream());
CsvReadConfig csvReadConfig = CsvReadConfig.defaultConfig();
csvReadConfig.setHeaderLineNo(0);
CsvReader reader = CsvUtil.getReader(bomReader, csvReadConfig);
CsvData csvData;
try {
csvData = reader.read();
} catch (Exception e) {
log.error("解析 csv 异常", e);
return new JsonMessage<>(405, "解析文件异常," + e.getMessage());
}
List rows = csvData.getRows();
Assert.notEmpty(rows, "没有任何数据");
int addCount = 0, updateCount = 0;
for (int i = 0; i < rows.size(); i++) {
int finalI = i;
CsvRow csvRow = rows.get(i);
String name = csvRow.getByName("name");
Assert.hasText(name, () -> StrUtil.format("第 {} 行 name 字段不能位空", finalI + 1));
String group = csvRow.getByName("group");
String address = csvRow.getByName("address");
Assert.hasText(address, () -> StrUtil.format("第 {} 行 address 字段不能位空", finalI + 1));
String type = csvRow.getByName("type");
Assert.hasText(type, () -> StrUtil.format("第 {} 行 type 字段不能位空", finalI + 1));
RepositoryModel.RepoType repoType = null;
if ("Git".equalsIgnoreCase(type)) {
repoType = RepositoryModel.RepoType.Git;
} else if ("Svn".equalsIgnoreCase(type)) {
repoType = RepositoryModel.RepoType.Svn;
}
Assert.notNull(repoType, () -> StrUtil.format("第 {} 行 type 字段值错误(Git/Svn)", finalI + 1));
String protocol = csvRow.getByName("protocol");
Assert.hasText(protocol, () -> StrUtil.format("第 {} 行 protocol 字段不能位空", finalI + 1));
GitProtocolEnum gitProtocolEnum = null;
if ("http".equalsIgnoreCase(protocol) || "https".equalsIgnoreCase(protocol)) {
gitProtocolEnum = GitProtocolEnum.HTTP;
} else if ("ssh".equalsIgnoreCase(protocol)) {
gitProtocolEnum = GitProtocolEnum.SSH;
}
Assert.notNull(gitProtocolEnum, () -> StrUtil.format("第 {} 行 protocol 字段值错误(http/http/ssh)", finalI + 1));
String privateRsa = csvRow.getByName("private rsa");
String username = csvRow.getByName("username");
String password = csvRow.getByName("password");
Integer timeout = Convert.toInt(csvRow.getByName("timeout(s)"));
//
String optWorkspaceId = repositoryService.covertGlobalWorkspace(request);
RepositoryModel where = new RepositoryModel();
where.setProtocol(gitProtocolEnum.getCode());
where.setGitUrl(address);
// 工作空间
where.setWorkspaceId(optWorkspaceId);
// 查询是否存在
RepositoryModel repositoryModel = repositoryService.queryByBean(where);
//
where.setName(name);
where.setGroup(group);
where.setTimeout(timeout);
where.setPassword(password);
where.setRsaPrv(privateRsa);
where.setRepoType(repoType.getCode());
where.setUserName(username);
// 检查 rsa 私钥
boolean andUpdateSshKey = this.checkAndUpdateSshKey(where);
Assert.state(andUpdateSshKey, StrUtil.format("第 {} 行 rsa 私钥文件不存在或者有误", finalI + 1));
if (where.getRepoType() == RepositoryModel.RepoType.Git.getCode()) {
// 验证 git 仓库信息
try {
IPlugin plugin = PluginFactory.getPlugin("git-clone");
Map map = where.toMap();
Tuple branchAndTagList = (Tuple) plugin.execute("branchAndTagList", map);
//Tuple tuple = GitUtil.getBranchAndTagList(repositoryModelReq);
} catch (Exception e) {
log.warn("获取仓库分支失败", e);
throw new IllegalStateException(StrUtil.format("第 {} 行 仓库信息有误", finalI + 1));
}
}
if (repositoryModel == null) {
// 添加
repositoryService.insert(where);
addCount++;
} else {
where.setId(repositoryModel.getId());
repositoryService.updateById(where);
updateCount++;
}
}
return JsonMessage.success("导入成功,添加 {} 条数据,修改 {} 条数据", addCount, updateCount);
}
/**
* load repository list
*
* @return json
*/
@GetMapping(value = "/build/repository/get")
@Feature(method = MethodFeature.LIST)
public IJsonMessage loadRepositoryGet(String id, HttpServletRequest request) {
RepositoryModel repositoryModel = repositoryService.getByKey(id, request);
Assert.notNull(repositoryModel, "没有对应的仓库");
return JsonMessage.success("", repositoryModel);
}
/**
* 过滤前端多余避免核心字段被更新
*
* @param repositoryModelReq 仓库对象
* @return 可以更新的对象
*/
private RepositoryModel convertRequest(RepositoryModel repositoryModelReq) {
RepositoryModel repositoryModel = new RepositoryModel();
repositoryModel.setName(repositoryModelReq.getName());
repositoryModel.setGroup(repositoryModelReq.getGroup());
repositoryModel.setUserName(repositoryModelReq.getUserName());
repositoryModel.setId(repositoryModelReq.getId());
repositoryModel.setProtocol(repositoryModelReq.getProtocol());
repositoryModel.setTimeout(repositoryModelReq.getTimeout());
repositoryModel.setGitUrl(repositoryModelReq.getGitUrl());
repositoryModel.setPassword(repositoryModelReq.getPassword());
repositoryModel.setRepoType(repositoryModelReq.getRepoType());
repositoryModel.setSortValue(repositoryModelReq.getSortValue());
repositoryModel.setRsaPrv(repositoryModelReq.getRsaPrv());
return repositoryModel;
}
/**
* edit
*
* @param req 仓库实体
* @return json
*/
@PostMapping(value = "/build/repository/edit")
@Feature(method = MethodFeature.EDIT)
public IJsonMessage editRepository(RepositoryModel req, HttpServletRequest request) {
RepositoryModel repositoryModelReq = this.convertRequest(req);
repositoryModelReq.setWorkspaceId(repositoryService.covertGlobalWorkspace(request));
this.checkInfo(repositoryModelReq, request);
// 检查 rsa 私钥
boolean andUpdateSshKey = this.checkAndUpdateSshKey(repositoryModelReq);
Assert.state(andUpdateSshKey, "rsa 私钥文件不存在或者有误");
if (repositoryModelReq.getRepoType() == RepositoryModel.RepoType.Git.getCode()) {
RepositoryModel repositoryModel = repositoryService.getByKey(repositoryModelReq.getId(), false);
if (repositoryModel != null) {
repositoryModelReq.setRsaPrv(StrUtil.emptyToDefault(repositoryModelReq.getRsaPrv(), repositoryModel.getRsaPrv()));
repositoryModelReq.setPassword(StrUtil.emptyToDefault(repositoryModelReq.getPassword(), repositoryModel.getPassword()));
}
// 验证 git 仓库信息
try {
IPlugin plugin = PluginFactory.getPlugin("git-clone");
Map map = repositoryModelReq.toMap();
Tuple branchAndTagList = (Tuple) plugin.execute("branchAndTagList", map);
//Tuple tuple = GitUtil.getBranchAndTagList(repositoryModelReq);
} catch (Exception e) {
log.warn("获取仓库分支失败", e);
return new JsonMessage<>(500, "无法连接此仓库," + e.getMessage());
}
}
if (StrUtil.isEmpty(repositoryModelReq.getId())) {
// insert data
repositoryService.insert(repositoryModelReq);
} else {
// update data
repositoryService.getByKeyAndGlobal(repositoryModelReq.getId(), request);
//repositoryModelReq.setWorkspaceId(repositoryService.getCheckUserWorkspace(getRequest()));
repositoryService.updateById(repositoryModelReq);
}
return new JsonMessage<>(200, "操作成功");
}
/**
* edit
*
* @param id 仓库信息
* @return json
*/
@PostMapping(value = "/build/repository/rest_hide_field")
@Feature(method = MethodFeature.EDIT)
public IJsonMessage restHideField(@ValidatorItem String id, HttpServletRequest request) {
RepositoryModel byKeyAndGlobal = repositoryService.getByKeyAndGlobal(id, request);
RepositoryModel repositoryModel = new RepositoryModel();
repositoryModel.setId(byKeyAndGlobal.getId());
repositoryModel.setPassword(StrUtil.EMPTY);
repositoryModel.setRsaPrv(StrUtil.EMPTY);
repositoryModel.setRsaPub(StrUtil.EMPTY);
repositoryService.updateById(repositoryModel, request);
return new JsonMessage<>(200, "操作成功");
}
@GetMapping(value = "/build/repository/provider_info")
@Feature(method = MethodFeature.LIST)
public IJsonMessage
© 2015 - 2024 Weber Informatics LLC | Privacy Policy