deason 4 лет назад
Родитель
Сommit
201d1b711c
16 измененных файлов с 379 добавлено и 221 удалено
  1. 42 12
      examcloud-core-examwork-api-provider/src/main/java/cn/com/qmth/examcloud/core/examwork/api/controller/ExamController.java
  2. 48 12
      examcloud-core-examwork-api-provider/src/main/java/cn/com/qmth/examcloud/core/examwork/api/controller/ExamStudentController.java
  3. 26 0
      examcloud-core-examwork-api-provider/src/main/java/cn/com/qmth/examcloud/core/examwork/api/controller/bean/ExamStudentDomain.java
  4. 33 6
      examcloud-core-examwork-api-provider/src/main/java/cn/com/qmth/examcloud/core/examwork/api/provider/ExamCloudServiceProvider.java
  5. 1 1
      examcloud-core-examwork-api-provider/src/main/java/cn/com/qmth/examcloud/core/examwork/api/provider/ExamStageCloudServiceProvider.java
  6. 1 1
      examcloud-core-examwork-api-provider/src/main/java/cn/com/qmth/examcloud/core/examwork/api/provider/ExamStudentCloudServiceProvider.java
  7. 1 1
      examcloud-core-examwork-api-provider/src/main/java/cn/com/qmth/examcloud/core/examwork/api/provider/HandleSyncCloudServiceProvider.java
  8. 1 1
      examcloud-core-examwork-api-provider/src/main/java/cn/com/qmth/examcloud/core/examwork/api/provider/NoticeCloudServiceProvider.java
  9. 1 1
      examcloud-core-examwork-dao/src/main/java/cn/com/qmth/examcloud/core/examwork/dao/entity/ExamStudentEntity.java
  10. 1 1
      examcloud-core-examwork-service/src/main/java/cn/com/qmth/examcloud/core/examwork/service/ExamService.java
  11. 2 2
      examcloud-core-examwork-service/src/main/java/cn/com/qmth/examcloud/core/examwork/service/impl/ExamServiceImpl.java
  12. 44 45
      examcloud-core-examwork-starter/src/main/java/cn/com/qmth/examcloud/core/examwork/starter/CoreExamWorkApp.java
  13. 126 111
      examcloud-core-examwork-starter/src/main/java/cn/com/qmth/examcloud/core/examwork/starter/config/ExamCloudResourceManager.java
  14. 28 27
      examcloud-core-examwork-starter/src/main/java/cn/com/qmth/examcloud/core/examwork/starter/config/ExamCloudWebMvcConfigurer.java
  15. 24 0
      examcloud-core-examwork-starter/src/main/resources/exam-properties.xml
  16. BIN
      examcloud-core-examwork-starter/src/main/resources/templates/studentImportTemplate.xlsx

+ 42 - 12
examcloud-core-examwork-api-provider/src/main/java/cn/com/qmth/examcloud/core/examwork/api/controller/ExamController.java

@@ -1,10 +1,12 @@
 package cn.com.qmth.examcloud.core.examwork.api.controller;
 
 import cn.com.qmth.examcloud.api.commons.enums.CURD;
+import cn.com.qmth.examcloud.api.commons.enums.DataRuleType;
 import cn.com.qmth.examcloud.api.commons.enums.ExamSpecialSettingsType;
 import cn.com.qmth.examcloud.api.commons.enums.ExamType;
 import cn.com.qmth.examcloud.api.commons.exchange.PageInfo;
 import cn.com.qmth.examcloud.api.commons.security.bean.User;
+import cn.com.qmth.examcloud.api.commons.security.bean.UserDataRule;
 import cn.com.qmth.examcloud.api.commons.security.bean.UserType;
 import cn.com.qmth.examcloud.commons.exception.StatusException;
 import cn.com.qmth.examcloud.commons.helpers.DynamicEnum;
@@ -14,7 +16,9 @@ import cn.com.qmth.examcloud.commons.util.*;
 import cn.com.qmth.examcloud.commons.util.DateUtil.DatePatterns;
 import cn.com.qmth.examcloud.core.basic.api.OrgCloudService;
 import cn.com.qmth.examcloud.core.basic.api.StudentCloudService;
+import cn.com.qmth.examcloud.core.basic.api.UserDataRuleCloudService;
 import cn.com.qmth.examcloud.core.basic.api.bean.OrgBean;
+import cn.com.qmth.examcloud.core.basic.api.request.AddUserDataRuleReq;
 import cn.com.qmth.examcloud.core.basic.api.request.GetOrgReq;
 import cn.com.qmth.examcloud.core.basic.api.request.GetOrgsReq;
 import cn.com.qmth.examcloud.core.basic.api.response.GetOrgResp;
@@ -43,6 +47,7 @@ import cn.com.qmth.examcloud.task.api.request.SyncExamReq;
 import cn.com.qmth.examcloud.web.config.SystemProperties;
 import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
 import cn.com.qmth.examcloud.web.redis.RedisClient;
+import cn.com.qmth.examcloud.web.security.DataRule;
 import cn.com.qmth.examcloud.web.support.ControllerSupport;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
@@ -54,10 +59,7 @@ import org.apache.commons.fileupload.disk.DiskFileItem;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.PageRequest;
-import org.springframework.data.domain.Pageable;
-import org.springframework.data.domain.Sort;
+import org.springframework.data.domain.*;
 import org.springframework.data.domain.Sort.Direction;
 import org.springframework.data.jpa.domain.Specification;
 import org.springframework.transaction.annotation.Transactional;
