Browse Source

Merge branch 'dev-cyz' into xzh

# Conflicts:
#	web/src/main/java/seecoder/devcloud/web/service/impl/tree/TreeNodeServiceImpl.java
woooodyy 5 years ago
parent
commit
61d951cd38
21 changed files with 809 additions and 7 deletions
  1. 23 0
      src/main/java/generator/Project.java
  2. 17 0
      src/main/java/seecoder/devcloud/web/dao/ProjectDao.java
  3. 87 0
      src/main/resources/generator/ProjectDao.xml
  4. 16 0
      web/src/main/java/seecoder/devcloud/web/aop/TreeLogging.java
  5. 73 0
      web/src/main/java/seecoder/devcloud/web/aspect/TreeLoggingAspect.java
  6. 56 0
      web/src/main/java/seecoder/devcloud/web/controller/project/ProjectController.java
  7. 47 0
      web/src/main/java/seecoder/devcloud/web/dao/project/ProjectMapper.java
  8. 29 0
      web/src/main/java/seecoder/devcloud/web/dao/tree/TreeLogMapper.java
  9. 4 0
      web/src/main/java/seecoder/devcloud/web/dao/user/GroupMemberMapper.java
  10. 22 0
      web/src/main/java/seecoder/devcloud/web/enums/OperationEnum.java
  11. 21 0
      web/src/main/java/seecoder/devcloud/web/po/project/Project.java
  12. 40 0
      web/src/main/java/seecoder/devcloud/web/po/tree/TreeLog.java
  13. 57 0
      web/src/main/java/seecoder/devcloud/web/service/impl/project/ProjectServiceImpl.java
  14. 2 7
      web/src/main/java/seecoder/devcloud/web/service/impl/tree/TreeNodeServiceImpl.java
  15. 40 0
      web/src/main/java/seecoder/devcloud/web/service/project/ProjectService.java
  16. 21 0
      web/src/main/java/seecoder/devcloud/web/vo/project/ProjectVO.java
  17. 39 0
      web/src/main/resources/SQLScripts/project.sql
  18. 38 0
      web/src/main/resources/SQLScripts/tree_log.sql
  19. 78 0
      web/src/test/java/seecoder/devcloud/web/dao/project/ProjectMapperTest.java
  20. 43 0
      web/src/test/java/seecoder/devcloud/web/dao/tree/TreeLogMapperTest.java
  21. 56 0
      web/src/test/java/seecoder/devcloud/web/service/project/ProjectServiceTest.java

+ 23 - 0
src/main/java/generator/Project.java

@@ -0,0 +1,23 @@
+package generator;
+
+import java.io.Serializable;
+import lombok.Data;
+
+/**
+ * project
+ * @author 
+ */
+@Data
+public class Project implements Serializable {
+    private Integer id;
+
+    private String name;
+
+    private String description;
+
+    private String gitRemoteUrl;
+
+    private Integer groupId;
+
+    private static final long serialVersionUID = 1L;
+}

+ 17 - 0
src/main/java/seecoder/devcloud/web/dao/ProjectDao.java

@@ -0,0 +1,17 @@
+package seecoder.devcloud.web.dao;
+
+import generator.Project;
+
+public interface ProjectDao {
+    int deleteByPrimaryKey(Integer id);
+
+    int insert(Project record);
+
+    int insertSelective(Project record);
+
+    Project selectByPrimaryKey(Integer id);
+
+    int updateByPrimaryKeySelective(Project record);
+
+    int updateByPrimaryKey(Project record);
+}

+ 87 - 0
src/main/resources/generator/ProjectDao.xml