@@ -132,6 +134,9 @@ public class ExamController extends ControllerSupport {
     @Autowired
     DataSyncCloudService dataSyncCloudService;
 
+    @Autowired
+    UserDataRuleCloudService userDataRuleCloudService;
+
     @Autowired
     ExamSettingsCache examSettingsCache;
 
@@ -225,18 +230,31 @@ public class ExamController extends ControllerSupport {
      * @return
      * @author WANGWEI
      */
+    @DataRule(type = DataRuleType.EXAM)
     @ApiOperation(value = "分页查询考试批次")
     @GetMapping("queryPage/{curPage}/{pageSize}")
     public PageInfo<ExamDomain> queryPage(@PathVariable Integer curPage,
-                                          @PathVariable Integer pageSize, @RequestParam(required = false) String name,
+                                          @PathVariable Integer pageSize,
+                                          @RequestParam(required = false) String name,
                                           @RequestParam(required = false) String examType,
                                           @RequestParam(required = false) Boolean enable,
                                           @RequestParam(required = false) String propertyKeys) {
-
         User accessUser = getAccessUser();
 
+        PageRequest pageable = PageRequest.of(curPage, pageSize, new Sort(Direction.DESC, "updateTime", "id"));
+
+        UserDataRule userDataRule = super.getUserDataRule(DataRuleType.EXAM);
+        if (userDataRule.assertEmptyQueryResult()) {
+            return new PageInfo(new PageImpl<>(new ArrayList<>(), pageable, 0L));
+        }
+
         Specification<ExamEntity> specification = (root, query, cb) -> {
             List<Predicate> predicates = new ArrayList<>();
+
+            if (userDataRule.assertNeedQueryRefIds()) {
+                predicates.add(root.get("id").in(userDataRule.getRefIds()));
+            }
+
             predicates.add(cb.equal(root.get("rootOrgId"), accessUser.getRootOrgId()));
             if (StringUtils.isNotBlank(name)) {
                 predicates.add(cb.like(root.get("name"), toSqlSearchPattern(name)));
@@ -251,10 +269,7 @@ public class ExamController extends ControllerSupport {
             return cb.and(predicates.toArray(new Predicate[predicates.size()]));
         };
 
-        PageRequest pageRequest = PageRequest.of(curPage, pageSize,
-                new Sort(Direction.DESC, "updateTime", "id"));
-
-        Page<ExamEntity> page = examRepo.findAll(specification, pageRequest);
+        Page<ExamEntity> page = examRepo.findAll(specification, pageable);
 
         Iterator<ExamEntity> iterator = page.iterator();
         List<ExamDomain> list = Lists.newArrayList();
@@ -293,7 +308,7 @@ public class ExamController extends ControllerSupport {
             }
         }
 
-        PageInfo<ExamDomain> ret = new PageInfo<ExamDomain>(page, list);
+        PageInfo<ExamDomain> ret = new PageInfo<>(page, list);
         return ret;
     }
 
@@ -307,6 +322,7 @@ public class ExamController extends ControllerSupport {
      * @return
      * @author WANGWEI
      */
+    @DataRule(type = DataRuleType.EXAM)
     @ApiOperation(value = "查询考试批次")
     @GetMapping("queryByNameLike")
     public List<ExamDomain> query(@RequestParam(required = true) String name,
@@ -315,14 +331,23 @@ public class ExamController extends ControllerSupport {
                                   @RequestParam(required = false) String propertyKeys,
                                   @RequestParam(required = false) Long studentId,
                                   @RequestParam(required = false) Long rootOrgId) {
-
         if (null == rootOrgId) {
             rootOrgId = getRootOrgId();
         }
         final Long finalRootOrgId = rootOrgId;
 
+        UserDataRule userDataRule = super.getUserDataRule(DataRuleType.EXAM);
+        if (userDataRule.assertEmptyQueryResult()) {
+            return new ArrayList<>();
+        }
+
         Specification<ExamEntity> specification = (root, query, cb) -> {
             List<Predicate> predicates = new ArrayList<>();
+
+            if (userDataRule.assertNeedQueryRefIds()) {
+                predicates.add(root.get("id").in(userDataRule.getRefIds()));
+            }
+
             predicates.add(cb.equal(root.get("rootOrgId"), finalRootOrgId));
             if (StringUtils.isNotBlank(name)) {
                 predicates.add(cb.like(root.get("name"), toSqlSearchPattern(name)));
@@ -541,6 +566,11 @@ public class ExamController extends ControllerSupport {
 
         examSettingsCache.remove(saved.getId());
 
+        if (CURD.CREATION == es) {
+            // 用户与考试的数据权限
+            userDataRuleCloudService.addUserDataRule(new AddUserDataRuleReq(accessUser.getUserId(), DataRuleType.EXAM, saved.getId()));
+        }
+
         return saved;
     }
 

+ 48 - 12
examcloud-core-examwork-api-provider/src/main/java/cn/com/qmth/examcloud/core/examwork/api/controller/ExamStudentController.java

@@ -2,8 +2,10 @@ package cn.com.qmth.examcloud.core.examwork.api.controller;
 
 import cn.com.qmth.examcloud.api.commons.enums.BooleanSelect;
 import cn.com.qmth.examcloud.api.commons.enums.CourseLevel;
+import cn.com.qmth.examcloud.api.commons.enums.DataRuleType;
 import cn.com.qmth.examcloud.api.commons.exchange.PageInfo;
 import cn.com.qmth.examcloud.api.commons.security.bean.User;
+import cn.com.qmth.examcloud.api.commons.security.bean.UserDataRule;
 import cn.com.qmth.examcloud.api.commons.security.bean.UserType;
 import cn.com.qmth.examcloud.commons.exception.StatusException;
 import cn.com.qmth.examcloud.commons.util.PathUtil;
@@ -35,6 +37,7 @@ import cn.com.qmth.examcloud.reports.commons.enums.OperateContent;
 import cn.com.qmth.examcloud.reports.commons.util.ReportsUtil;
 import cn.com.qmth.examcloud.support.helper.IdentityNumberHelper;
 import cn.com.qmth.examcloud.web.helpers.GlobalHelper;
+import cn.com.qmth.examcloud.web.security.DataRule;
 import cn.com.qmth.examcloud.web.support.ControllerSupport;
 import com.google.common.collect.Lists;
 import io.swagger.annotations.Api;
@@ -42,6 +45,7 @@ import io.swagger.annotations.ApiOperation;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageImpl;
 import org.springframework.data.domain.PageRequest;
 import org.springframework.data.domain.Sort;
 import org.springframework.data.domain.Sort.Direction;
@@ -150,6 +154,7 @@ public class ExamStudentController extends ControllerSupport {
      * @return
      * @author WANGWEI
      */
+    @DataRule(type = {DataRuleType.ORG, DataRuleType.COURSE})
     @ApiOperation(value = "查询考试学生带条件和分页", notes = "带条件带分页")
     @GetMapping("examStudentPage/{curPage}/{pageSize}")
     public PageInfo<ExamStudentDomain> getExamStudentPage(
@@ -170,19 +175,44 @@ public class ExamStudentController extends ControllerSupport {
             @RequestParam(required = false) String specialtyName,
             @RequestParam(required = false) String infoCollector,
             @RequestParam(required = false) BooleanSelect enable,
-            @RequestParam(required = false) Boolean withStarted) {
+            @RequestParam(required = false) Boolean withStarted,
+            @RequestParam(required = false, defaultValue = "false") Boolean skipRule) {
 
         User accessUser = getAccessUser();
+        PageRequest pageable = PageRequest.of(curPage, pageSize, new Sort(Direction.DESC, "updateTime", "id"));
+
+        UserDataRule orgDataRule = super.getUserDataRule(DataRuleType.ORG);
+        UserDataRule courseDataRule = super.getUserDataRule(DataRuleType.COURSE);
+        if (!skipRule) {
+            if (orgDataRule.assertEmptyQueryResult() || courseDataRule.assertEmptyQueryResult()) {
+                return new PageInfo(new PageImpl<>(new ArrayList<>(), pageable, 0L));
+            }
+        }
 
         Specification<ExamStudentEntity> specification = (root, query, cb) -> {
             List<Predicate> predicates = new ArrayList<>();
             predicates.add(cb.equal(root.get("rootOrgId"), accessUser.getRootOrgId()));
-            if (null != orgId) {
-                predicates.add(cb.equal(root.get("orgId"), orgId));
-            }
+
             if (null != examId) {
                 predicates.add(cb.equal(root.get("examId"), examId));
             }
+
+            if (null != courseId) {
+                predicates.add(cb.equal(root.get("courseId"), courseId));
+            } else {
+                if (!skipRule && courseDataRule.assertNeedQueryRefIds()) {
+                    predicates.add(root.get("courseId").in(courseDataRule.getRefIds()));
+                }
+            }
+
+            if (null != orgId) {
+                predicates.add(cb.equal(root.get("orgId"), orgId));
+            } else {
+                if (!skipRule && orgDataRule.assertNeedQueryRefIds()) {
+                    predicates.add(root.get("orgId").in(orgDataRule.getRefIds()));
+                }
+            }
+
             if (null != examStageId) {
                 predicates.add(cb.equal(root.get("examStageId"), examStageId));
             }
@@ -192,9 +222,6 @@ public class ExamStudentController extends ControllerSupport {
             if (StringUtils.isNotBlank(studentCode)) {
                 predicates.add(cb.like(root.get("studentCode"), toSqlRightLike(studentCode)));
             }
-            if (null != courseId) {
-                predicates.add(cb.equal(root.get("courseId"), courseId));
-            }
             if (StringUtils.isNotEmpty(courseCode)) {
                 predicates.add(cb.equal(root.get("courseCode"), courseCode));
             }
@@ -235,10 +262,7 @@ public class ExamStudentController extends ControllerSupport {
             return cb.and(predicates.toArray(new Predicate[predicates.size()]));
         };
 
-        PageRequest pageRequest = PageRequest.of(curPage, pageSize,
-                new Sort(Direction.DESC, "updateTime", "id"));
-
-        Page<ExamStudentEntity> examStudents = examStudentRepo.findAll(specification, pageRequest);
+        Page<ExamStudentEntity> examStudents = examStudentRepo.findAll(specification, pageable);
 
         List<ExamStudentDomain> ret = Lists.newArrayList();
 
@@ -309,7 +333,19 @@ public class ExamStudentController extends ControllerSupport {
             bean.setExt3(cur.getExt3());
             bean.setExt4(cur.getExt4());
             bean.setExt5(cur.getExt5());
-            bean.setExamStageOrder(cur.getExamStageOrder());
+            if (null != cur.getExamStageId()) {
+                ExamStageEntity examStageEntity = GlobalHelper.getEntity(examStageRepo, cur.getExamStageId(), ExamStageEntity.class);
+                if (null == examStageEntity) {
+                    throw new StatusException("005001", "场次id不正确");
+                }
+
+                if (examStageEntity.getEnable() == false) {
+                    throw new StatusException("005002", "场次被禁用,请重新选择场次");
+                }
+                bean.setExamStageOrder(examStageEntity.getStageOrder());
+                bean.setStartTime(examStageEntity.getStartTime());
+                bean.setEndTime(examStageEntity.getEndTime());
+            }
             bean.setExamStageId(cur.getExamStageId());
             ret.add(bean);
         }

+ 26 - 0
examcloud-core-examwork-api-provider/src/main/java/cn/com/qmth/examcloud/core/examwork/api/controller/bean/ExamStudentDomain.java

@@ -85,6 +85,16 @@ public class ExamStudentDomain implements JsonSerializable {
 	 */
 	private Integer examStageOrder;
 
+	/**
+	 * 开始进入考试时间
+	 */
+	private Date startTime;
+
+	/**
+	 * 考试批次结束时间
+	 */
+	private Date endTime;
+
 	/**
 	 * 扩展属性1
 	 */
@@ -405,4 +415,20 @@ public class ExamStudentDomain implements JsonSerializable {
 	public void setExamStageId(Long examStageId) {
 		this.examStageId = examStageId;
 	}
+
+	public Date getStartTime() {
+		return startTime;
+	}
+
+	public void setStartTime(Date startTime) {
+		this.startTime = startTime;
+	}
+
+	public Date getEndTime() {
+		return endTime;
+	}
+
+	public void setEndTime(Date endTime) {
+		this.endTime = endTime;
+	}
 }

+ 33 - 6
examcloud-core-examwork-api-provider/src/main/java/cn/com/qmth/examcloud/core/examwork/api/provider/ExamCloudServiceProvider.java

@@ -52,7 +52,7 @@ import java.util.*;
  * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
  */
 @RestController
-@Api(tags = "考试相关接口")
+@Api(tags = "RPC-考试相关接口")
 @RequestMapping("${$rmp.cloud.examwork}" + "exam")
 public class ExamCloudServiceProvider extends ControllerSupport implements ExamCloudService {
 
@@ -759,12 +759,39 @@ public class ExamCloudServiceProvider extends ControllerSupport implements ExamC
     }
 
     @Override
-    @PostMapping("getExamNames")
-    @ApiOperation(value = "获取考试名称")
-    public GetExamNamesResp getExamNames(@RequestBody GetExamNamesReq req) {
-        GetExamNamesResp resp = new GetExamNamesResp();
-        resp.setExamNames(examService.getExamNamesByIds(req.getExamIds()));
+    @PostMapping("getExamMaps")
+    @ApiOperation(value = "根据ID列表获取考试集合")
+    public GetExamMapsResp getExamMaps(@RequestBody GetExamMapsReq req) {
+        Map<Long, ExamEntity> exams = examService.getExamMapsByIds(req.getExamIds());
+
+        Map<Long, ExamBean> examMaps = new HashMap<>();
+        for (Map.Entry<Long, ExamEntity> exam : exams.entrySet()) {
+            examMaps.put(exam.getKey(), toExamBean(exam.getValue()));
+        }
+
+        GetExamMapsResp resp = new GetExamMapsResp();
+        resp.setExamMaps(examMaps);
         return resp;
     }
 
+    private ExamBean toExamBean(ExamEntity entity) {
+        ExamBean bean = new ExamBean();
+
+        bean.setId(entity.getId());
+        bean.setRootOrgId(entity.getRootOrgId());
+        bean.setCode(entity.getCode());
+        bean.setName(entity.getName());
+        bean.setExamType(entity.getExamType().name());
+        bean.setBeginTime(entity.getBeginTime());
+        bean.setEndTime(entity.getEndTime());
+        bean.setDuration(entity.getDuration());
+        bean.setExamTimes(entity.getExamTimes());
+        bean.setExamLimit(entity.getExamLimit());
+        bean.setSpecialSettingsEnabled(entity.getSpecialSettingsEnabled());
+        bean.setSpecialSettingsType(entity.getSpecialSettingsType());
+        bean.setEnable(entity.getEnable());
+
+        return bean;
+    }
+
 }

+ 1 - 1
examcloud-core-examwork-api-provider/src/main/java/cn/com/qmth/examcloud/core/examwork/api/provider/ExamStageCloudServiceProvider.java

@@ -27,7 +27,7 @@ import org.springframework.web.bind.annotation.RestController;
  * @Version 1.0
  */
 @RestController
-@Api(tags = "考试场次相关接口")
+@Api(tags = "RPC-考试场次相关接口")
 @RequestMapping("${$rmp.cloud.examwork}" + "examStage")
 public class ExamStageCloudServiceProvider extends ControllerSupport implements ExamStageCloudService {
 

+ 1 - 1
examcloud-core-examwork-api-provider/src/main/java/cn/com/qmth/examcloud/core/examwork/api/provider/ExamStudentCloudServiceProvider.java

@@ -63,7 +63,7 @@ import java.util.List;
  * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
  */
 @RestController
-@Api(tags = "考生相关接口")
+@Api(tags = "RPC-考生相关接口")
 @RequestMapping("${$rmp.cloud.examwork}" + "examStudent")
 public class ExamStudentCloudServiceProvider extends ControllerSupport
         implements

+ 1 - 1
examcloud-core-examwork-api-provider/src/main/java/cn/com/qmth/examcloud/core/examwork/api/provider/HandleSyncCloudServiceProvider.java

@@ -29,7 +29,7 @@ import java.util.List;
  */
 @Transactional
 @RestController
-@Api(tags = "同步相关接口")
+@Api(tags = "RPC-同步相关接口")
 @RequestMapping("${$rmp.cloud.examwork}" + "dataSync")
 public class HandleSyncCloudServiceProvider extends ControllerSupport
         implements

+ 1 - 1
examcloud-core-examwork-api-provider/src/main/java/cn/com/qmth/examcloud/core/examwork/api/provider/NoticeCloudServiceProvider.java

@@ -29,7 +29,7 @@ import java.util.List;
  * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
  */
 @RestController
-@Api(tags = "通知相关接口")
+@Api(tags = "RPC-通知相关接口")
 @RequestMapping("${$rmp.cloud.examwork}" + "notice")
 public class NoticeCloudServiceProvider extends ControllerSupport implements NoticeCloudService {
 

+ 1 - 1
examcloud-core-examwork-dao/src/main/java/cn/com/qmth/examcloud/core/examwork/dao/entity/ExamStudentEntity.java

@@ -12,7 +12,7 @@ import cn.com.qmth.examcloud.web.jpa.JpaEntity;
 
 @Entity
 @Table(name = "EC_E_EXAM_STUDENT", indexes = {
-		@Index(name = "IDX_E_E_S_001001", columnList = "studentId,examId,courseId", unique = true),
+		@Index(name = "IDX_E_E_S_001001", columnList = "examId,courseId,studentId", unique = true),
 		@Index(name = "IDX_E_E_S_001002", columnList = "rootOrgId,name", unique = false),
 		@Index(name = "IDX_E_E_S_001003", columnList = "rootOrgId,studentCode", unique = false),
 		@Index(name = "IDX_E_E_S_001004", columnList = "rootOrgId,identityNumber", unique = false),

+ 1 - 1
examcloud-core-examwork-service/src/main/java/cn/com/qmth/examcloud/core/examwork/service/ExamService.java

@@ -80,6 +80,6 @@ public interface ExamService {
      */
     String getExamProperty(Long examId, String key);
 
-    Map<Long, String> getExamNamesByIds(Set<Long> examIds);
+    Map<Long, ExamEntity> getExamMapsByIds(Set<Long> examIds);
 
 }

+ 2 - 2
examcloud-core-examwork-service/src/main/java/cn/com/qmth/examcloud/core/examwork/service/impl/ExamServiceImpl.java

@@ -804,7 +804,7 @@ public class ExamServiceImpl implements ExamService {
     }
 
     @Override
-    public Map<Long, String> getExamNamesByIds(Set<Long> examIds) {
+    public Map<Long, ExamEntity> getExamMapsByIds(Set<Long> examIds) {
         if (CollectionUtils.isEmpty(examIds)) {
             return new HashMap<>();
         }
@@ -816,7 +816,7 @@ public class ExamServiceImpl implements ExamService {
         };
 
         List<ExamEntity> entities = examRepo.findAll(spec);
-        return entities.stream().collect(Collectors.toMap(v -> v.getId(), v -> v.getName(), (oldValue, newValue) -> newValue));
+        return entities.stream().collect(Collectors.toMap(v -> v.getId(), v -> v, (k, v) -> v));
     }
 
 }

+ 44 - 45
examcloud-core-examwork-starter/src/main/java/cn/com/qmth/examcloud/core/examwork/starter/CoreExamWorkApp.java

@@ -1,5 +1,10 @@
 package cn.com.qmth.examcloud.core.examwork.starter;
 
+import cn.com.qmth.examcloud.core.examwork.base.enums.ExamProperty;
+import cn.com.qmth.examcloud.core.examwork.dao.UniqueRuleHolder;
+import cn.com.qmth.examcloud.web.bootstrap.AppBootstrap;
+import cn.com.qmth.examcloud.web.jpa.DataIntegrityViolationTransverter;
+import cn.com.qmth.examcloud.web.support.SpringContextHolder;
 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.autoconfigure.domain.EntityScan;
@@ -15,12 +20,6 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
 import org.springframework.web.multipart.MultipartResolver;
 import org.springframework.web.multipart.commons.CommonsMultipartResolver;
 
-import cn.com.qmth.examcloud.core.examwork.base.enums.ExamProperty;
-import cn.com.qmth.examcloud.core.examwork.dao.UniqueRuleHolder;
-import cn.com.qmth.examcloud.web.bootstrap.AppBootstrap;
-import cn.com.qmth.examcloud.web.jpa.DataIntegrityViolationTransverter;
-import cn.com.qmth.examcloud.web.support.SpringContextHolder;
-
 @SpringBootApplication
 @Configuration
 @EnableJpaAuditing
@@ -33,49 +32,49 @@ import cn.com.qmth.examcloud.web.support.SpringContextHolder;
 @EnableAutoConfiguration(exclude = {MultipartAutoConfiguration.class})
 public class CoreExamWorkApp {
 
-	static {
-		String runtimeLevel = System.getProperty("log.commonLevel");
-		if (null == runtimeLevel) {
-			System.setProperty("log.commonLevel", "DEBUG");
-		}
-		System.setProperty("hibernate.dialect.storage_engine", "innodb");
+    static {
+        String runtimeLevel = System.getProperty("log.commonLevel");
+        if (null == runtimeLevel) {
+            System.setProperty("log.commonLevel", "INFO");
+        }
+        System.setProperty("hibernate.dialect.storage_engine", "innodb");
 
-		DataIntegrityViolationTransverter.setUniqueRules(UniqueRuleHolder.getUniqueRuleList());
-		ExamProperty.init();
-	}
+        DataIntegrityViolationTransverter.setUniqueRules(UniqueRuleHolder.getUniqueRuleList());
+        ExamProperty.init();
+    }
 
-	/**
-	 * main 启动类
-	 *
-	 * @author WANGWEI
-	 * @param args
-	 * @throws Exception
-	 */
-	public static void main(String[] args) throws Exception {
-		//test 再次测试git文件,配合测试20200928004
-		AppBootstrap.run(CoreExamWorkApp.class, args);
+    /**
+     * main 启动类
+     *
+     * @param args
+     * @throws Exception
+     * @author WANGWEI
+     */
+    public static void main(String[] args) throws Exception {
+        //test 再次测试git文件,配合测试20200928004
+        AppBootstrap.run(CoreExamWorkApp.class, args);
 
-		test();
-	}
+        test();
+    }
 
-	/**
-	 * 测试方法
-	 *
-	 * @author WANGWEI
-	 */
-	private static void test() {
-		Tester tester = SpringContextHolder.getBean(Tester.class);
-		tester.test();
-	}
+    /**
+     * 测试方法
+     *
+     * @author WANGWEI
+     */
+    private static void test() {
+        Tester tester = SpringContextHolder.getBean(Tester.class);
+        tester.test();
+    }
 
-	@Bean(name = "multipartResolver")
-	public MultipartResolver multipartResolver() {
-		CommonsMultipartResolver resolver = new CommonsMultipartResolver();
-		resolver.setDefaultEncoding("UTF-8");
-		resolver.setResolveLazily(true);
-		resolver.setMaxInMemorySize(2);
-		resolver.setMaxUploadSize(200 * 1024 * 1024);
-		return resolver;
-	}
+    @Bean(name = "multipartResolver")
+    public MultipartResolver multipartResolver() {
+        CommonsMultipartResolver resolver = new CommonsMultipartResolver();
+        resolver.setDefaultEncoding("UTF-8");
+        resolver.setResolveLazily(true);
+        resolver.setMaxInMemorySize(2);
+        resolver.setMaxUploadSize(200 * 1024 * 1024);
+        return resolver;
+    }
 
 }

+ 126 - 111
examcloud-core-examwork-starter/src/main/java/cn/com/qmth/examcloud/core/examwork/starter/config/ExamCloudResourceManager.java

@@ -1,28 +1,27 @@
 package cn.com.qmth.examcloud.core.examwork.starter.config;
 
-import java.util.List;
-import java.util.Set;
-
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-import com.google.common.collect.Sets;
-
-import cn.com.qmth.examcloud.api.commons.security.bean.AccessApp;
-import cn.com.qmth.examcloud.api.commons.security.bean.Role;
-import cn.com.qmth.examcloud.api.commons.security.bean.User;
-import cn.com.qmth.examcloud.api.commons.security.bean.UserType;
+import cn.com.qmth.examcloud.api.commons.enums.DataRuleType;
+import cn.com.qmth.examcloud.api.commons.security.bean.*;
 import cn.com.qmth.examcloud.api.commons.security.enums.RoleMeta;
 import cn.com.qmth.examcloud.commons.util.PathUtil;
 import cn.com.qmth.examcloud.commons.util.PropertiesUtil;
 import cn.com.qmth.examcloud.commons.util.RegExpUtil;
+import cn.com.qmth.examcloud.core.basic.api.UserDataRuleCloudService;
+import cn.com.qmth.examcloud.core.basic.api.request.QueryUserDataRuleReq;
+import cn.com.qmth.examcloud.core.basic.api.response.QueryUserDataRuleResp;
 import cn.com.qmth.examcloud.support.cache.CacheHelper;
 import cn.com.qmth.examcloud.support.cache.bean.AppCacheBean;
 import cn.com.qmth.examcloud.web.redis.RedisClient;
 import cn.com.qmth.examcloud.web.security.ResourceManager;
 import cn.com.qmth.examcloud.web.support.ApiInfo;
+import com.google.common.collect.Sets;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Set;
 
 /**
  * Demo资源管理器
@@ -34,102 +33,118 @@ import cn.com.qmth.examcloud.web.support.ApiInfo;
 @Component
 public class ExamCloudResourceManager implements ResourceManager {
 
-	@Autowired
-	RedisClient redisClient;
-
-	static {
-		PropertiesUtil.loadFromPath(PathUtil.getResoucePath("security.properties"));
-	}
-
-	@Override
-	public AccessApp getAccessApp(Long appId) {
-		AppCacheBean appCacheBean = CacheHelper.getApp(appId);
-		if (null == appCacheBean) {
-			return null;
-		}
-		AccessApp app = new AccessApp();
-		app.setAppId(appCacheBean.getId());
-		app.setAppCode(appCacheBean.getCode());
-		app.setAppName(appCacheBean.getName());
-		app.setSecretKey(appCacheBean.getSecretKey());
-		app.setTimeRange(appCacheBean.getTimeRange());
-		return app;
-	}
-
-	@Override
-	public boolean isNaked(ApiInfo apiInfo, String mapping) {
-		if (null == apiInfo) {
-			return true;
-		}
-
-		if (mapping.matches(".*swagger.*")) {
-			return true;
-		}
-
-		if (null != apiInfo) {
-			if (apiInfo.isNaked()) {
-				return true;
-			}
-		}
-
-		return false;
-	}
-
-	@Override
-	public boolean hasPermission(User user, ApiInfo apiInfo, String mapping) {
-
-		// 学生鉴权
-		if (user.getUserType().equals(UserType.STUDENT)) {
-			String key = "[s]" + mapping;
-			return PropertiesUtil.getBoolean(key, false);
-		}
-
-		List<Role> roleList = user.getRoleList();
-
-		if (CollectionUtils.isEmpty(roleList)) {
-			return false;
-		}
-
-		for (Role role : roleList) {
-			if (role.getRoleCode().equals(RoleMeta.SUPER_ADMIN.name())) {
-				return true;
-			}
-		}
-
-		// 权限组集合
-		String privilegeGroups = PropertiesUtil.getString(mapping);
-		if (StringUtils.isBlank(privilegeGroups)) {
-			return true;
-		}
-
-		// 用户权限集合
-		Set<String> rolePrivilegeList = Sets.newHashSet();
-		Long rootOrgId = user.getRootOrgId();
-		for (Role role : roleList) {
-			String key = "$_P_" + rootOrgId + "_" + role.getRoleId();
-			String rolePrivileges = redisClient.get(key, String.class);
-
-			List<String> rpList = RegExpUtil.findAll(rolePrivileges, "\\w+");
-			rolePrivilegeList.addAll(rpList);
-		}
-
-		List<String> privilegeGroupList = RegExpUtil.findAll(privilegeGroups, "[^\\;]+");
-
-		for (String pg : privilegeGroupList) {
-			pg = pg.trim();
-			if (StringUtils.isBlank(pg)) {
-				continue;
-			}
-
-			List<String> pList = RegExpUtil.findAll(pg, "[^\\,]+");
-			if (rolePrivilegeList.containsAll(pList)) {
-				return true;
-			} else {
-				continue;
-			}
-		}
-
-		return false;
-	}
+    @Autowired
+    RedisClient redisClient;
+
+    @Autowired
+    UserDataRuleCloudService userDataRuleCloudService;
+
+    static {
+        PropertiesUtil.loadFromPath(PathUtil.getResoucePath("security.properties"));
+    }
+
+    @Override
+    public AccessApp getAccessApp(Long appId) {
+        AppCacheBean appCacheBean = CacheHelper.getApp(appId);
+        if (null == appCacheBean) {
+            return null;
+        }
+        AccessApp app = new AccessApp();
+        app.setAppId(appCacheBean.getId());
+        app.setAppCode(appCacheBean.getCode());
+        app.setAppName(appCacheBean.getName());
+        app.setSecretKey(appCacheBean.getSecretKey());
+        app.setTimeRange(appCacheBean.getTimeRange());
+        return app;
+    }
+
+    @Override
+    public boolean isNaked(ApiInfo apiInfo, String mapping) {
+        if (null == apiInfo) {
+            return true;
+        }
+
+        if (mapping.matches(".*swagger.*")) {
+            return true;
+        }
+
+        if (null != apiInfo) {
+            if (apiInfo.isNaked()) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    @Override
+    public boolean hasPermission(User user, ApiInfo apiInfo, String mapping) {
+
+        // 学生鉴权
+        if (user.getUserType().equals(UserType.STUDENT)) {
+            String key = "[s]" + mapping;
+            return PropertiesUtil.getBoolean(key, false);
+        }
+
+        List<Role> roleList = user.getRoleList();
+
+        if (CollectionUtils.isEmpty(roleList)) {
+            return false;
+        }
+
+        for (Role role : roleList) {
+            if (role.getRoleCode().equals(RoleMeta.SUPER_ADMIN.name())) {
+                return true;
+            }
+        }
+
+        // 权限组集合
+        String privilegeGroups = PropertiesUtil.getString(mapping);
+        if (StringUtils.isBlank(privilegeGroups)) {
+            return true;
+        }
+
+        // 用户权限集合
+        Set<String> rolePrivilegeList = Sets.newHashSet();
+        Long rootOrgId = user.getRootOrgId();
+        for (Role role : roleList) {
+            String key = "$_P_" + rootOrgId + "_" + role.getRoleId();
+            String rolePrivileges = redisClient.get(key, String.class);
+
+            List<String> rpList = RegExpUtil.findAll(rolePrivileges, "\\w+");
+            rolePrivilegeList.addAll(rpList);
+        }
+
+        List<String> privilegeGroupList = RegExpUtil.findAll(privilegeGroups, "[^\\;]+");
+
+        for (String pg : privilegeGroupList) {
+            pg = pg.trim();
+            if (StringUtils.isBlank(pg)) {
+                continue;
+            }
+
+            List<String> pList = RegExpUtil.findAll(pg, "[^\\,]+");
+            if (rolePrivilegeList.containsAll(pList)) {
+                return true;
+            } else {
+                continue;
+            }
+        }
+
+        return false;
+    }
+
+    @Override
+    public UserDataRule loadUserDataRule(Long userId, DataRuleType dataRuleType) {
+        QueryUserDataRuleReq req = new QueryUserDataRuleReq();
+        req.setUserId(userId);
+        req.setType(dataRuleType);
+        QueryUserDataRuleResp resp = userDataRuleCloudService.queryUserDataRule(req);
+
+        UserDataRule userDataRule = new UserDataRule();
+        userDataRule.setGlobalStatus(resp.getGlobalStatus());
+        userDataRule.setRefIds(resp.getRefIds());
+        return userDataRule;
+    }
 
 }

+ 28 - 27
examcloud-core-examwork-starter/src/main/java/cn/com/qmth/examcloud/core/examwork/starter/config/ExamCloudWebMvcConfigurer.java

@@ -1,19 +1,19 @@
 package cn.com.qmth.examcloud.core.examwork.starter.config;
 
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.web.servlet.config.annotation.CorsRegistry;
-import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
-import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
-
 import cn.com.qmth.examcloud.web.interceptor.ApiFlowLimitedInterceptor;
 import cn.com.qmth.examcloud.web.interceptor.ApiStatisticInterceptor;
 import cn.com.qmth.examcloud.web.interceptor.FirstInterceptor;
 import cn.com.qmth.examcloud.web.interceptor.SeqlockInterceptor;
 import cn.com.qmth.examcloud.web.redis.RedisClient;
+import cn.com.qmth.examcloud.web.security.DataRuleInterceptor;
 import cn.com.qmth.examcloud.web.security.RequestPermissionInterceptor;
 import cn.com.qmth.examcloud.web.security.ResourceManager;
 import cn.com.qmth.examcloud.web.security.RpcInterceptor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 
 /**
  * WebMvcConfigurer
@@ -25,29 +25,30 @@ import cn.com.qmth.examcloud.web.security.RpcInterceptor;
 @Configuration
 public class ExamCloudWebMvcConfigurer implements WebMvcConfigurer {
 
-	@Autowired
-	ResourceManager resourceManager;
+    @Autowired
+    ResourceManager resourceManager;
+
+    @Autowired
+    RedisClient redisClient;
 
-	@Autowired
-	RedisClient redisClient;
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+        registry.addInterceptor(new FirstInterceptor()).addPathPatterns("/**");
+        registry.addInterceptor(new ApiFlowLimitedInterceptor()).addPathPatterns("/**");
+        registry.addInterceptor(new RpcInterceptor(resourceManager)).addPathPatterns("/**");
 
-	@Override
-	public void addInterceptors(InterceptorRegistry registry) {
-		registry.addInterceptor(new FirstInterceptor()).addPathPatterns("/**");
-		registry.addInterceptor(new ApiFlowLimitedInterceptor()).addPathPatterns("/**");
-		registry.addInterceptor(new RpcInterceptor(resourceManager)).addPathPatterns("/**");
+        RequestPermissionInterceptor permissionInterceptor = new RequestPermissionInterceptor(resourceManager, redisClient);
+        registry.addInterceptor(permissionInterceptor).addPathPatterns("/**");
+        registry.addInterceptor(new SeqlockInterceptor(redisClient)).addPathPatterns("/**");
+        registry.addInterceptor(new ApiStatisticInterceptor()).addPathPatterns("/**");
 
-		RequestPermissionInterceptor permissionInterceptor = new RequestPermissionInterceptor(
-				resourceManager, redisClient);
-		registry.addInterceptor(permissionInterceptor).addPathPatterns("/**");
-		registry.addInterceptor(new SeqlockInterceptor(redisClient)).addPathPatterns("/**");
-		registry.addInterceptor(new ApiStatisticInterceptor()).addPathPatterns("/**");
-	}
+        registry.addInterceptor(new DataRuleInterceptor(resourceManager)).addPathPatterns("/api/**");
+    }
 
-	@Override
-	public void addCorsMappings(CorsRegistry registry) {
-		registry.addMapping("/**").allowedOrigins("*").allowCredentials(false).allowedMethods("*")
-				.maxAge(3600);
-	}
+    @Override
+    public void addCorsMappings(CorsRegistry registry) {
+        registry.addMapping("/**").allowedOrigins("*").allowCredentials(false).allowedMethods("*")
+                .maxAge(3600);
+    }
 
-}
+}

+ 24 - 0
examcloud-core-examwork-starter/src/main/resources/exam-properties.xml

@@ -264,4 +264,28 @@
 		<desc>开放APP考试</desc>
 		<valueType>BOOLEAN</valueType>
 	</enum>
+	<enum>
+		<id>45</id>
+		<name>VIRTUAL_CAMERA_AUDIT_ENABLED</name>
+		<desc>虚拟摄像头进入待审</desc>
+		<valueType>BOOLEAN</valueType>
+	</enum>
+	<enum>
+		<id>46</id>
+		<name>EXAM_CYCLE_ENABLED</name>
+		<desc>是否启用考试周期设置</desc>
+		<valueType>BOOLEAN</valueType>
+	</enum>
+	<enum>
+		<id>47</id>
+		<name>EXAM_CYCLE_WEEK</name>
+		<desc>考试周期星期设置</desc>
+		<valueType>STRING</valueType>
+	</enum>
+	<enum>
+		<id>48</id>
+		<name>EXAM_CYCLE_TIME_RANGE</name>
+		<desc>考试周期时间段设置</desc>
+		<valueType>STRING</valueType>
+	</enum>
 </enums>

BIN
examcloud-core-examwork-starter/src/main/resources/templates/studentImportTemplate.xlsx