@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="seecoder.devcloud.web.dao.ProjectDao">
+  <resultMap id="BaseResultMap" type="generator.Project">
+    <id column="id" jdbcType="INTEGER" property="id" />
+    <result column="name" jdbcType="VARCHAR" property="name" />
+    <result column="description" jdbcType="VARCHAR" property="description" />
+    <result column="git_remote_url" jdbcType="VARCHAR" property="gitRemoteUrl" />
+    <result column="group_id" jdbcType="INTEGER" property="groupId" />
+  </resultMap>
+  <sql id="Base_Column_List">
+    id, `name`, description, git_remote_url, group_id
+  </sql>
+  <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
+    select 
+    <include refid="Base_Column_List" />
+    from project
+    where id = #{id,jdbcType=INTEGER}
+  </select>
+  <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
+    delete from project
+    where id = #{id,jdbcType=INTEGER}
+  </delete>
+  <insert id="insert" keyColumn="id" keyProperty="id" parameterType="generator.Project" useGeneratedKeys="true">
+    insert into project (`name`, description, git_remote_url, 
+      group_id)
+    values (#{name,jdbcType=VARCHAR}, #{description,jdbcType=VARCHAR}, #{gitRemoteUrl,jdbcType=VARCHAR}, 
+      #{groupId,jdbcType=INTEGER})
+  </insert>
+  <insert id="insertSelective" keyColumn="id" keyProperty="id" parameterType="generator.Project" useGeneratedKeys="true">
+    insert into project
+    <trim prefix="(" suffix=")" suffixOverrides=",">
+      <if test="name != null">
+        `name`,
+      </if>
+      <if test="description != null">
+        description,
+      </if>
+      <if test="gitRemoteUrl != null">
+        git_remote_url,
+      </if>
+      <if test="groupId != null">
+        group_id,
+      </if>
+    </trim>
+    <trim prefix="values (" suffix=")" suffixOverrides=",">
+      <if test="name != null">
+        #{name,jdbcType=VARCHAR},
+      </if>
+      <if test="description != null">
+        #{description,jdbcType=VARCHAR},
+      </if>
+      <if test="gitRemoteUrl != null">
+        #{gitRemoteUrl,jdbcType=VARCHAR},
+      </if>
+      <if test="groupId != null">
+        #{groupId,jdbcType=INTEGER},
+      </if>
+    </trim>
+  </insert>
+  <update id="updateByPrimaryKeySelective" parameterType="generator.Project">
+    update project
+    <set>
+      <if test="name != null">
+        `name` = #{name,jdbcType=VARCHAR},
+      </if>
+      <if test="description != null">
+        description = #{description,jdbcType=VARCHAR},
+      </if>
+      <if test="gitRemoteUrl != null">
+        git_remote_url = #{gitRemoteUrl,jdbcType=VARCHAR},
+      </if>
+      <if test="groupId != null">
+        group_id = #{groupId,jdbcType=INTEGER},
+      </if>
+    </set>
+    where id = #{id,jdbcType=INTEGER}
+  </update>
+  <update id="updateByPrimaryKey" parameterType="generator.Project">
+    update project
+    set `name` = #{name,jdbcType=VARCHAR},
+      description = #{description,jdbcType=VARCHAR},
+      git_remote_url = #{gitRemoteUrl,jdbcType=VARCHAR},
+      group_id = #{groupId,jdbcType=INTEGER}
+    where id = #{id,jdbcType=INTEGER}
+  </update>
+</mapper>

+ 16 - 0
web/src/main/java/seecoder/devcloud/web/aop/TreeLogging.java

@@ -0,0 +1,16 @@
+package seecoder.devcloud.web.aop;
+
+import seecoder.devcloud.web.enums.OperationEnum;
+
+import java.lang.annotation.*;
+
+/**
+ * 以注解方式标记日志插入
+ * 要求:参数里带有TreeNodeVO
+ */
+@Target({ElementType.PARAMETER, ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface TreeLogging {
+    public OperationEnum value();
+}

+ 73 - 0
web/src/main/java/seecoder/devcloud/web/aspect/TreeLoggingAspect.java

@@ -0,0 +1,73 @@
+package seecoder.devcloud.web.aspect;
+
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.AfterReturning;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import seecoder.devcloud.web.aop.TreeLogging;
+import seecoder.devcloud.web.dao.tree.TreeLogMapper;
+import seecoder.devcloud.web.enums.ResponseEnums;
+import seecoder.devcloud.web.po.tree.TreeLog;
+import seecoder.devcloud.web.vo.Response;
+import seecoder.devcloud.web.vo.TreeNodeVO;
+
+import java.lang.reflect.Method;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * 树操作日志类切面,关联@TreeLogging注解
+ */
+@Aspect
+@Component
+public class TreeLoggingAspect {
+    @Autowired
+    TreeLogMapper treeLogMapper;
+
+    @Pointcut("@annotation(seecoder.devcloud.web.aop.TreeLogging)")
+    public void logPointCut() {
+
+    }
+
+    @AfterReturning(pointcut = "logPointCut()", returning = "result")
+    public void doAfterReturning(JoinPoint joinPoint, Response result) {
+        // 只处理成功的情况
+        if (result.getCode().equals(ResponseEnums.OK.getCode())) {
+            TreeLog log = new TreeLog();
+            //从切面织入点处通过反射机制获取织入点处的方法
+            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
+            //获取切入点所在的方法
+            Method method = signature.getMethod();
+            //获取注解,提取操作类型属性
+            TreeLogging logging = method.getAnnotation(TreeLogging.class);
+            if (logging != null) {
+                log.setOperation(logging.value());
+            }
+            //请求的参数
+            Object[] args = joinPoint.getArgs();
+            SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+            for (Object arg : args) {
+                if (arg instanceof TreeNodeVO) {
+                    TreeNodeVO node = (TreeNodeVO) arg;
+                    log.setTreeId(node.getId());
+//                    log.setUserId();
+//                    log.setUserName();
+//                    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
+//                    HttpSession session = request.getSession();
+//                    读取session中的用户
+//                    User user = (User) session.getAttribute("user");
+//                    请求的IP
+//                    String ip = request.getRemoteAddr();
+//                    TODO:从session中获取userId和userName
+                    log.setTime(sf.format(new Date()));
+                    System.out.println(log);
+                    treeLogMapper.insertTreeLog(log);
+                    break;
+                }
+            }
+        }
+    }
+}

+ 56 - 0
web/src/main/java/seecoder/devcloud/web/controller/project/ProjectController.java

@@ -0,0 +1,56 @@
+package seecoder.devcloud.web.controller.project;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import seecoder.devcloud.web.po.project.Project;
+import seecoder.devcloud.web.service.project.ProjectService;
+import seecoder.devcloud.web.vo.Response;
+import seecoder.devcloud.web.vo.project.ProjectVO;
+
+import java.util.List;
+
+/**
+ * @author Chenyz
+ * @date 2021/3/10
+ * @description: 项目接口
+ */
+@Api("项目相关API")
+@RestController
+@RequestMapping("/project")
+public class ProjectController {
+    @Autowired
+    ProjectService projectService;
+
+
+    @ApiOperation("根据group获取Project列表")
+    @GetMapping("/listByGroup/{groupId}")
+    public Response<List<Project>> listProjectsByGroupId(@PathVariable("groupId")int groupId){
+        return projectService.listProjectsByGroupId(groupId);
+    }
+
+    @ApiOperation("根据user获取Project列表")
+    @GetMapping("/listByUser/{userId}")
+    public Response<List<Project>> listProjectsByUserId(@PathVariable("userId")int userId){
+        return projectService.listProjectsByUserId(userId);
+    }
+
+    @ApiOperation("根据projectId获取Project")
+    @GetMapping("/{projectId}")
+    public Response<Project> getProjectById(@PathVariable("projectId")int projectId){
+        return projectService.getProjectById(projectId);
+    }
+
+    @ApiOperation("创建项目,传入的参数中不必带有效的projectId字段,返回一个创建后的结果,注入id")
+    @PostMapping("/create")
+    public Response<Project> createProject(ProjectVO project){
+        return projectService.createProject(project);
+    }
+
+    @ApiOperation("根据projectId删除项目")
+    @GetMapping("/delete/{projectId}")
+    public Response deleteProject(@PathVariable("projectId")int projectId){
+        return projectService.deleteProject(projectId);
+    }
+}

+ 47 - 0
web/src/main/java/seecoder/devcloud/web/dao/project/ProjectMapper.java

@@ -0,0 +1,47 @@
+package seecoder.devcloud.web.dao.project;
+
+import org.apache.ibatis.annotations.*;
+import org.springframework.stereotype.Repository;
+import seecoder.devcloud.web.dao.GeneralInsertUpdateSqlProvider;
+import seecoder.devcloud.web.po.project.Project;
+import seecoder.devcloud.web.po.user.Group;
+import seecoder.devcloud.web.vo.Response;
+import seecoder.devcloud.web.vo.project.ProjectVO;
+
+import java.util.List;
+
+@Mapper
+@Repository
+public interface ProjectMapper {
+
+
+    @Select("select * from project")
+    @Results(id="projectMap",value = {
+            @Result(column = "git_remote_url", property = "gitRemoteUrl"),
+            @Result(column = "group_id", property = "groupId")
+    })
+    List<Project> listAll();
+
+    /**
+     * 插入,自增ID
+     */
+    @InsertProvider(type = GeneralInsertUpdateSqlProvider.class, method = "insert")
+    @Options(useGeneratedKeys = true, keyProperty = "param1.id")
+    int insertProject(Project project, String... ignoredCols);
+
+    @UpdateProvider(type= GeneralInsertUpdateSqlProvider.class, method="updateById")
+    int updateProject(Project project);
+
+    @Select("select * from project where group_id=#{groupId}")
+    @ResultMap(value = "projectMap")
+    List<Project> listProjectsByGroupId(int groupId);
+
+    @Select("select * from project where group_id in(select unique group_id from group_member where user_id=#{userId}")
+    @ResultMap(value = "projectMap")
+    List<Project> listProjectsByUserId(int userId);
+
+    @Select("select * from project where id=#{projectId}")
+    @ResultMap(value = "projectMap")
+    Project getProjectById(int projectId);
+
+}

+ 29 - 0
web/src/main/java/seecoder/devcloud/web/dao/tree/TreeLogMapper.java

@@ -0,0 +1,29 @@
+package seecoder.devcloud.web.dao.tree;
+
+
+import org.apache.ibatis.annotations.*;
+import org.springframework.stereotype.Repository;
+import seecoder.devcloud.web.dao.GeneralInsertUpdateSqlProvider;
+import seecoder.devcloud.web.po.tree.TreeLog;
+
+import java.util.List;
+
+@Mapper
+@Repository
+public interface TreeLogMapper {
+
+    /**
+     * 插入,自增ID
+     */
+    @InsertProvider(type = GeneralInsertUpdateSqlProvider.class, method = "insert")
+    @Options(useGeneratedKeys = true, keyProperty = "param1.id")
+    int insertTreeLog(TreeLog project, String... ignoredCols);
+
+    @Select("select * from tree_log where tree_id=#{treeId}")
+    @Results(id="treeLogMap",value = {
+            @Result(column = "user_name", property = "userName"),
+            @Result(column = "tree_id", property = "treeId"),
+            @Result(column = "user_id", property = "userId")
+    })
+    List<TreeLog> listTreeLogsByTreeId(int treeId);
+}

+ 4 - 0
web/src/main/java/seecoder/devcloud/web/dao/user/GroupMemberMapper.java

@@ -2,6 +2,7 @@ package seecoder.devcloud.web.dao.user;
 
 import jnr.ffi.annotations.In;
 import org.apache.ibatis.annotations.*;
+import org.springframework.stereotype.Repository;
 import seecoder.devcloud.web.po.user.Group;
 import seecoder.devcloud.web.po.user.User;
 
@@ -12,6 +13,9 @@ import java.util.List;
  * @date 2021/3/4
  * @description:
  */
+
+@Mapper
+@Repository
 public interface GroupMemberMapper {
 
     @Insert("insert into group_member (group_id,user_id) values (#{groupId}, #{userId}) ")

+ 22 - 0
web/src/main/java/seecoder/devcloud/web/enums/OperationEnum.java

@@ -0,0 +1,22 @@
+package seecoder.devcloud.web.enums;
+
+/**
+ * TreeNode操作类型
+ */
+public enum  OperationEnum {
+    START("开启"),
+    RESTART("重新开启"),
+    UPDATE("更新"),
+    FINISH("结束");
+
+    private String value;
+
+    OperationEnum(String value){
+        this.value=value;
+    }
+
+    @Override
+    public String toString(){
+        return value;
+    }
+}

+ 21 - 0
web/src/main/java/seecoder/devcloud/web/po/project/Project.java

@@ -0,0 +1,21 @@
+package seecoder.devcloud.web.po.project;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author Chenyz
+ * @date 2021/3/10
+ * @description:
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class Project {
+    private Integer id;
+    private String name;
+    private String gitRemoteUrl;
+    private String description;
+    private Integer groupId;
+}

+ 40 - 0
web/src/main/java/seecoder/devcloud/web/po/tree/TreeLog.java

@@ -0,0 +1,40 @@
+package seecoder.devcloud.web.po.tree;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import seecoder.devcloud.web.enums.OperationEnum;
+
+/**
+ * 树操作的日志类,用于后序进行数据分析
+ */
+@Data
+@NoArgsConstructor
+public class TreeLog {
+
+    private Integer id;
+
+    /**
+     * 操作时间
+     */
+    private String time;
+
+    /**
+     * 操作类型
+     */
+    private OperationEnum operation;
+
+    /**
+     * 树节点
+     */
+    private Integer treeId;
+
+    /**
+     * 操作人
+     */
+    private Integer userId;
+
+    /**
+     * 操作名
+     */
+    private String userName;
+}

+ 57 - 0
web/src/main/java/seecoder/devcloud/web/service/impl/project/ProjectServiceImpl.java

@@ -0,0 +1,57 @@
+package seecoder.devcloud.web.service.impl.project;
+
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import seecoder.devcloud.web.dao.project.ProjectMapper;
+import seecoder.devcloud.web.po.project.Project;
+import seecoder.devcloud.web.service.project.ProjectService;
+import seecoder.devcloud.web.vo.Response;
+import seecoder.devcloud.web.vo.project.ProjectVO;
+
+import java.util.List;
+
+@Service
+public class ProjectServiceImpl implements ProjectService {
+    @Autowired
+    ProjectMapper projectMapper;
+
+
+    @Override
+    public Response<List<Project>> listProjectsByGroupId(int groupId) {
+        List<Project> projects = projectMapper.listProjectsByGroupId(groupId);
+        return Response.ok(projects);
+    }
+
+    @Override
+    // TODO:该方法待测试
+    public Response<List<Project>> listProjectsByUserId(int userId) {
+        List<Project> projects = projectMapper.listProjectsByUserId(userId);
+        return Response.ok(projects);
+    }
+
+    @Override
+    public Response<Project> getProjectById(int projectId) {
+        Project project = projectMapper.getProjectById(projectId);
+        return Response.ok(project);
+    }
+
+    @Override
+    public Response<Project> createProject(ProjectVO projectVO) {
+        Project project = new Project();
+        BeanUtils.copyProperties(projectVO,project);
+        try {
+            projectMapper.insertProject(project);
+            // TODO:在对应的gitlab仓库中注册WEBHOOK
+            return Response.ok(project);
+        }catch (Exception e){
+            return Response.badRequest("异常错误");
+        }
+    }
+
+    @Override
+    public Response deleteProject(int projectId) {
+        //TODO:不知道该怎么做,懒删除?还是直接删?
+        return null;
+    }
+}

+ 2 - 7
web/src/main/java/seecoder/devcloud/web/service/impl/tree/TreeNodeServiceImpl.java

@@ -4,19 +4,13 @@ package seecoder.devcloud.web.service.impl.tree;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
-import seecoder.devcloud.web.enums.NodeStateEnum;
-import seecoder.devcloud.web.enums.NodeTypeEnum;
 import seecoder.devcloud.web.po.TreeNodePO;
 import seecoder.devcloud.web.service.tree.TreeNodeService;
-import seecoder.devcloud.web.utils.TimeUtils;
 import seecoder.devcloud.web.vo.Response;
 import seecoder.devcloud.web.vo.TreeNodeVO;
 import seecoder.devcloud.web.dao.tree.TreeNodeMapper;
 
-import java.text.SimpleDateFormat;
-import java.util.Date;
 import java.util.List;
-import java.util.PriorityQueue;
 
 @Service
 public class TreeNodeServiceImpl implements TreeNodeService {
@@ -32,9 +26,9 @@ public class TreeNodeServiceImpl implements TreeNodeService {
         List<TreeNodePO> result = treeNodeMapper.listTreeNodesByProjectId(projectId);
         return Response.ok(result);
     }
-    
 
     @Override
+    @TreeLogging(OperationEnum.START)
     public Response insertTreeNode(TreeNodeVO treeNodeVO) {
         TreeNodePO treeNodePO = new TreeNodePO();
         BeanUtils.copyProperties(treeNodeVO,treeNodePO);
@@ -47,6 +41,7 @@ public class TreeNodeServiceImpl implements TreeNodeService {
     }
 
     @Override
+    @TreeLogging(OperationEnum.UPDATE)
     public Response updateTreeNode(TreeNodeVO treeNodeVO) {
         TreeNodePO treeNodePO = new TreeNodePO();
         BeanUtils.copyProperties(treeNodeVO,treeNodePO);

+ 40 - 0
web/src/main/java/seecoder/devcloud/web/service/project/ProjectService.java

@@ -0,0 +1,40 @@
+package seecoder.devcloud.web.service.project;
+
+import org.springframework.web.bind.annotation.PathVariable;
+import seecoder.devcloud.web.po.project.Project;
+import seecoder.devcloud.web.vo.Response;
+import seecoder.devcloud.web.vo.project.ProjectVO;
+
+import java.util.List;
+
+public interface ProjectService {
+    /**
+     * 根据group找projects
+     */
+    Response<List<Project>> listProjectsByGroupId(int groupId);
+
+    /**
+     * 根据user找Project
+     */
+    Response<List<Project>> listProjectsByUserId(int userId);
+
+    /**
+     * 获取project
+     * @param projectId
+     * @return
+     */
+    Response<Project> getProjectById(int projectId);
+
+    /**
+     * 创建项目
+     * @param project 不包含id
+     * @return 注入id后返回
+     */
+    Response<Project> createProject(ProjectVO project);
+
+    /**
+     * 删除项目,懒删除
+     */
+    Response deleteProject(int projectId);
+
+}

+ 21 - 0
web/src/main/java/seecoder/devcloud/web/vo/project/ProjectVO.java

@@ -0,0 +1,21 @@
+package seecoder.devcloud.web.vo.project;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author Chenyz
+ * @date 2021/3/10
+ * @description:
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class ProjectVO {
+    private Integer id;
+    private String name;
+    private String gitRemoteUrl;
+    private String description;
+    private Integer groupId;
+}

+ 39 - 0
web/src/main/resources/SQLScripts/project.sql

@@ -0,0 +1,39 @@
+/*
+ Navicat Premium Data Transfer
+
+ Source Server         : localhost_3306
+ Source Server Type    : MySQL
+ Source Server Version : 80018
+ Source Host           : localhost:3306
+ Source Schema         : seecoder
+
+ Target Server Type    : MySQL
+ Target Server Version : 80018
+ File Encoding         : 65001
+
+ Date: 10/03/2021 23:54:40
+*/
+
+SET NAMES utf8mb4;
+SET FOREIGN_KEY_CHECKS = 0;
+
+-- ----------------------------
+-- Table structure for project
+-- ----------------------------
+DROP TABLE IF EXISTS `project`;
+CREATE TABLE `project`  (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `name` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
+  `description` varchar(512) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
+  `git_remote_url` varchar(512) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
+  `group_id` int(11) NOT NULL,
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of project
+-- ----------------------------
+INSERT INTO `project` VALUES (1, '前端', 'DevCloud前端', 'http://gogs.seecoder.cn/HuangKaiSheng/seecoder-devcloud-frontend/src/master', 1);
+INSERT INTO `project` VALUES (2, '后端开发', '后端测试测试测试测试测试', 'http://gogs.seecoder.cn/WengPuHong/seecoder-devcloud', 1);
+
+SET FOREIGN_KEY_CHECKS = 1;

+ 38 - 0
web/src/main/resources/SQLScripts/tree_log.sql

@@ -0,0 +1,38 @@
+/*
+ Navicat Premium Data Transfer
+
+ Source Server         : localhost_3306
+ Source Server Type    : MySQL
+ Source Server Version : 80018
+ Source Host           : localhost:3306
+ Source Schema         : seecoder
+
+ Target Server Type    : MySQL
+ Target Server Version : 80018
+ File Encoding         : 65001
+
+ Date: 11/03/2021 09:46:42
+*/
+
+SET NAMES utf8mb4;
+SET FOREIGN_KEY_CHECKS = 0;
+
+-- ----------------------------
+-- Table structure for tree_log
+-- ----------------------------
+DROP TABLE IF EXISTS `tree_log`;
+CREATE TABLE `tree_log`  (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `time` datetime(0) NULL DEFAULT NULL,
+  `operation` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
+  `user_id` int(11) NULL DEFAULT NULL,
+  `tree_id` int(11) NULL DEFAULT NULL,
+  `user_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of tree_log
+-- ----------------------------
+
+SET FOREIGN_KEY_CHECKS = 1;

+ 78 - 0
web/src/test/java/seecoder/devcloud/web/dao/project/ProjectMapperTest.java

@@ -0,0 +1,78 @@
+package seecoder.devcloud.web.dao.project;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mybatis.spring.boot.test.autoconfigure.MybatisTest;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
+import org.springframework.test.context.junit4.SpringRunner;
+import seecoder.devcloud.web.dao.user.GroupMemberMapper;
+import seecoder.devcloud.web.po.project.Project;
+
+import java.util.List;
+
+@RunWith(SpringRunner.class)
+@MybatisTest
+@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
+public class ProjectMapperTest {
+    @Autowired
+    ProjectMapper projectMapper;
+    @Autowired
+    GroupMemberMapper groupMemberMapper;
+
+    @Test
+    public void testInsert(){
+        Project project = new Project(null,"TEST","JUST A TEST","seecoder.cn",2);
+        projectMapper.insertProject(project);
+        Project project2 = projectMapper.getProjectById(project.getId());
+        assert project.equals(project2);
+    }
+
+    @Test
+    public void testUpdate(){
+        Project project2 = projectMapper.getProjectById(1);
+        project2.setName("modify");
+        project2.setDescription("modify description");
+        project2.setGitRemoteUrl("www.google.com");
+        project2.setGroupId(7);
+        projectMapper.updateProject(project2);
+        Project project = projectMapper.getProjectById(1);
+        System.out.println(project);
+        assert project2.equals(project);
+    }
+
+    @Test
+    public void testListProjectsByGroupId(){
+        List<Project> projects = projectMapper.listProjectsByGroupId(1);
+        boolean res = true;
+        for (Project project:projects){
+            if(project.getGroupId()!=1){
+                res = false;
+                break;
+            }
+        }
+        assert res;
+    }
+
+    /**
+     * 这个因为groupMemberMapper有外键,不好测
+     */
+//    @Test
+    public void testListProjectsByUserId(){
+        Project project = new Project(0,"test","seecoder.cn","decription",2);
+        projectMapper.insertProject(project);
+        // TODO:插入如下两条数据
+//        groupMemberMapper.insert(2,1);
+//        groupMemberMapper.insert(1,1);
+        List<Project> projects = projectMapper.listProjectsByUserId(1);
+        boolean res = true;
+        for (Project project1:projects){
+            System.out.println(project1);
+            if(project1.getGroupId()!=1||project1.getGroupId()!=2){
+                res = false;
+                break;
+            }
+        }
+        assert res;
+    }
+}

+ 43 - 0
web/src/test/java/seecoder/devcloud/web/dao/tree/TreeLogMapperTest.java

@@ -0,0 +1,43 @@
+package seecoder.devcloud.web.dao.tree;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mybatis.spring.boot.test.autoconfigure.MybatisTest;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
+import org.springframework.test.context.junit4.SpringRunner;
+import seecoder.devcloud.web.enums.OperationEnum;
+import seecoder.devcloud.web.po.tree.TreeLog;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+
+@RunWith(SpringRunner.class)
+@MybatisTest
+@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
+public class TreeLogMapperTest {
+    @Autowired
+    TreeLogMapper treeLogMapper;
+
+    @Test
+    public void testInsertAndSelect(){
+        TreeLog treeLog = new TreeLog();
+        treeLog.setTreeId(1);
+        treeLog.setUserId(1);
+        treeLog.setTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
+        treeLog.setUserName("test");
+        treeLog.setOperation(OperationEnum.START);
+        treeLogMapper.insertTreeLog(treeLog);
+        List<TreeLog> logList = treeLogMapper.listTreeLogsByTreeId(1);
+        boolean res = false;
+        for(TreeLog log:logList){
+            if(log.equals(treeLog)){
+                res = true;
+                System.out.println(log);
+                break;
+            }
+        }
+        assert res;
+    }
+}

+ 56 - 0
web/src/test/java/seecoder/devcloud/web/service/project/ProjectServiceTest.java

@@ -0,0 +1,56 @@
+package seecoder.devcloud.web.service.project;
+
+import io.swagger.annotations.Api;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.transaction.annotation.Transactional;
+import seecoder.devcloud.web.DevcloudWebApplication;
+import seecoder.devcloud.web.enums.ResponseEnums;
+import seecoder.devcloud.web.po.project.Project;
+import seecoder.devcloud.web.vo.Response;
+import seecoder.devcloud.web.vo.project.ProjectVO;
+
+import java.util.List;
+
+
+@Api(tags = "GitLab Hook API")
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = DevcloudWebApplication.class)
+@Transactional
+public class ProjectServiceTest {
+    @Autowired
+    ProjectService projectService;
+    ProjectVO projectVO;
+
+    @Before
+    public void initProjectVO(){
+        projectVO  = new ProjectVO(null,"TEST","JUST A TEST","seecoder.cn",2);
+    }
+
+    @Test
+    public void testInsert(){
+        Response<Project> projectResponse = projectService.createProject(projectVO);
+        assert projectResponse.getCode().equals(ResponseEnums.OK.getCode());
+        Project project = projectResponse.getData();
+        System.out.println(project);
+        assert project.getName().equals(projectVO.getName());
+        assert project.getGitRemoteUrl().equals(projectVO.getGitRemoteUrl());
+        assert project.getDescription().equals(projectVO.getDescription());
+        assert project.getGroupId().equals(projectVO.getGroupId());
+    }
+
+    @Test
+    public void testListProjectsByGroupId(){
+        Response<List<Project>>  listResponse = projectService.listProjectsByGroupId(1);
+        assert listResponse.getCode().equals(ResponseEnums.OK.getCode());
+        for(Project project:listResponse.getData()){
+            assert project.getGroupId()==1;
+        }
+    }
+
+
+}