Просмотр исходного кода

尝试合并分析统计的代码

MengyangDuan 4 лет назад
Родитель
Сommit
7d18a96488
77 измененных файлов с 3575 добавлено и 257 удалено
  1. 4 0
      .gitattributes
  2. 31 0
      logs/crowdsource-backend.log.2020-10-12.log
  3. 31 0
      logs/crowdsource-backend.log.2020-10-22.log
  4. 31 0
      logs/crowdsource-backend.log.2020-10-26.log
  5. 113 0
      logs/crowdsource-backend.log.2020-10-30.log
  6. 6 0
      logs/crowdsource-backend.log.2020-11-02.log
  7. 6 0
      logs/crowdsource-backend.log.2020-11-04.log
  8. 6 0
      logs/crowdsource-backend.log.2020-11-18.log
  9. 6 0
      logs/crowdsource-backend.log.2021-04-20.log
  10. 0 0
      logs/recommend.log.2020-10-12.log
  11. 0 0
      logs/recommend.log.2020-10-22.log
  12. 0 0
      logs/recommend.log.2020-10-26.log
  13. 0 0
      logs/recommend.log.2020-10-30.log
  14. 0 0
      logs/recommend.log.2020-11-02.log
  15. 0 0
      logs/recommend.log.2020-11-04.log
  16. 0 0
      logs/recommend.log.2020-11-18.log
  17. 0 0
      logs/recommend.log.2021-04-20.log
  18. 28 22
      pom.xml
  19. 120 0
      src/main/java/edu/nju/algorithm/progress/BugForProgress.java
  20. 34 0
      src/main/java/edu/nju/algorithm/progress/ConstantsForProgress.java
  21. 80 0
      src/main/java/edu/nju/algorithm/progress/M0CRCAlgorithm.java
  22. 97 0
      src/main/java/edu/nju/algorithm/progress/TaskClosePrediction.java
  23. 305 7
      src/main/java/edu/nju/controller/AnalyzeController.java
  24. 4 1
      src/main/java/edu/nju/controller/CrowdsourcingToReviewController.java
  25. 1 1
      src/main/java/edu/nju/controller/DataController.java
  26. 10 22
      src/main/java/edu/nju/controller/ExtraController.java
  27. 45 1
      src/main/java/edu/nju/controller/HistoryController.java
  28. 16 0
      src/main/java/edu/nju/controller/NodeController.java
  29. 7 1
      src/main/java/edu/nju/controller/OAuthController.java
  30. 36 5
      src/main/java/edu/nju/controller/ReviewAnalyzeController.java
  31. 19 0
      src/main/java/edu/nju/controller/ReviewPaperController.java
  32. 5 0
      src/main/java/edu/nju/controller/UploadController.java
  33. 8 0
      src/main/java/edu/nju/dao/BugHistoryDao.java
  34. 2 1
      src/main/java/edu/nju/dao/CTBDao.java
  35. 3 1
      src/main/java/edu/nju/dao/CaseToBugDao.java
  36. 36 0
      src/main/java/edu/nju/dao/CrowdTestDao.java
  37. 5 1
      src/main/java/edu/nju/dao/ReportDao.java
  38. 1 1
      src/main/java/edu/nju/dao/ReviewGroupDao.java
  39. 44 0
      src/main/java/edu/nju/dao/ShortTokenDao.java
  40. 8 0
      src/main/java/edu/nju/dao/StuInfoDao.java
  41. 21 1
      src/main/java/edu/nju/dao/TaskDao.java
  42. 10 4
      src/main/java/edu/nju/dao/TestCaseDao.java
  43. 7 0
      src/main/java/edu/nju/dao/ThumsUpDao.java
  44. 40 0
      src/main/java/edu/nju/dao/UserLabelDao.java
  45. 1 2
      src/main/java/edu/nju/entities/Bug.java
  46. 78 0
      src/main/java/edu/nju/entities/CrowdTest.java
  47. 1 1
      src/main/java/edu/nju/entities/ReviewPaper.java
  48. 110 0
      src/main/java/edu/nju/entities/ShortToken.java
  49. 27 0
      src/main/java/edu/nju/entities/UserLabel.java
  50. 33 0
      src/main/java/edu/nju/model/AnalysePeopleVO.java
  51. 69 0
      src/main/java/edu/nju/model/AnalyseVO2.java
  52. 1 1
      src/main/java/edu/nju/model/BugRecurrent.java
  53. 1 5
      src/main/java/edu/nju/model/BugSeverity.java
  54. 75 0
      src/main/java/edu/nju/model/ExamVO.java
  55. 64 0
      src/main/java/edu/nju/model/HistoricalDataVO.java
  56. 59 0
      src/main/java/edu/nju/model/PageExamVO.java
  57. 5 0
      src/main/java/edu/nju/model/WebBrand.java
  58. 4 4
      src/main/java/edu/nju/model/WorkerVO.java
  59. 696 86
      src/main/java/edu/nju/service/AnalyzeService.java
  60. 0 2
      src/main/java/edu/nju/service/DataService.java
  61. 40 2
      src/main/java/edu/nju/service/ExtraService.java
  62. 17 0
      src/main/java/edu/nju/service/FileService.java
  63. 471 0
      src/main/java/edu/nju/service/NginxFileService.java
  64. 17 0
      src/main/java/edu/nju/service/NodeService.java
  65. 4 0
      src/main/java/edu/nju/service/ReportService.java
  66. 176 4
      src/main/java/edu/nju/service/ReviewAnalyzeService.java
  67. 11 10
      src/main/java/edu/nju/service/ReviewJobService.java
  68. 8 0
      src/main/java/edu/nju/service/ReviewPaperService.java
  69. 13 5
      src/main/java/edu/nju/service/ReviewService.java
  70. 51 0
      src/main/java/edu/nju/util/AESUtil.java
  71. 233 61
      src/main/java/edu/nju/util/BlockChainAspect.java
  72. 32 0
      src/main/java/edu/nju/util/DataMaskingUtil.java
  73. 8 1
      src/main/java/edu/nju/util/HTTP.java
  74. 28 0
      src/main/java/edu/nju/util/TimeUtil.java
  75. 2 2
      src/main/java/paperjson
  76. 2 2
      src/main/resources/logback.xml
  77. 12 0
      src/workerDIstribution

+ 4 - 0
.gitattributes

@@ -1,2 +1,6 @@
 # Auto detect text files and perform LF normalization
 * text=auto
+
+/target/
+.yml
+.xml

Разница между файлами не показана из-за своего большого размера
+ 31 - 0
logs/crowdsource-backend.log.2020-10-12.log


Разница между файлами не показана из-за своего большого размера
+ 31 - 0
logs/crowdsource-backend.log.2020-10-22.log


Разница между файлами не показана из-за своего большого размера
+ 31 - 0
logs/crowdsource-backend.log.2020-10-26.log


+ 113 - 0
logs/crowdsource-backend.log.2020-10-30.log

@@ -0,0 +1,113 @@
+15:35:52.985 [main] INFO  o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker - Bean 'org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration' of type [org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration$$EnhancerBySpringCGLIB$$87d25f89] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) 
+15:35:53.364 [main] INFO  edu.nju.BugApplication - The following profiles are active: dev 
+15:35:54.991 [main] WARN  o.s.b.actuate.endpoint.EndpointId - Endpoint ID 'nacos-discovery' contains invalid characters, please migrate to a valid format. 
+15:35:55.538 [main] INFO  o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data repositories in DEFAULT mode. 
+15:35:55.571 [main] INFO  o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 26ms. Found 0 repository interfaces. 
+15:35:55.727 [main] WARN  o.s.b.actuate.endpoint.EndpointId - Endpoint ID 'service-registry' contains invalid characters, please migrate to a valid format. 
+15:35:56.013 [main] INFO  o.s.c.context.scope.GenericScope - BeanFactory id=dd69386d-7336-3446-b1bd-c86a36be6a84 
+15:35:56.254 [main] INFO  o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker - Bean 'org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration' of type [org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration$$EnhancerBySpringCGLIB$$87d25f89] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) 
+15:35:56.998 [main] INFO  o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 8080 (http) 
+15:35:57.040 [main] INFO  o.a.catalina.core.StandardService - Starting service [Tomcat] 
+15:35:57.040 [main] INFO  o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/9.0.17] 
+15:35:57.250 [main] INFO  o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext 
+15:35:57.251 [main] INFO  o.s.web.context.ContextLoader - Root WebApplicationContext: initialization completed in 3797 ms 
+15:35:57.946 [main] INFO  org.mongodb.driver.cluster - Cluster created with settings {hosts=[localhost:27017], mode=SINGLE, requiredClusterType=UNKNOWN, serverSelectionTimeout='30000 ms', maxWaitQueueSize=500} 
+15:35:58.133 [cluster-ClusterId{value='5f9bc25d1d830702c595cb18', description='null'}-localhost:27017] INFO  org.mongodb.driver.connection - Opened connection [connectionId{localValue:1, serverValue:1}] to localhost:27017 
+15:35:58.137 [cluster-ClusterId{value='5f9bc25d1d830702c595cb18', description='null'}-localhost:27017] INFO  org.mongodb.driver.cluster - Monitor thread successfully connected to server with description ServerDescription{address=localhost:27017, type=STANDALONE, state=CONNECTED, ok=true, version=ServerVersion{versionList=[4, 0, 3]}, minWireVersion=0, maxWireVersion=7, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=2844493} 
+15:35:58.681 [main] INFO  org.mongodb.driver.connection - Opened connection [connectionId{localValue:2, serverValue:2}] to localhost:27017 
+15:35:59.459 [main] WARN  o.s.b.w.s.c.AnnotationConfigServletWebServerApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'analyzeController': Unsatisfied dependency expressed through field 'blockChainAspect'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'blockChainAspect': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'mooctest.url' in value "${mooctest.url}" 
+15:35:59.461 [main] INFO  org.mongodb.driver.connection - Closed connection [connectionId{localValue:2, serverValue:2}] to localhost:27017 because the pool has been closed. 
+15:35:59.464 [main] INFO  o.a.catalina.core.StandardService - Stopping service [Tomcat] 
+15:35:59.469 [main] WARN  o.a.c.loader.WebappClassLoaderBase - The web application [ROOT] appears to have started a thread named [logback-1] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
+ sun.misc.Unsafe.park(Native Method)
+ java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
+ java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
+ java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1093)
+ java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
+ java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
+ java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
+ java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
+ java.lang.Thread.run(Thread.java:748) 
+15:35:59.469 [main] WARN  o.a.c.loader.WebappClassLoaderBase - The web application [ROOT] appears to have started a thread named [com.alibaba.nacos.naming.client.listener] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
+ sun.misc.Unsafe.park(Native Method)
+ java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
+ java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
+ java.util.concurrent.LinkedBlockingQueue.poll(LinkedBlockingQueue.java:467)
+ com.alibaba.nacos.client.naming.core.EventDispatcher$Notifier.run(EventDispatcher.java:114)
+ java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
+ java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
+ java.lang.Thread.run(Thread.java:748) 
+15:35:59.470 [main] WARN  o.a.c.loader.WebappClassLoaderBase - The web application [ROOT] appears to have started a thread named [com.alibaba.nacos.naming.failover] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
+ sun.misc.Unsafe.park(Native Method)
+ java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
+ java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
+ java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1093)
+ java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
+ java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
+ java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
+ java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
+ java.lang.Thread.run(Thread.java:748) 
+15:35:59.470 [main] WARN  o.a.c.loader.WebappClassLoaderBase - The web application [ROOT] appears to have started a thread named [com.alibaba.nacos.naming.push.receiver] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
+ java.net.PlainDatagramSocketImpl.receive0(Native Method)
+ java.net.AbstractPlainDatagramSocketImpl.receive(AbstractPlainDatagramSocketImpl.java:143)
+ java.net.DatagramSocket.receive(DatagramSocket.java:812)
+ com.alibaba.nacos.client.naming.core.PushReceiver.run(PushReceiver.java:73)
+ java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
+ java.util.concurrent.FutureTask.run(FutureTask.java:266)
+ java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
+ java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
+ java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
+ java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
+ java.lang.Thread.run(Thread.java:748) 
+15:35:59.481 [main] INFO  o.s.b.a.l.ConditionEvaluationReportLoggingListener - 
+
+Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled. 
+15:35:59.490 [main] ERROR o.s.boot.SpringApplication - Application run failed 
+org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'analyzeController': Unsatisfied dependency expressed through field 'blockChainAspect'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'blockChainAspect': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'mooctest.url' in value "${mooctest.url}"
+	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:596)
+	at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90)
+	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:374)
+	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1411)
+	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:592)
+	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
+	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
+	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
+	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
+	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
+	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:849)
+	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:877)
+	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549)
+	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:142)
+	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775)
+	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
+	at org.springframework.boot.SpringApplication.run(SpringApplication.java:316)
+	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260)
+	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248)
+	at edu.nju.BugApplication.main(BugApplication.java:10)
+Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'blockChainAspect': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'mooctest.url' in value "${mooctest.url}"
+	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:380)
+	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1411)
+	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:592)
+	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
+	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
+	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
+	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
+	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
+	at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277)
+	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1247)
+	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1167)
+	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:593)
+	... 19 common frames omitted
+Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'mooctest.url' in value "${mooctest.url}"
+	at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:172)
+	at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:124)
+	at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:237)
+	at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:211)
+	at org.springframework.context.support.PropertySourcesPlaceholderConfigurer.lambda$processProperties$0(PropertySourcesPlaceholderConfigurer.java:175)
+	at org.springframework.beans.factory.support.AbstractBeanFactory.resolveEmbeddedValue(AbstractBeanFactory.java:851)
+	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1188)
+	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1167)
+	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:593)
+	at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90)
+	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:374)
+	... 30 common frames omitted

Разница между файлами не показана из-за своего большого размера
+ 6 - 0
logs/crowdsource-backend.log.2020-11-02.log


Разница между файлами не показана из-за своего большого размера
+ 6 - 0
logs/crowdsource-backend.log.2020-11-04.log


Разница между файлами не показана из-за своего большого размера
+ 6 - 0
logs/crowdsource-backend.log.2020-11-18.log


Разница между файлами не показана из-за своего большого размера
+ 6 - 0
logs/crowdsource-backend.log.2021-04-20.log


+ 0 - 0
logs/recommend.log.2020-10-12.log


+ 0 - 0
logs/recommend.log.2020-10-22.log


+ 0 - 0
logs/recommend.log.2020-10-26.log


+ 0 - 0
logs/recommend.log.2020-10-30.log


+ 0 - 0
logs/recommend.log.2020-11-02.log


+ 0 - 0
logs/recommend.log.2020-11-04.log


+ 0 - 0
logs/recommend.log.2020-11-18.log


+ 0 - 0
logs/recommend.log.2021-04-20.log


+ 28 - 22
pom.xml

@@ -96,24 +96,24 @@
         </dependency>
 
 <!--        nacos-->
-        <dependency>
-            <groupId>org.springframework.cloud</groupId>
-            <artifactId>spring-cloud-starter-gateway</artifactId>
-            <exclusions>
-                <exclusion>
-                    <groupId>org.springframework.cloud</groupId>
-                    <artifactId>spring-boot-starter-web</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.springframework.boot</groupId>
-                    <artifactId>spring-boot-starter-web</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.springframework.boot</groupId>
-                    <artifactId>spring-boot-starter-webflux</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
+<!--        <dependency>-->
+<!--            <groupId>org.springframework.cloud</groupId>-->
+<!--            <artifactId>spring-cloud-starter-gateway</artifactId>-->
+<!--            <exclusions>-->
+<!--                <exclusion>-->
+<!--                    <groupId>org.springframework.cloud</groupId>-->
+<!--                    <artifactId>spring-boot-starter-web</artifactId>-->
+<!--                </exclusion>-->
+<!--                <exclusion>-->
+<!--                    <groupId>org.springframework.boot</groupId>-->
+<!--                    <artifactId>spring-boot-starter-web</artifactId>-->
+<!--                </exclusion>-->
+<!--                <exclusion>-->
+<!--                    <groupId>org.springframework.boot</groupId>-->
+<!--                    <artifactId>spring-boot-starter-webflux</artifactId>-->
+<!--                </exclusion>-->
+<!--            </exclusions>-->
+<!--        </dependency>-->
 
         <!-- Nacos Client -->
         <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-alibaba-nacos-discovery -->
@@ -143,10 +143,10 @@
 
 
         <!-- actuator -->
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-actuator</artifactId>
-        </dependency>
+<!--        <dependency>-->
+<!--            <groupId>org.springframework.boot</groupId>-->
+<!--            <artifactId>spring-boot-starter-actuator</artifactId>-->
+<!--        </dependency>-->
 
         <!--引入AOP依赖-->
         <dependency>
@@ -154,6 +154,12 @@
             <artifactId>spring-boot-starter-aop</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+            <version>25.0-jre</version>
+        </dependency>
+
 
 
     </dependencies>

+ 120 - 0
src/main/java/edu/nju/algorithm/progress/BugForProgress.java

@@ -0,0 +1,120 @@
+package edu.nju.algorithm.progress;
+import java.util.Date;
+
+/**
+ * @Author JiaWei Xu
+ * @Date 2021-01-06 15:56
+ * @Email xjwhhh233@outlook.com
+ */
+
+public class BugForProgress {
+    String id;
+    String testCaseId;
+    String testCaseName;
+    String userId;
+
+    String title;
+    String description;
+    Date bugCreateTime;
+
+    String severity;
+    String bugPage;
+
+    public BugForProgress(){};
+
+    public BugForProgress(String id, String testCaseId, String testCaseName, String title, String description) {
+        this.id = id;
+        this.testCaseId = testCaseId;
+        this.testCaseName = testCaseName;
+
+        this.title = title;
+        this.description = description;
+    }
+
+    public BugForProgress(String id, String testCaseId, String testCaseName, String userId, String title, String description, Date bugCreateTime, String severity, String bugPage) {
+        this.id = id;
+        this.testCaseId = testCaseId;
+        this.userId = userId;
+        this.testCaseName = testCaseName;
+        this.title = title;
+        this.description = description;
+        this.bugCreateTime = bugCreateTime;
+        this.severity = severity;
+        this.bugPage = bugPage;
+    }
+
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getTestCaseId() {
+        return testCaseId;
+    }
+
+    public void setTestCaseId(String testCaseId) {
+        this.testCaseId = testCaseId;
+    }
+
+    public String getTestCaseName() {
+        return testCaseName;
+    }
+
+    public void setTestCaseName(String testCaseName) {
+        this.testCaseName = testCaseName;
+    }
+
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public Date getBugCreateTime() {
+        return bugCreateTime;
+    }
+
+    public void setBugCreateTime(Date bugCreateTime) {
+        this.bugCreateTime = bugCreateTime;
+    }
+
+    public String getSeverity() {
+        return severity;
+    }
+
+    public void setSeverity(String severity) {
+        this.severity = severity;
+    }
+
+    public String getBugPage() {
+        return bugPage;
+    }
+
+    public void setBugPage(String bugPage) {
+        this.bugPage = bugPage;
+    }
+
+}
+

+ 34 - 0
src/main/java/edu/nju/algorithm/progress/ConstantsForProgress.java

@@ -0,0 +1,34 @@
+package edu.nju.algorithm.progress;
+
+/**
+ * @author xujiawei
+ */
+public interface ConstantsForProgress {
+//	final static Integer FIELD_INDEX_TEST_CASE_ID = 0;
+//	final static Integer FIELD_INDEX_USER_ID = 1;
+//	final static Integer FIELD_INDEX_TEST_CASE_NAME	 = 2;
+//	final static Integer FIELD_INDEX_BUG_DETAIL = 9;
+//	final static Integer FIELD_INDEX_REPRO_STEPS = 10;
+//	final static Integer FIELD_INDEX_SUBMIT_TIME  = 15;
+//	final static Integer FIELD_BUG_TAG = 14;
+//	final static Integer FIELD_DUP_TAG  = 17;    //17 corresponds to R column, 18 corresponds to S column
+	
+	// YK add
+	final static String FIELD_BUG_ID = "bug_id";
+	final static String FIELD_TEST_CASE_ID = "test_case_id";
+	final static String FIELD_USER_ID = "worker_id";
+	final static String FIELD_TEST_CASE_NAME	 = "test_case_name";
+	final static String FIELD_BUG_DETAIL = "title";
+	final static String FIELD_REPRO_STEPS = "description";
+	final static String FIELD_SUBMIT_TIME  = "bug_create_time";
+	final static String FIELD_BUG_TAG = "severity";
+	final static String FIELD_DUP_TAG  = "bug_page";    //17 corresponds to R column, 18 corresponds to S column
+	final static double SIM_THRESHOLD = 0.01;
+	
+	int captureSize = 6;
+	int equalTimeThres = 2;
+	
+	final static String projectFolder = "data/demoProjects";     
+
+	Integer sampleStep = 10;
+}

+ 80 - 0
src/main/java/edu/nju/algorithm/progress/M0CRCAlgorithm.java

@@ -0,0 +1,80 @@
+package edu.nju.algorithm.progress;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.TreeMap;
+
+/**
+ * @Author JiaWei Xu
+ * @Date 2021-01-06 15:54
+ * @Email xjwhhh233@outlook.com
+ */
+public class M0CRCAlgorithm {
+    public Integer[] obtainRecaptureResults(TreeMap<Integer, ArrayList<BugForProgress>> captureProcess) {
+        HashSet<String> distinctBugs = new HashSet<String>();
+        for (Integer cap : captureProcess.keySet()) {
+            ArrayList<BugForProgress> reportList = captureProcess.get(cap);
+
+            for (int i = 0; i < reportList.size(); i++) {
+                String dupTag = reportList.get(i).getBugPage();
+                distinctBugs.add(dupTag);
+            }
+        }
+
+        int captureSize = captureProcess.size();
+        int sep1 = captureSize / 2;
+        int sep2 = sep1;
+        int sep3 = sep1;
+        if (sep1 > 3) {
+            sep2 = sep1 - 1;
+            sep3 = sep1 + 1;
+        }
+        if (sep1 > 5) {
+            sep2 = sep1 - 2;
+            sep3 = sep1 + 2;
+        }
+
+        int estBugs1 = this.estimateTotalBugNum(captureProcess, sep1);
+        int estBugs2 = this.estimateTotalBugNum(captureProcess, sep2);
+        int estBugs3 = this.estimateTotalBugNum(captureProcess, sep3);
+
+        int estBugs = (estBugs1 + estBugs2 + estBugs3) / 3;
+        return new Integer[]{estBugs, estBugs, estBugs, distinctBugs.size()};
+    }
+
+    public Integer estimateTotalBugNum(TreeMap<Integer, ArrayList<BugForProgress>> captureProcess, int sep) {
+        HashSet<String> priorNoDupBugs = new HashSet<String>();
+        HashSet<String> laterNoDupBugs = new HashSet<String>();
+        int count = 0;
+        for (Integer cap : captureProcess.keySet()) {
+            count++;
+            ArrayList<BugForProgress> reportList = captureProcess.get(cap);
+            for (int i = 0; i < reportList.size(); i++) {
+                BugForProgress report = reportList.get(i);
+                if (count <= sep) {
+                    priorNoDupBugs.add(report.getBugPage());
+                } else {
+                    laterNoDupBugs.add(report.getBugPage());
+                }
+            }
+        }
+
+        int overlapBugs = 0;
+        for (String dupTag : priorNoDupBugs) {
+            if (laterNoDupBugs.contains(dupTag)) {
+                overlapBugs++;
+            }
+        }
+
+        int priorBugs = priorNoDupBugs.size();
+        int laterBugs = laterNoDupBugs.size();
+
+        int estimateBugs = priorBugs * laterBugs;
+        if (overlapBugs > 0) {
+            estimateBugs = estimateBugs / overlapBugs;
+        }
+
+        return estimateBugs;
+    }
+
+}

+ 97 - 0
src/main/java/edu/nju/algorithm/progress/TaskClosePrediction.java

@@ -0,0 +1,97 @@
+package edu.nju.algorithm.progress;
+
+import edu.nju.entities.Bug;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+import java.util.TreeMap;
+
+/**
+ * @Author JiaWei Xu
+ * @Date 2021-01-06 16:02
+ * @Email xjwhhh233@outlook.com
+ */
+public class TaskClosePrediction {
+    public Double determineTaskProgressStatus(List<BugForProgress> bugForProgressList) {
+        Random rand = new Random();
+
+        ArrayList<Integer[]> captureResults = new ArrayList<Integer[]>();
+        TreeMap<Integer, ArrayList<BugForProgress>> captureProcess = new TreeMap<Integer, ArrayList<BugForProgress>>();
+
+        int captureSize = ConstantsForProgress.captureSize;
+        int equalTimeThres = ConstantsForProgress.equalTimeThres;
+
+        if (bugForProgressList.size() / captureSize < 5) {
+            return bugForProgressList.size() * 2.0;
+        }
+
+        M0CRCAlgorithm M0Algorithm = new M0CRCAlgorithm();
+        int captureTime = -1;
+        for (int i = 0; i < bugForProgressList.size(); ) {
+            captureTime++;
+            int beginReport = captureTime * captureSize;
+            int endReport = beginReport + captureSize;
+
+            if (endReport >= bugForProgressList.size()) {
+                break;
+            }
+
+            ArrayList<BugForProgress> curCapture = new ArrayList<BugForProgress>();
+            for (int j = beginReport; j < endReport && j < bugForProgressList.size(); j++) {
+                curCapture.add(bugForProgressList.get(j));
+            }
+            captureProcess.put(captureTime, curCapture);
+
+            Integer[] results = M0Algorithm.obtainRecaptureResults(captureProcess);    //estBugs, estBugs, estBugs, alreadySubBugs
+            captureResults.add(results);
+        }
+
+        Boolean isTerminate = this.whetherCanTerminate(captureResults, equalTimeThres);
+        Integer[] lastResults = captureResults.get(captureResults.size() - 1);
+        Double bugRatio = 1.0 * lastResults[3] / lastResults[0];
+        //System.out.println ( "bug ratio : " + bugRatio + " whether can terminate: " + isTerminate );
+
+        bugRatio = bugRatio * 100;
+        if (!isTerminate) {
+            if (bugRatio > 98) {
+                bugRatio = rand.nextInt(4) + 94.0;
+            }
+        }
+
+        return bugRatio;
+    }
+
+    private Boolean whetherCanTerminate(ArrayList<Integer[]> captureResults, Integer equalTimeThres) {
+        if (captureResults.size() < equalTimeThres) {
+            return false;
+        }
+
+        int count = 0;
+        for (int i = captureResults.size() - 1; i > 0; i--) {
+            Integer[] curResults = captureResults.get(i);
+            Integer[] priorResults = captureResults.get(i - 1);
+
+            if (this.isEqual(priorResults, curResults)) {
+                count++;
+            } else {
+                break;
+            }
+
+            if (count >= equalTimeThres) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private Boolean isEqual(Integer[] priorResults, Integer[] curResults) {
+        if (!curResults[0].equals(curResults[3])) {
+            return false;
+        }
+        if (curResults[3] == 0) {
+            return false;
+        }
+        return true;
+    }
+}

+ 305 - 7
src/main/java/edu/nju/controller/AnalyzeController.java

@@ -1,21 +1,29 @@
 package edu.nju.controller;
 
+import java.io.IOException;
 import java.io.PrintWriter;
+import java.net.URLDecoder;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
 import javax.servlet.http.HttpServletResponse;
 
-import edu.nju.model.AnalyseVO;
-import edu.nju.model.BugDataVO;
+import edu.nju.dao.TaskDao;
+import edu.nju.entities.Task;
+import edu.nju.entities.ShortToken;
+import edu.nju.model.*;
+import edu.nju.util.AESUtil;
+import edu.nju.util.BlockChainAspect;
 import org.json.JSONArray;
 import org.json.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.CrossOrigin;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.util.DigestUtils;
+import org.springframework.web.bind.annotation.*;
 
 import edu.nju.service.AnalyzeService;
 import edu.nju.service.ReportService;
@@ -30,7 +38,16 @@ public class AnalyzeController {
 	
 	@Autowired
 	ReportService rservice;
-	
+
+	@Autowired
+	BlockChainAspect blockChainAspect;
+
+	@Autowired
+	TaskDao taskDao;
+
+
+	Logger log= LoggerFactory.getLogger(AnalyzeController.class);
+
 	//根据用例获取所有有效bug
 	@RequestMapping(value = "/valid")
 	@ResponseBody
@@ -328,7 +345,7 @@ public class AnalyzeController {
 		}
 	}
 
-	@RequestMapping(value = "/analyseExam")
+	@RequestMapping(value = "/anabootstrap.ymllyseExam")
 	@ResponseBody
 	public void analyseExam(String caseId, String taskId, HttpServletResponse response){
 		try {
@@ -341,4 +358,285 @@ public class AnalyzeController {
 			e.printStackTrace();
 		}
 	}
+
+	/**
+	 * todo 引进 guvva 来做缓存
+	 * @param caseId
+	 * @param taskId
+	 * @param workId
+	 * @param response
+	 */
+	@RequestMapping(value = "/analysePeople")
+	@ResponseBody
+	public void analysePeople(String caseId, String taskId, String workId , HttpServletResponse response){
+		try {
+			response.setCharacterEncoding("utf-8");
+			response.setContentType("text/html;charset=utf-8");
+			PrintWriter out = response.getWriter();
+			AnalysePeopleVO analyseVO=aservice.getReviewAnalysePeopleVO(caseId, taskId,workId);
+			out.print(new JSONObject(analyseVO));
+			out.flush();
+			out.close();
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+	@RequestMapping(value = "/analyse/getTaskToken")
+	@ResponseBody
+	public String getAnalyseTaskToken(String caseId,String taskId,HttpServletResponse response ){
+		return AESUtil.encrypt("taskId="+taskId+"&caseId="+caseId);
+	}
+
+	@RequestMapping(value = "/analyse/task")
+	public void analyseTask(String token, HttpServletResponse response ){
+		String realUrl = AESUtil.decrypt(token);
+		String [] decoder = url2decode(realUrl);
+		analyseExam2(decoder[1],decoder[0],response);
+//		return "redirect:/analyze/analyseExam2?"+realUrl;
+	}
+
+	/**
+	 * todo 引进 guvva 来做缓存
+	 * @param workId
+	 * @param response
+	 */
+	@RequestMapping(value = "/analyse/people")
+	public void analyseSinglePeople(String token, String workId , HttpServletResponse response){
+		String realUrl = AESUtil.decrypt(token);
+		String [] decoder = url2decode(realUrl);
+		analysePeople(decoder[1],decoder[0],workId,response);
+//		return "redirect:/analyze/analysePeople?"+realUrl+"&workId="+workId;
+	}
+
+	@RequestMapping(value = "/historicalData")
+	@ResponseBody
+	public HistoricalDataVO getHistoricalData(Long workerId,int caseTypeId){
+		return aservice.getHistoricalData(workerId, caseTypeId);
+	}
+
+	@RequestMapping(value = "/uploadTestReportToBlockChain")
+	@ResponseBody
+	public void uploadTestReport(String bug_id,HttpServletResponse response){
+		try {
+			PrintWriter out = response.getWriter();
+			JSONObject result = new JSONObject();
+			if (blockChainAspect.uploadTestReportInfoToBlockChain(bug_id)) {
+				result.put("status","200");
+			}else{
+				result.put("status","500");
+			}
+			out.print(result);
+			out.flush();
+			out.close();
+		}catch (IOException e){
+			e.printStackTrace();
+		}
+	}
+
+	@RequestMapping(value = "/analyseExam2", method = RequestMethod.GET)
+	@ResponseBody
+	public void analyseExam2(@RequestParam("caseId") String caseId, @RequestParam("taskId")  String taskId, HttpServletResponse response){
+		try {
+			response.setCharacterEncoding("utf-8");
+			response.setContentType("text/html;charset=utf-8");
+			PrintWriter out = response.getWriter();
+			AnalyseVO2 analyseVO=aservice.getReviewAnalyseVO2(caseId, taskId);
+			out.print(new JSONObject(analyseVO));
+			out.flush();
+			out.close();
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+	@RequestMapping(value = "/analysePageCover", method = RequestMethod.GET)
+	@ResponseBody
+	public void analysePageCover(@RequestParam("caseId") String caseId, @RequestParam("taskId")  String taskId, HttpServletResponse response){
+		try {
+			response.setCharacterEncoding("utf-8");
+			response.setContentType("text/html;charset=utf-8");
+			PrintWriter out = response.getWriter();
+			Map<String,Integer>map=aservice.getPageCover(taskId, caseId);
+			out.print(new JSONObject(map));
+			out.flush();
+			out.close();
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+	@RequestMapping(value = "/analyseBugInfo", method = RequestMethod.GET)
+	@ResponseBody
+	public void analyseBugInfo(@RequestParam("caseId") String caseId, @RequestParam("taskId")  String taskId, HttpServletResponse response){
+		try {
+			response.setCharacterEncoding("utf-8");
+			response.setContentType("text/html;charset=utf-8");
+			PrintWriter out = response.getWriter();
+			int[][]bugInfo=aservice.getBugInfo(taskId, caseId);
+			JSONArray res = new JSONArray();
+			for(int i =0;i<bugInfo.length;i++){
+				for(int j =0;j<bugInfo[0].length;j++){
+					if(bugInfo[i][j]!=0){
+						JSONArray  temp  = new JSONArray();
+						temp.put(BugSeverity.getValue(i));
+						temp.put(BugRecurrent.getValue(j));
+						temp.put(bugInfo[i][j]);
+						temp.put(bugInfo[i][j]+"个");
+						temp.put("报告数量 ");
+						res.put(temp);
+					}
+				}
+			}
+			out.print(res);
+			out.flush();
+			out.close();
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+	@RequestMapping(value = "/analyse/BugInfo", method = RequestMethod.GET)
+	public void analyseBugInfoByToken(@RequestParam("token") String token, HttpServletResponse response){
+		try {
+			String realUrl = AESUtil.decrypt(token);
+			String [] decoder = url2decode(realUrl);
+			analyseBugInfo(decoder[1],decoder[0],response);
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+
+	@RequestMapping(value = "/analyseBugSubmitInfo", method = RequestMethod.GET)
+	public void analyseBugSubmitInfo(@RequestParam("caseId") String caseId, @RequestParam("taskId")  String taskId,@RequestParam("piece")  int piece, HttpServletResponse response){
+		try {
+			response.setCharacterEncoding("utf-8");
+			response.setContentType("text/html;charset=utf-8");
+			PrintWriter out = response.getWriter();
+			Map<String,Integer>map=aservice.getBugSubmitInfo(taskId,caseId,piece);
+			JSONObject res =  new JSONObject();
+			JSONArray label =  new JSONArray(map.keySet());
+			JSONArray data = new JSONArray(map.values());
+			res.put("label",label);
+			res.put("data",data);
+			out.print(res);
+			out.flush();
+			out.close();
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+	@RequestMapping(value = "/analyse/BugSubmitInfo", method = RequestMethod.GET)
+	@ResponseBody
+	public void analyseBugSubmitInfoByToken(@RequestParam("token") String token ,@RequestParam("piece")  int piece, HttpServletResponse response){
+		try {
+			String realUrl = AESUtil.decrypt(token);
+			String [] decoder = url2decode(realUrl);
+			analyseBugSubmitInfo(decoder[1],decoder[0],piece,response);
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+	/**
+	 * 根据token获取众测任务具体信息
+	 * @param token
+	 * @param response
+	 */
+	@RequestMapping(value = "/tokenToDetail")
+	@ResponseBody
+	public void tokenToDetailUrl(String token ,HttpServletResponse response){
+		try {
+			JSONObject result = new JSONObject();
+			ShortToken shortToken=aservice.tokenToDetail(token);
+			if(shortToken==null){
+				result.put("result","fail");
+				result.put("cause","no such token");
+			}else {
+				result.put("result", "success");
+				result.put("examId",shortToken.getExamId());
+				result.put("caseId",shortToken.getCaseId());
+				result.put("userId",shortToken.getUserId());
+				result.put("beginTime",shortToken.getBeginTime());
+				result.put("endTime",shortToken.getEndTime());
+			}
+			PrintWriter out = response.getWriter();
+			out.print(result);
+			out.flush();
+			out.close();
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+	/**
+	 * 根据众测信息获取对应token
+	 * @param examId
+	 * @param caseId
+	 * @param userId
+	 * @param beginTime
+	 * @param endTime
+	 * @return
+	 */
+	@RequestMapping(value = "/detailToToken")
+	@ResponseBody
+	public String detailToToken(String examId,String caseId,String userId,String beginTime,String endTime){
+		JSONObject result = new JSONObject();
+		try {
+			ShortToken shortToken=aservice.findTokenByDetail(examId,caseId,userId);
+			if(shortToken==null){
+//				String token=AESUtil.encrypt(examId+"/"+caseId+"/"+userId);
+				String token= DigestUtils.md5DigestAsHex((examId+"/"+caseId+"/"+userId).getBytes());
+				ShortToken newShortToken=new ShortToken(token,beginTime,endTime,caseId,examId,userId,true);
+				aservice.saveShortToken(newShortToken);
+				result.put("result","success");
+				result.put("token",token);
+			}else{
+				shortToken.setBeginTime(beginTime);
+				shortToken.setEndTime(endTime);
+				aservice.saveShortToken(shortToken);
+				result.put("result","success");
+				result.put("token",shortToken.getToken());
+			}
+			return result.toString();
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		result.put("result","fail");
+		return result.toString();
+	}
+
+
+
+	@RequestMapping(value = "/progress", method = RequestMethod.GET)
+	@ResponseBody
+	public Double crowdTestProgress(String token){
+		String realUrl = AESUtil.decrypt(token);
+		String [] decoder = url2decode(realUrl);
+		String taskId=decoder[0];
+		String caseId=decoder[1];
+		Task task=taskDao.findById(taskId);
+		if(task.getEnd_time()>System.currentTimeMillis()){
+			return aservice.crowdTestProgressFromDB(caseId,taskId);
+		}else{
+			return aservice.crowdTestProgress(caseId,taskId);
+		}
+	}
+
+
+	private String [] url2decode(String str){
+		log.info("#AnalyseController url2decode(): "+str);
+		String [] res = new String[2];
+		String []  temp = str.split("&");
+		if(temp[0].startsWith("taskId=")){
+			res[0]  = temp[0].substring(7);
+		}
+		if(temp[1].startsWith("caseId=")){
+			res[1] = temp[1].substring(7);
+		}
+		return res;
+	}
+
 }

+ 4 - 1
src/main/java/edu/nju/controller/CrowdsourcingToReviewController.java

@@ -30,9 +30,12 @@ public class CrowdsourcingToReviewController {
         ReviewJob reviewJob=rService.getJob(jobId);
         String result="";
         if(reviewJob!=null){
-            String temp=reviewJob.getExam_id();
+            String temp=reviewJob.getCase_id();
             if(temp!=null)
                 result=temp;
+            String taskId=reviewJob.getExam_id();
+            if(taskId!=null)
+                result=result+"-"+taskId;
         }
         return result;
     }

+ 1 - 1
src/main/java/edu/nju/controller/DataController.java

@@ -8,6 +8,7 @@ import org.springframework.web.bind.annotation.*;
 import java.util.List;
 import org.springframework.web.multipart.MultipartFile;
 
+
 /**
  * @Author JiaWei Xu
  * @Date 2020-12-25 10:40
@@ -39,5 +40,4 @@ public class DataController {
         return dataService.saveBugDetailFromFile(sourceZipFile,sourceJsonFile,originalCaseId,cpSerialNum);
     }
 
-
 }

+ 10 - 22
src/main/java/edu/nju/controller/ExtraController.java

@@ -9,6 +9,8 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import edu.nju.entities.*;
+import edu.nju.model.ExamVO;
+import edu.nju.model.PageExamVO;
 import org.json.JSONArray;
 import org.json.JSONObject;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -95,6 +97,13 @@ public class ExtraController {
 			e.printStackTrace();
 		}
 	}
+
+	//获得一场众测三级页面信息
+	@RequestMapping(value = "/getPageVo")
+	@ResponseBody
+	public PageExamVO findPage(Long examId, Long caseId) {
+		return extraService.findPageAndExam(examId,caseId);
+	}
 	
 	//使用worker_id获取测试报告
 	@RequestMapping(value = "/findByWorker")
@@ -421,28 +430,6 @@ public class ExtraController {
 			e.printStackTrace();
 		}
 	}
-	
-	//获取页面json
-	@RequestMapping(value = "/getPageJson")
-	@ResponseBody
-	public void getPageJson(String caseId, HttpServletResponse response) {
-		try {
-			PrintWriter out = response.getWriter();
-			JSONObject result = new JSONObject();
-			Exam exam = extraService.getExam(caseId);
-			if(exam != null) { 
-				result.put("status", 200);
-				result.put("result", exam.getJson());
-			}
-			else { result.put("status", 500); }
-			out.print(result);
-			out.flush();
-			out.close();
-		} catch (IOException e) {
-			// TODO Auto-generated catch block
-			e.printStackTrace();
-		}
-	}
 
 
 	@RequestMapping(value = "/updateTask", method = RequestMethod.POST)
@@ -464,6 +451,7 @@ public class ExtraController {
 		}
 	}
 
+	//
 	@RequestMapping(value = "/getTask")
 	@ResponseBody
 	public void getTask(String id, HttpServletResponse response) {

+ 45 - 1
src/main/java/edu/nju/controller/HistoryController.java

@@ -5,12 +5,15 @@ import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
 
 import edu.nju.entities.Bug;
 import edu.nju.entities.BugHistory;
+import edu.nju.service.ReportService;
+import edu.nju.util.TimeUtil;
 import org.json.JSONArray;
 import org.json.JSONObject;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -34,6 +37,9 @@ public class HistoryController {
 	
 	@Autowired
 	RecommendService recservice;
+
+	@Autowired
+	ReportService reportService;
 	
 	//获取指定节点的历史信息
 	@RequestMapping(value = "/getHistory")
@@ -148,7 +154,7 @@ public class HistoryController {
 			//三级页面筛选,单个节点筛选(没有parent,也没有children)
 			for(String id : hisservice.getBugIdListByPage(case_take_id,page,start,count)) {
 				BugHistory bugHistory=hisservice.getHistory(id);
-				if(bugHistory.getChildren().size() == 0&&bugHistory.getParent().equals("null")) {all.add(id);}
+				if(bugHistory==null || bugHistory.getChildren().size() == 0&&bugHistory.getParent().equals("null")) {all.add(id);}
 			}
 			//根据三级页面筛选
 			//分页
@@ -179,6 +185,44 @@ public class HistoryController {
 		}
 	}
 
+	//获取所有单个节点的数据
+	@RequestMapping(value = "/getAll")
+	@ResponseBody
+	public void getAll(String case_take_id, String start, String count, String page, HttpSession session, HttpServletResponse response) {
+		try {
+			PrintWriter out = response.getWriter();
+			JSONObject result = new JSONObject();
+			List<String> all = hisservice.getBugIdListByPage(case_take_id,page,start,count).stream().collect(Collectors.toList());
+			//分页
+			List<String> ids = all.subList(Integer.parseInt(start), Math.min(all.size(), Integer.parseInt(start) + Integer.parseInt(count)));
+
+			List<String> invalid = hisservice.getInvalid(ids);
+			for(String id: invalid) {
+				if(ids.contains(id)) {ids.remove(id);}
+			}
+			List<List<String>> list = new ArrayList<List<String>>();
+			for(String id : ids) {
+				List<String> temp = new ArrayList<String>();
+				temp.add(id);
+				int score = aservice.getGrade(id);
+				if(score != -1) {temp.add("true");}
+				else {temp.add("false");}
+				Bug bug = reportService.findBugById(id);
+				temp.add(bug.getTitle());
+				temp.add(TimeUtil.timeStamp2Date(bug.getCreate_time_millis()));
+				list.add(temp);
+			}
+			result.put("Count", all.size());
+			result.put("TreeRoot", new JSONArray(list));
+			out.print(result);
+			out.flush();
+			out.close();
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+
 	//学生获取所有单个节点的数据
 	@RequestMapping(value = "/getSingleStu")
 	@ResponseBody

+ 16 - 0
src/main/java/edu/nju/controller/NodeController.java

@@ -101,6 +101,22 @@ public class NodeController {
         }
     }
 
+    @RequestMapping(value = "/uploadSingleCatchNodes")
+    @ResponseBody
+    public void uploadSingleCatchNodes(String jobId,HttpServletResponse response){
+        JSONObject result;
+        try {
+            PrintWriter out = response.getWriter();
+            result=nodeService.uploadSingleCatchNodesToMoocTest(jobId);
+            out.print(result);
+            out.flush();
+            out.close();
+        }catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+    }
+
 
 
 

+ 7 - 1
src/main/java/edu/nju/controller/OAuthController.java

@@ -4,6 +4,7 @@ import edu.nju.controller.data.UserInfo;
 import edu.nju.controller.interceptor.AuthRequired;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -31,6 +32,11 @@ public class OAuthController {
     @Autowired
     private RestTemplate restTemplate;
 
+    @Value("${server.host}")
+    private String serverHost;
+    @Value("${report.port}")
+    private String serverPort;
+
     @RequestMapping(value = "/auth", method = RequestMethod.GET)
     public void auth(@RequestParam("task_id") Long taskId,
                      @RequestParam("case_id") Long caseId,
@@ -52,7 +58,7 @@ public class OAuthController {
         session.setAttribute("caseId", caseId);
         session.setAttribute("taskId", taskId);
         try {
-            response.sendRedirect("http://47.99.140.117:9001/report/detail/"+taskId+"/"+caseId+"/"+userInfoResponse.getBody().getId());
+            response.sendRedirect("http://"+serverHost+":"+serverPort+"/report/detail/"+taskId+"/"+caseId+"/"+userInfoResponse.getBody().getId());
         } catch (IOException e) {
             e.printStackTrace();
         }

+ 36 - 5
src/main/java/edu/nju/controller/ReviewAnalyzeController.java

@@ -1,12 +1,11 @@
 package edu.nju.controller;
 
+import edu.nju.entities.ReviewJob;
 import edu.nju.service.ReviewAnalyzeService;
 import org.json.JSONObject;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.CrossOrigin;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
@@ -35,11 +34,43 @@ public class ReviewAnalyzeController {
     }
 
     //获取众审任务的结果excel
-    @RequestMapping(value = "/getJobExcel")
+    @RequestMapping(value = "/job/excel" , method = RequestMethod.GET)
     @ResponseBody
     public String getExcel (String jobId){
         String res = reviewAnalyzeService.getExcel(jobId);
-        return res==null?"errpr":res;
+        return res==null?"err0r":res;
     }
 
+    @RequestMapping(value = "/job/json", method = RequestMethod.GET)
+    @ResponseBody
+    public void getJson ( @RequestParam("id") String jobId , HttpServletResponse response){
+        try {
+            PrintWriter out = response.getWriter();
+            JSONObject job = reviewAnalyzeService.getJsonExport(jobId);
+            out.print(job);
+            out.flush();
+            out.close();
+        }catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+    }
+
+//    @RequestMapping(value = "/job/json", method = RequestMethod.GET)
+//    @ResponseBody
+//    public JSONObject getJson ( @RequestParam("id") String jobId , HttpServletResponse response){
+//        JSONObject job = reviewAnalyzeService.getJsonExport(jobId);
+//        return job;
+//    }
+
+    @RequestMapping(value = "/job/crowdReviewGradeToCrowdTest", method = RequestMethod.GET)
+    @ResponseBody
+    public String crowdReviewGradeToCrowdTest (String jobId , HttpServletResponse response){
+        JSONObject result = reviewAnalyzeService.crowdReviewGradeToCrowdTest(jobId);
+        return result.toString();
+    }
+
+
+
+
 }

+ 19 - 0
src/main/java/edu/nju/controller/ReviewPaperController.java

@@ -6,6 +6,7 @@ import edu.nju.entities.ReviewReport;
 import edu.nju.entities.ReviewWorker;
 import edu.nju.model.CrowdReviewReportDTO;
 import edu.nju.model.CrowdReviewReportVO;
+import edu.nju.service.ReviewAnalyzeService;
 import edu.nju.service.ReviewPaperService;
 import org.json.JSONArray;
 import org.json.JSONObject;
@@ -27,6 +28,9 @@ public class ReviewPaperController {
     @Autowired
     ReviewPaperService reviewPaperService;
 
+    @Autowired
+    ReviewAnalyzeService analyzeService;
+
     @RequestMapping(value = "/uploadReport", method = RequestMethod.POST)
     @ResponseBody
     public  CrowdReviewReportVO uploadReport(@RequestBody CrowdReviewReportDTO crowdReviewReportDTO){
@@ -151,5 +155,20 @@ public class ReviewPaperController {
         return url;
     }
 
+    @RequestMapping(value = "/answer", method = RequestMethod.GET)
+    @ResponseBody
+    public void getPaperAnswerJson (@RequestParam("paperId") String peperId, HttpServletResponse response ){
+        try {
+            PrintWriter out = response.getWriter();
+            JSONArray paperJson = analyzeService.getJsonExportByPaper(peperId);
+            out.print(paperJson);
+            out.flush();
+            out.close();
+        }catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+    }
+
 
 }

+ 5 - 0
src/main/java/edu/nju/controller/UploadController.java

@@ -5,6 +5,7 @@ import java.io.PrintWriter;
 
 import javax.servlet.http.HttpServletResponse;
 
+import edu.nju.util.BlockChainAspect;
 import org.json.JSONObject;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
@@ -26,6 +27,9 @@ public class UploadController {
 	
 	@Autowired
 	CTBService ctbservice;
+
+	@Autowired
+	BlockChainAspect blockChainAspect;
 	
 	//上传新的Bug报告
 	@RequestMapping(value = "/submit", method = RequestMethod.POST)
@@ -36,6 +40,7 @@ public class UploadController {
 		String id = saveservice.save(case_take_id, bug_category, description, img_url, severity, recurrent, title, report_id, parent, page, useCase, case_id);
 //		System.out.println(useCase);
 		if(!useCase.equals("null") && !id.equals("")) {flag = ctbservice.save(useCase, id, case_take_id, report_id);}
+//		boolean uploadBlockResult=blockChainAspect.uploadTestReportInfoToBlockChain(id);
 		if(flag && !id.equals("")) {
 			result.put("status", "200");
 			result.put("id", id);

+ 8 - 0
src/main/java/edu/nju/dao/BugHistoryDao.java

@@ -44,6 +44,14 @@ public class BugHistoryDao {
 		}
 		return ids;
 	}
+
+	//查找所有指定节点
+	public List<BugHistory> findBugHistoryList(List<String> lists) {
+		Query query = new Query();
+		query.addCriteria(Criteria.where("_id").in(lists));
+		List<BugHistory> bugHistories = mongoOps.find(query,BugHistory.class);
+		return bugHistories;
+	}
 	
 	//查找所有的BugRoot
 	public List<String> findRoots() {

+ 2 - 1
src/main/java/edu/nju/dao/CTBDao.java

@@ -49,7 +49,8 @@ public class CTBDao {
 //		System.out.println("3"+id);
 		return mongoOperations.find(query, CaseToBug.class).get(0);
 	}
-	
+
+	//根据testCaseId获取bugIdList
 	public List<String> findById(String id) {
 //		System.out.println("3"+id);
 		Query query = new Query();

+ 3 - 1
src/main/java/edu/nju/dao/CaseToBugDao.java

@@ -31,4 +31,6 @@ public class CaseToBugDao {
             return caseToBugList.get(0);
         }
     }
-}
+
+}
+

+ 36 - 0
src/main/java/edu/nju/dao/CrowdTestDao.java

@@ -0,0 +1,36 @@
+package edu.nju.dao;
+
+import edu.nju.entities.CaseToBug;
+import edu.nju.entities.CrowdTest;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.stereotype.Repository;
+import java.util.List;
+
+/**
+ * @Author JiaWei Xu
+ * @Date 2021-01-06 16:43
+ * @Email xjwhhh233@outlook.com
+ */
+@Repository
+public class CrowdTestDao {
+    @Autowired
+    private MongoOperations mongoOperations;
+
+    public void save(CrowdTest crowdTest) {
+        mongoOperations.save(crowdTest);
+    }
+
+    public CrowdTest findByCaseTakeId(String caseTakeId){
+        Query query = new Query();
+        query.addCriteria(Criteria.where("case_take_id").is(caseTakeId));
+        List<CrowdTest> crowdTestList= mongoOperations.find(query, CrowdTest.class);
+        if(crowdTestList.size()==0){
+            return null;
+        }else{
+            return crowdTestList.get(0);
+        }
+    }
+}

+ 5 - 1
src/main/java/edu/nju/dao/ReportDao.java

@@ -66,5 +66,9 @@ public class ReportDao {
 		query.addCriteria(Criteria.where("task_id").is(task_id));
 		return mongoOperations.find(query, Report.class);
 	}
-	
+	public List<Report> findReportsByWorker(String worker_id) {
+		Query query = new Query();
+		query.addCriteria(Criteria.where("worker_id").is(worker_id));
+		return mongoOperations.find(query, Report.class);
+	}
 }

+ 1 - 1
src/main/java/edu/nju/dao/ReviewGroupDao.java

@@ -33,7 +33,7 @@ public class ReviewGroupDao {
     public void removeByJob(String jobId){
         Query query = new Query();
         query.addCriteria(Criteria.where("job_id").is(jobId));
-        mongoOperations.remove(query,ReviewJob.class);
+        mongoOperations.remove(query,ReviewGroup.class);
     }
 
     public ReviewGroup getGroupByReports(List<String>reportIds){

+ 44 - 0
src/main/java/edu/nju/dao/ShortTokenDao.java

@@ -0,0 +1,44 @@
+package edu.nju.dao;
+
+import edu.nju.entities.ShortToken;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * @Author JiaWei Xu
+ * @Date 2020-12-03 16:35
+ * @Email xjwhhh233@outlook.com
+ */
+@Repository
+public class ShortTokenDao {
+    @Autowired
+    private MongoOperations mongoOperations;
+
+    public String save(ShortToken shortToken) {
+        mongoOperations.save(shortToken);
+        return shortToken.getId();
+    }
+
+    public ShortToken findByTokenString(String token){
+        Query query = new Query();
+        query.addCriteria(Criteria.where("token").is(token));
+        List<ShortToken> list = mongoOperations.find(query,ShortToken.class);
+        if(list.size() == 0)  {return null;}
+        return list.get(0);
+    }
+
+    public ShortToken findByDetailInfo(String examId,String caseId,String userId){
+        Query query = new Query();
+        query.addCriteria(Criteria.where("examId").is(examId).and("caseId").is(caseId).and("userId").is(userId));
+        List<ShortToken> list = mongoOperations.find(query,ShortToken.class);
+        if(list.size() == 0)  {return null;}
+        return list.get(0);
+    }
+
+
+}

+ 8 - 0
src/main/java/edu/nju/dao/StuInfoDao.java

@@ -35,4 +35,12 @@ public class StuInfoDao {
 		if(stu_info == null || stu_info.size() == 0) { return "null"; }
 		else { return stu_info.get(0).getWorker_id(); }
 	}
+
+	public String findWorkerName(String report_id) {
+		Query query = new Query();
+		query.addCriteria(Criteria.where("_id").is(report_id));
+		List<StuInfo> stu_info = mongoOperations.find(query, StuInfo.class);
+		if(stu_info == null || stu_info.size() == 0) { return "null"; }
+		else { return stu_info.get(0).getName(); }
+	}
 }

+ 21 - 1
src/main/java/edu/nju/dao/TaskDao.java

@@ -1,6 +1,8 @@
 package edu.nju.dao;
 
 import edu.nju.entities.Task;
+import edu.nju.util.HTTP;
+import org.json.JSONObject;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.mongodb.core.MongoOperations;
 import org.springframework.data.mongodb.core.query.Criteria;
@@ -24,8 +26,26 @@ public class TaskDao {
         Query query = new Query();
         query.addCriteria(Criteria.where("_id").is(id));
         List<Task> tasks = mongoOperations.find(query, Task.class);
-        if(tasks == null || tasks.size() == 0) { return null; }
+        if(tasks.size() == 0) {
+            return getAndSaveTaskInfo(id);
+        }
         else { return tasks.get(0); }
     }
 
+    private Task getAndSaveTaskInfo(String id){
+        String result = HTTP.sendGet("http://www.mooctest.net/api/exam/" + id + "/info", "");
+        if (!"".equals(result)) {
+            JSONObject json = new JSONObject(result);
+            long beginTime = json.getLong("beginTime");
+            long endTime = json.getLong("endTime");
+            String name=json.getString("name");
+            double totalMins = (endTime - beginTime) / 1000 / 60.0;
+            Task newTask = new Task(id, name,beginTime, endTime, totalMins, totalMins);
+            save(newTask);
+            return newTask;
+        }else{
+            return null;
+        }
+    }
+
 }

+ 10 - 4
src/main/java/edu/nju/dao/TestCaseDao.java

@@ -23,7 +23,7 @@ public class TestCaseDao {
 	
 	public TestCase findById(String id) {
 		Query query = new Query();
-		query.addCriteria(Criteria.where("id").is(id));
+		query.addCriteria(Criteria.where("_id").is(id));
 		List<TestCase> list = mongoOperations.find(query, TestCase.class);
 		if(list == null || list.size() == 0) { return null; }
 		else { return list.get(0); }
@@ -33,13 +33,19 @@ public class TestCaseDao {
 		Query query = new Query();
 		query.addCriteria(Criteria.where("report_id").is(report_id));
 		List<TestCase> list = mongoOperations.find(query, TestCase.class);
-		if(list == null || list.size() == 0) { return null; }
-		else { return list; }
+		return list;
+	}
+
+	public List<TestCase> findByReports(List<String>report_ids) {
+		Query query = new Query();
+		query.addCriteria(Criteria.where("report_id").in(report_ids));
+		List<TestCase> list = mongoOperations.find(query, TestCase.class);
+		return list;
 	}
 	
 	public void updateTestCase(String id, String report_id, String name, String front, String behind, String description) {
 		Query query = new Query();
-		query.addCriteria(Criteria.where("id").is(id));
+		query.addCriteria(Criteria.where("_id").is(id));
 		List<TestCase> list = mongoOperations.find(query, TestCase.class);
 		if(list != null && list.size() != 0) {
 			TestCase testCase = list.get(0);

+ 7 - 0
src/main/java/edu/nju/dao/ThumsUpDao.java

@@ -88,4 +88,11 @@ public class ThumsUpDao {
 			mongoOperations.updateFirst(query, update, ThumsUp.class);
 		}
 	}
+
+	public List<ThumsUp> findByReports(List<String>report_ids) {
+		Query query = new Query();
+		query.addCriteria(Criteria.where("_id").in(report_ids));
+		List<ThumsUp> list = mongoOperations.find(query, ThumsUp.class);
+		return list;
+	}
 }

+ 40 - 0
src/main/java/edu/nju/dao/UserLabelDao.java

@@ -0,0 +1,40 @@
+package edu.nju.dao;
+
+import edu.nju.entities.ReviewItem;
+import edu.nju.entities.UserLabel;
+import org.apache.catalina.User;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+import java.util.Queue;
+
+@Repository
+public class UserLabelDao {
+
+    @Autowired
+    private MongoOperations mongoOperations;
+
+    public String saveItem(UserLabel item){
+        mongoOperations.save(item);
+        return item.getId();
+    }
+
+//    public List<ReviewItem>findItemsByJob(String job_id){
+//        Query query = new Query();
+//        query.addCriteria(Criteria.where("job_id").is(job_id));
+//        return mongoOperations.find(query, ReviewItem.class);
+//    }
+
+    public List<UserLabel> findLabelsByWorkerId(String workerId){
+        Query query = new Query();
+        query.addCriteria(Criteria.where("workerId").is(workerId));
+        List<UserLabel> labels = mongoOperations.find(query,UserLabel.class);
+        return  labels;
+    }
+
+
+}

+ 1 - 2
src/main/java/edu/nju/entities/Bug.java

@@ -6,8 +6,7 @@ import org.springframework.data.mongodb.core.index.Indexed;
 import org.springframework.data.mongodb.core.mapping.Document;
 
 @Document
-public class
-Bug implements java.io.Serializable{
+public class Bug implements java.io.Serializable{
 	/**
 	 * 
 	 */

+ 78 - 0
src/main/java/edu/nju/entities/CrowdTest.java

@@ -0,0 +1,78 @@
+package edu.nju.entities;
+
+import org.springframework.data.annotation.Id;
+import org.springframework.data.annotation.PersistenceConstructor;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+/**
+ * @Author JiaWei Xu
+ * @Date 2021-01-06 15:43
+ * @Email xjwhhh233@outlook.com
+ */
+@Document
+public class CrowdTest {
+
+    private static final long serialVersionUID = 7484726588592610736L;
+
+    @Id
+    private String id;
+
+    private String caseId;
+
+    private String taskId;
+
+    private String caseTakeId;
+
+    private Double progress;
+
+    public CrowdTest(){};
+
+    @PersistenceConstructor
+    public CrowdTest(String id, String caseId, String taskId, String caseTakeId, Double progress) {
+        this.id = id;
+        this.caseId = caseId;
+        this.taskId = taskId;
+        this.caseTakeId = caseTakeId;
+        this.progress = progress;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getCaseId() {
+        return caseId;
+    }
+
+    public void setCaseId(String caseId) {
+        this.caseId = caseId;
+    }
+
+    public String getTaskId() {
+        return taskId;
+    }
+
+    public void setTaskId(String taskId) {
+        this.taskId = taskId;
+    }
+
+    public String getCaseTakeId() {
+        return caseTakeId;
+    }
+
+    public void setCaseTakeId(String caseTakeId) {
+        this.caseTakeId = caseTakeId;
+    }
+
+    public Double getProgress() {
+        return progress;
+    }
+
+    public void setProgress(Double progress) {
+        this.progress = progress;
+    }
+}

+ 1 - 1
src/main/java/edu/nju/entities/ReviewPaper.java

@@ -35,7 +35,7 @@ public class ReviewPaper implements java.io.Serializable{
         this.requirement_location = requirement_location;
     }
 
-    @PersistenceConstructor
+
     public ReviewPaper(ReviewPaperVO reviewPaperVO) {
         this.description = reviewPaperVO.getDescription();
         this.name = reviewPaperVO.getName();

+ 110 - 0
src/main/java/edu/nju/entities/ShortToken.java

@@ -0,0 +1,110 @@
+package edu.nju.entities;
+
+import org.springframework.data.annotation.Id;
+import org.springframework.data.annotation.PersistenceConstructor;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import java.io.Serializable;
+
+/**
+ * @Author JiaWei Xu
+ * @Date 2020-12-03 15:11
+ * @Email xjwhhh233@outlook.com
+ */
+@Document
+public class ShortToken implements Serializable {
+
+    private static final long serialVersionUID = 8980368107739914394L;
+
+    @Id
+    private String id;
+
+    private String token;
+
+    private String beginTime;
+
+    private String endTime;
+
+    private String caseId;
+
+    private String examId;
+
+    private String userId;
+
+    private boolean disabled;
+
+    @PersistenceConstructor
+    public ShortToken(String token, String beginTime, String endTime, String caseId, String examId, String userId,boolean disabled) {
+        this.token = token;
+        this.beginTime = beginTime;
+        this.endTime = endTime;
+        this.caseId = caseId;
+        this.examId = examId;
+        this.userId = userId;
+        this.disabled=disabled;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getToken() {
+        return token;
+    }
+
+    public void setToken(String token) {
+        this.token = token;
+    }
+
+    public String getBeginTime() {
+        return beginTime;
+    }
+
+    public void setBeginTime(String beginTime) {
+        this.beginTime = beginTime;
+    }
+
+    public String getEndTime() {
+        return endTime;
+    }
+
+    public void setEndTime(String endTime) {
+        this.endTime = endTime;
+    }
+
+    public String getCaseId() {
+        return caseId;
+    }
+
+    public void setCaseId(String caseId) {
+        this.caseId = caseId;
+    }
+
+    public String getExamId() {
+        return examId;
+    }
+
+    public void setExamId(String examId) {
+        this.examId = examId;
+    }
+
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    public boolean isDisabled() {
+        return disabled;
+    }
+
+    public void setDisabled(boolean disabled) {
+        this.disabled = disabled;
+    }
+}

+ 27 - 0
src/main/java/edu/nju/entities/UserLabel.java

@@ -0,0 +1,27 @@
+package edu.nju.entities;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.data.annotation.Id;
+
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class UserLabel implements java.io.Serializable{
+
+    private static final long serialVersionUID = -4445308752903947027L;
+
+    @Id
+    private String id;
+
+    private String workerId;
+
+    private String label;
+
+    private String type; // 用来表示用 标签的类型
+
+
+}

+ 33 - 0
src/main/java/edu/nju/model/AnalysePeopleVO.java

@@ -0,0 +1,33 @@
+package edu.nju.model;
+
+import com.google.gson.JsonArray;
+import edu.nju.entities.Bug;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import java.util.List;
+
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+@Data
+public class AnalysePeopleVO {
+    JSONArray timeLine ;
+    JSONObject userRadar;
+    String taskName;
+    String name;
+    String school;
+    String photoUrl;
+    String province;
+    String city;
+    long registerTime;
+    long crowdTime;
+    List<Bug> bugList ; //= extraService.getBugList(report_id, case_take_id);
+    long firstActivate ;
+    long lastActivate ;
+    List<String> labels ; // 用户标签
+}

+ 69 - 0
src/main/java/edu/nju/model/AnalyseVO2.java

@@ -0,0 +1,69 @@
+package edu.nju.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.json.JSONArray;
+
+import java.util.List;
+import java.util.Map;
+
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class AnalyseVO2 {
+
+    private int likeNum;
+
+    private int dislikeNum;
+
+    private int forkNum;
+
+    private int reportNum;
+
+    private int testcaseNum;
+
+    private int bugNum;
+
+    private long startTime;
+
+    private long endTime;
+
+    private int workerNum;
+
+    private String taskName;
+
+    private JSONArray workerDistribute;
+
+    private List<WorkerVO> workerRank;
+
+    private Map<Integer,Integer> gradeDistrubute;
+
+    private double pageCover;
+
+    private String managerCheck ;
+
+    public AnalyseVO2(int likeNum, int dislikeNum, int forkNum, int reportNum, int testcaseNum, int bugNum, long startTime, long endTime, int workerNum, String taskName, JSONArray workerDistribute, List<WorkerVO> workerRank, Map<Integer, Integer> gradeDistrubute,double pageCover) {
+
+        this.likeNum = likeNum;
+        this.dislikeNum = dislikeNum;
+        this.forkNum = forkNum;
+        this.reportNum = reportNum;
+        this.testcaseNum = testcaseNum;
+        this.bugNum = bugNum;
+        this.startTime = startTime;
+        this.endTime = endTime;
+        this.workerNum = workerNum;
+        this.taskName = taskName;
+        this.workerDistribute = workerDistribute;
+        this.workerRank = workerRank;
+        this.gradeDistrubute = gradeDistrubute;
+        this.pageCover = pageCover;
+    }
+
+
+
+}

+ 1 - 1
src/main/java/edu/nju/model/BugRecurrent.java

@@ -1,7 +1,7 @@
 package edu.nju.model;
 
 public enum BugRecurrent {
-    其他(0),无规律复现(1),小概率复现(2),大概率复现(3),必现(4);
+    未知(0),其他(1),无规律复现(2),小概率复现(3),大概率复现(4),必现(5);
     private int id;
 
     BugRecurrent(int id) {

+ 1 - 5
src/main/java/edu/nju/model/BugSeverity.java

@@ -1,7 +1,7 @@
 package edu.nju.model;
 
 public enum BugSeverity {
-    待定(0),较轻(1),一般(2),严重(3),紧急(4);
+    其他(0),待定(1),较轻(2),一般(3),严重(4),紧急(5);
 
     private int id;
 
@@ -22,8 +22,4 @@ public enum BugSeverity {
         return null;
     }
 
-    public static void main(String[] args) {
-        BugSeverity bugSeveritsy=BugSeverity.getValue(2);
-        System.out.println(bugSeveritsy.toString());
-    }
 }

+ 75 - 0
src/main/java/edu/nju/model/ExamVO.java

@@ -0,0 +1,75 @@
+package edu.nju.model;
+
+import java.util.Date;
+
+public class ExamVO {
+    private Long id;
+
+    private Long caseId;
+
+    private int state;
+
+    private int caseTypeId;
+
+    private Date beginTime;
+
+    private Date endTime;
+
+    public ExamVO(Long id,Long caseId, int state, int caseTypeId, Date beginTime, Date endTime) {
+        this.id = id;
+        this.caseId=caseId;
+        this.state = state;
+        this.caseTypeId = caseTypeId;
+        this.beginTime = beginTime;
+        this.endTime = endTime;
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Long getCaseId() {
+        return caseId;
+    }
+
+    public void setCaseId(Long caseId) {
+        this.caseId = caseId;
+    }
+
+    public int getState() {
+        return state;
+    }
+
+    public void setState(int state) {
+        this.state = state;
+    }
+
+    public int getCaseTypeId() {
+        return caseTypeId;
+    }
+
+    public void setCaseTypeId(int caseTypeId) {
+        this.caseTypeId = caseTypeId;
+    }
+
+    public Date getBeginTime() {
+        return beginTime;
+    }
+
+    public void setBeginTime(Date beginTime) {
+        this.beginTime = beginTime;
+    }
+
+    public Date getEndTime() {
+        return endTime;
+    }
+
+    public void setEndTime(Date endTime) {
+        this.endTime = endTime;
+    }
+}
+

+ 64 - 0
src/main/java/edu/nju/model/HistoricalDataVO.java

@@ -0,0 +1,64 @@
+package edu.nju.model;
+
+
+import java.util.List;
+
+public class HistoricalDataVO {
+    private int reportNum;
+
+    private List<Double>scoreList;  //各个报告的得分
+
+    private Double totalScore;   //报告总分
+
+    private int participateNum;   //参加的和本次考试类型有关的众包测试次数
+
+    private int totalParticipateNum;  //参加众包考试次数
+
+    public HistoricalDataVO(int reportNum, List<Double> scoreList, Double totalScore, int participateNum, int totalParticipateNum) {
+        this.reportNum = reportNum;
+        this.scoreList = scoreList;
+        this.totalScore = totalScore;
+        this.participateNum = participateNum;
+        this.totalParticipateNum = totalParticipateNum;
+    }
+
+    public int getReportNum() {
+        return reportNum;
+    }
+
+    public void setReportNum(int reportNum) {
+        this.reportNum = reportNum;
+    }
+
+    public List<Double> getScoreList() {
+        return scoreList;
+    }
+
+    public void setScoreList(List<Double> scoreList) {
+        this.scoreList = scoreList;
+    }
+
+    public Double getTotalScore() {
+        return totalScore;
+    }
+
+    public void setTotalScore(Double totalScore) {
+        this.totalScore = totalScore;
+    }
+
+    public int getParticipateNum() {
+        return participateNum;
+    }
+
+    public void setParticipateNum(int participateNum) {
+        this.participateNum = participateNum;
+    }
+
+    public int getTotalParticipateNum() {
+        return totalParticipateNum;
+    }
+
+    public void setTotalParticipateNum(int totalParticipateNum) {
+        this.totalParticipateNum = totalParticipateNum;
+    }
+}

+ 59 - 0
src/main/java/edu/nju/model/PageExamVO.java

@@ -0,0 +1,59 @@
+package edu.nju.model;
+
+public class PageExamVO {
+
+    private Long examId;
+
+    private Long caseId;
+
+    private ExamVO examVO;
+
+    private int caseTypeId;   //web:0 app:1
+
+    private String pageContent;
+
+    public PageExamVO(Long examId,Long caseId) {
+        this.examId = examId;
+        this.caseId = caseId;
+    }
+
+    public Long getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Long id) {
+        this.examId = id;
+    }
+
+    public Long getCaseId() {
+        return caseId;
+    }
+
+    public void setCaseId(Long caseId) {
+        this.caseId = caseId;
+    }
+
+    public ExamVO getExamVO() {
+        return examVO;
+    }
+
+    public void setExamVO(ExamVO examVO) {
+        this.examVO = examVO;
+    }
+
+    public int getCaseTypeId() {
+        return caseTypeId;
+    }
+
+    public void setCaseTypeId(int caseTypeId) {
+        this.caseTypeId = caseTypeId;
+    }
+
+    public String getPageContent() {
+        return pageContent;
+    }
+
+    public void setPageContent(String pageContent) {
+        this.pageContent = pageContent;
+    }
+}

+ 5 - 0
src/main/java/edu/nju/model/WebBrand.java

@@ -0,0 +1,5 @@
+package edu.nju.model;
+
+public enum WebBrand {
+    windows,linux,macos
+}

+ 4 - 4
src/main/java/edu/nju/model/WorkerVO.java

@@ -7,12 +7,12 @@ public class WorkerVO {
 
     private String school;
 
-    private int grade;
+    private double grade;
 
     public WorkerVO() {
     }
 
-    public WorkerVO(String id, String name, String school,int grade) {
+    public WorkerVO(String id, String name, String school,double grade) {
         this.id = id;
         this.name = name;
         this.school = school;
@@ -43,11 +43,11 @@ public class WorkerVO {
         this.school = school;
     }
 
-    public int getGrade() {
+    public double getGrade() {
         return grade;
     }
 
-    public void setGrade(int grade) {
+    public void setGrade(double grade) {
         this.grade = grade;
     }
 }

+ 696 - 86
src/main/java/edu/nju/service/AnalyzeService.java

@@ -1,18 +1,34 @@
 package edu.nju.service;
 
+import java.nio.charset.StandardCharsets;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
 import java.util.*;
+import java.util.stream.Collectors;
 
+import edu.nju.algorithm.progress.BugForProgress;
+import edu.nju.algorithm.progress.TaskClosePrediction;
 import edu.nju.dao.*;
 import edu.nju.entities.*;
-import edu.nju.model.AnalyseVO;
-import edu.nju.model.BugDataVO;
-import edu.nju.model.BugSeverity;
-import edu.nju.model.WorkerVO;
+import edu.nju.model.*;
+import edu.nju.util.DataMaskingUtil;
 import edu.nju.util.HTTP;
+import edu.nju.util.TimeUtil;
+import edu.nju.util.TransUtil;
+import org.apache.commons.lang3.EnumUtils;
 import org.json.JSONArray;
 import org.json.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.converter.StringHttpMessageConverter;
 import org.springframework.stereotype.Service;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.client.RestTemplate;
 
 @Service
 public class AnalyzeService {
@@ -52,6 +68,43 @@ public class AnalyzeService {
 
 	@Autowired
 	TestCaseDao testCaseDao;
+
+	@Autowired
+	ThumsUpDao thumsUpDao;
+
+	@Autowired
+	BugHistoryDao bugHistoryDao;
+
+	@Autowired
+	UserLabelDao userLabelDao;
+
+	@Autowired
+	ExtraService extraService;
+
+	@Autowired
+	ShortTokenDao shortTokenDao;
+
+	@Autowired
+	ExamDao examDao;
+
+	@Autowired
+	CrowdTestDao crowdTestDao;
+
+	@Value("${server.host}")
+	private String serverHost;
+	@Value("${report.port}")
+	private String serverPort;
+
+	private static String[] radarInfo = {"发现bug能力","描述bug能力","经验值","bug有效率","众测平均得分"};
+	private static int[] radarValueStart = {70,80,60,50,70};
+	private static List<String> mockLabels = Arrays.asList("移动应用","Android","ios","鸿蒙os","华为","MacOS","Windows10",
+					"小米","Web测试","发现bug能力强","页面覆盖率高","互动性强",
+					"社交类app","江苏省南京市");
+
+
+
+
+	Logger logger= LoggerFactory.getLogger(RecommendService.class);
 	
 	//获取所有bug
 	public List<String> getValid(String case_take_id) {
@@ -101,7 +154,7 @@ public class AnalyzeService {
 				Bug bug=bugMap.get(bugMirror.getId());
 				BugHistory bugHistory=hdao.findByid(bugMirror.getId());
 				if(bug!=null&&bugHistory!=null){
-					BugSeverity bugSeveritsy=BugSeverity.getValue(2);
+					BugSeverity bugSeveritsy=BugSeverity.getValue(bug.getSeverity());
 					String bugSeverity=bugSeveritsy.toString();
 					BugScore bugScore=bsdao.findById(bug.getId());
 					int score=bugScore==null?0:bugScore.getGrade();
@@ -129,7 +182,7 @@ public class AnalyzeService {
 		List<Report> reports = reportDao.findByExamId(examId);
 		for(Report report : reports) {
 			if(report!=null) {
-				String workerId=findWorkerId(report.getId());
+				String workerId=report.getWorker_id();
 				if(!workerId.equals("")&&!result.contains(workerId))
 					result.add(Long.parseLong(workerId));
 			}
@@ -215,83 +268,122 @@ public class AnalyzeService {
 
 	//todo 搞清楚究竟是通过哪种方式写回主站分数
 	public JSONArray getScores(String case_take_id) {
-		Map<String, Integer> reviewScore = new HashMap<String, Integer>(); //评审他人bug得分
-		Map<String, Integer> bugScore = new HashMap<String, Integer>(); //系统或专家评审你的bug得分
-		Map<String, Integer> finalScores = new HashMap<String, Integer>(); //计算bug得分
-		JSONArray json = new JSONArray();
-
-		//获取所有bugID
-		List<String> bugIdList = getValid(case_take_id);
-		//获取bug本身得分
-		for(String bugId: bugIdList) {
-			BugScore temp = bsdao.findById(bugId);
-			if(temp != null) {bugScore.put(bugId, temp.getGrade());}
-			else {bugScore.put(bugId, 0);}
-		}
-
-		//计算树状bug得分
-		countScore(case_take_id, finalScores, bugScore);
+//		Map<String, Integer> reviewScore = new HashMap<String, Integer>(); //评审他人bug得分
+//		Map<String, Integer> bugScore = new HashMap<String, Integer>(); //系统或专家评审你的bug得分
+//		Map<String, Integer> finalScores = new HashMap<String, Integer>(); //计算bug得分
+//		JSONArray json = new JSONArray();
+//
+//		//获取所有bugID
+//		List<String> bugIdList = getValid(case_take_id);
+//		logger.info(String.valueOf(bugIdList.size()));
+//		//获取bug本身得分
+//		for(String bugId: bugIdList) {
+//			BugScore temp = bsdao.findById(bugId);
+//			if(temp != null) {bugScore.put(bugId, temp.getGrade());}
+//			else {bugScore.put(bugId, 0);}
+//		}
+//
+//		//计算树状bug得分
+//		countScore(case_take_id, finalScores, bugScore);
+//
+//		//计算审查得分
+//		for(String bug: bugIdList) {
+//			BugMirror mirror = mdao.findById(bug);
+//			if(mirror == null) { continue; }
+//			int grade = bugScore.getOrDefault(bug, 0);
+//			int thumbsScore=0;
+//			if(grade>=0&&grade<3){
+//				thumbsScore=-2;
+//			}else if(grade<5){
+//				thumbsScore=-1;
+//			}else if(grade<8){
+//				thumbsScore=1;
+//			}else{
+//				thumbsScore=2;
+//			}
+//			//点赞点踩积分减分
+//			ThumsUp(thumbsScore,reviewScore,mirror);
+//		}
+//		int maxReviewScore=0;
+//		int maxReportScore=0;
+//		for(Map.Entry<String, Integer> entry : reviewScore.entrySet()) {
+//			//审查得分低于零分按零分算
+//			if(entry.getValue() < 0) { reviewScore.put(entry.getKey(), 0); }
+//			if(entry.getValue()>maxReviewScore){
+//				maxReviewScore=entry.getValue();
+//			}
+//		}
+//
+//		//将bug得分汇总为report得分
+//		Map<String, Integer> reportScore = new HashMap<String, Integer>();
+//		for(String bugId: bugIdList) {
+//			BugMirror mirror = mdao.findById(bugId);
+//			if(mirror == null) { continue; }
+//			String reportId=mirror.getReport_id();
+//			//出现过bug和bugMirror中没有reportId的问题,需要单独检查
+//			if(reportId!=null) {
+//				reportScore.put(reportId, finalScores.getOrDefault(bugId, 0) + reportScore.getOrDefault(reportId, 0));
+//				if (reportScore.get(reportId) > maxReportScore) {
+//					maxReportScore = reportScore.get(reportId);
+//				}
+//			}
+//		}
+//		//确保被除数不为0
+//		if(maxReportScore==0){
+//			maxReportScore=1;
+//		}
+//		if(maxReviewScore==0){
+//			maxReviewScore=1;
+//		}
+//		//得分要以最高分为满分
+//		for(Map.Entry<String, Integer> entry : reportScore.entrySet()) {
+//			JSONObject json_temp = new JSONObject();
+//			json_temp.put("report_id", entry.getKey());
+//			json_temp.put("worker_id", findWorkerId(entry.getKey()));
+//			json_temp.put("名字", report_trans(entry.getKey()));
+//			json_temp.put("报告得分", (entry.getValue()/maxReportScore)*100);
+//			json_temp.put("审查得分", (reviewScore.getOrDefault(entry.getKey(), 0)/maxReviewScore)*100);
+//			json.put(json_temp);
+//		}
 
-		//计算审查得分
-		for(String bug: bugIdList) {
-			BugMirror mirror = mdao.findById(bug);
-			if(mirror == null) { continue; }
-			int grade = bugScore.getOrDefault(bug, 0);
-			int thumbsScore=0;
-			if(grade>=0&&grade<3){
-				thumbsScore=-2;
-			}else if(grade<5){
-				thumbsScore=-1;
-			}else if(grade<8){
-				thumbsScore=1;
-			}else{
-				thumbsScore=2;
-			}
-			//点赞点踩积分减分
-			ThumsUp(thumbsScore,reviewScore,mirror);
-		}
-		int maxReviewScore=0;
-		int maxReportScore=0;
-		for(Map.Entry<String, Integer> entry : reviewScore.entrySet()) {
-			//审查得分低于零分按零分算
-			if(entry.getValue() < 0) { reviewScore.put(entry.getKey(), 0); }
-			if(entry.getValue()>maxReviewScore){
-				maxReviewScore=entry.getValue();
-			}
-		}
-
-		//将bug得分汇总为report得分
-		Map<String, Integer> reportScore = new HashMap<String, Integer>();
-		for(String bugId: bugIdList) {
-			BugMirror mirror = mdao.findById(bugId);
-			if(mirror == null) { continue; }
-			String reportId=mirror.getReport_id();
-			//出现过bug和bugMirror中没有reportId的问题,需要单独检查
-			if(reportId!=null) {
-				reportScore.put(reportId, finalScores.getOrDefault(bugId, 0) + reportScore.getOrDefault(reportId, 0));
-				if (reportScore.get(reportId) > maxReportScore) {
-					maxReportScore = reportScore.get(reportId);
+		List<Report> reportList=reportDao.findByCaseTakeId(case_take_id);
+		HashMap<String,Integer> hashMap=new HashMap<>();
+		int maxScore=0;
+		for(Report report:reportList){
+			String workerId=report.getWorker_id();
+			hashMap.put(workerId,0);
+			List<Bug> bugList=bdao.findByReport(report.getId(),case_take_id);
+//			logger.info(String.valueOf(bugList.size()));
+			for(Bug bug:bugList){
+				if(bug!=null) {
+					logger.info(bug.getId());
+					BugScore bugScore = bsdao.findById(bug.getId());
+					int score = hashMap.get(workerId);
+					if (bugScore != null) {
+						score += bugScore.getGrade();
+						logger.info(String.valueOf(bugScore.getGrade()));
+					}
+					if (score > maxScore) {
+						maxScore = score;
+					}
+					hashMap.put(workerId, score);
 				}
 			}
 		}
-		//确保被除数不为0
-		if(maxReportScore==0){
-			maxReportScore=1;
-		}
-		if(maxReviewScore==0){
-			maxReviewScore=1;
-		}
-		//得分要以最高分为满分
-		for(Map.Entry<String, Integer> entry : reportScore.entrySet()) {
+		logger.info(String.valueOf(maxScore));
+		JSONArray json = new JSONArray();
+		for(Map.Entry<String, Integer> entry : hashMap.entrySet()) {
+			String key=entry.getKey();
+			int value=entry.getValue();
+			value=(value*100/maxScore);
 			JSONObject json_temp = new JSONObject();
-			json_temp.put("report_id", entry.getKey());
-			json_temp.put("worker_id", findWorkerId(entry.getKey()));
-			json_temp.put("名字", report_trans(entry.getKey()));
-			json_temp.put("报告得分", (entry.getValue()/maxReportScore)*100);
-			json_temp.put("审查得分", (reviewScore.getOrDefault(entry.getKey(), 0)/maxReviewScore)*100);
+			json_temp.put("worker_id",key);
+			json_temp.put("score",value);
 			json.put(json_temp);
 		}
 		//把分写回主站
+//		logger.info("计算结束");
+		logger.info(json.toString());
 		writeScores(case_take_id, json);
 		return json;
 	}
@@ -415,24 +507,51 @@ public class AnalyzeService {
 	}
 
 	private void writeScores(String case_take_id, JSONArray array) {
-		String host = "http://www.mooctest.net";
-		String url = "/api/common/uploadCaseScore";
+//		String host = "http://www.mooctest.net";
+//		String url = "/api/common/uploadCaseScore";
+//		String[] ids = case_take_id.split("-");
+//		String param1 = "caseId=" + ids[0] + "&examId=" + ids[1];
+//		for(int i = 0; i < array.length(); i ++) {
+//			JSONObject json = (JSONObject)array.get(i);
+//			String worker_id = json.get("worker_id").toString();
+//			//报告得分*0.7+审查得分*0.3
+////			int bugScore=Integer.parseInt(json.get("报告得分").toString());
+////			int reviewScore=Integer.parseInt(json.get("审查得分").toString());
+//			double score =  json.getDouble("score");
+//			if(worker_id.equals("")) { continue; }
+//			if(score<0){
+//				score=0;
+//			}
+//			if(score > 100) { score = 100; }
+//			String param2 = "&userId=" + worker_id + "&score=" + score;
+//			HTTP.sendPut(host, url, param1 + param2);
+//			logger.info("---------------");
+//			logger.info(worker_id);
+//		}
+		RestTemplate template = new RestTemplate();
+		String url = "http://www.test.mooctest.net/api/common/uploadCaseScore";
 		String[] ids = case_take_id.split("-");
-		String param1 = "caseId=" + ids[0] + "&examId=" + ids[1];
 		for(int i = 0; i < array.length(); i ++) {
+			MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<String, Object>();
+
 			JSONObject json = (JSONObject)array.get(i);
 			String worker_id = json.get("worker_id").toString();
-			//报告得分*0.7+审查得分*0.3
-			int bugScore=Integer.parseInt(json.get("报告得分").toString());
-			int reviewScore=Integer.parseInt(json.get("审查得分").toString());
-			double score =  bugScore*0.7+reviewScore*0.3;
-			if(score <= 0 || worker_id.equals("")) { continue; }
-			if(score > 100) { score = 100; }
-			String param2 = "&userId=" + worker_id + "&score=" + score;
-			HTTP.sendPut(host, url, param1 + param2);
+			paramMap.add("examId", ids[1]);
+			paramMap.add("caseId", ids[0]);
+			paramMap.add("userId", worker_id);
+			paramMap.add("score", json.getDouble("score"));
+			template.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
+			HttpHeaders headers = new HttpHeaders();
+			HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<MultiValueMap<String, Object>>(paramMap, headers);
+			template.put(url, httpEntity);
+			logger.info("workerId:" +worker_id);
+			logger.info("score:" +json.getDouble("score"));
 		}
+
+
 	}
 
+
 	private String report_trans(String report_id) {
 		String name = studao.findById(report_id);
 		if(name == null || name.equals("null")) { return report_id;}
@@ -465,6 +584,97 @@ public class AnalyzeService {
 		return true;
 	}
 
+	public AnalysePeopleVO getReviewAnalysePeopleVO(String caseId,String taskId,String workerId) {
+		Task task=taskDao.findById(taskId);
+		AnalysePeopleVO res = new AnalysePeopleVO();
+		if(task!=null)res.setTaskName(task.getName());
+		String caseTakeId = caseId+"-"+taskId;
+		// 部分数据从主战接口中取得
+		String result = HTTP.sendGet("http://114.55.91.83:8191/api/user/" + workerId, "");
+		if (result != null && !result.equals("")) {
+			JSONObject json = new JSONObject(result);
+			if (json.has("name") && !json.isNull("name")) {
+				res.setName(DataMaskingUtil.nameMasking(json.getString("name")));
+			}
+			if (json.has("school") && !json.isNull("school")) {
+				res.setSchool( json.getString("school"));
+			}
+			if (json.has("province") && !json.isNull("province")) {
+				res.setProvince(json.getString("province"));
+			}
+			if (json.has("city") && !json.isNull("city")) {
+				res.setCity(json.getString("city"));
+			}
+			if (json.has("createTime") && !json.isNull("createTime")) {
+				res.setRegisterTime(json.getLong("createTime"));
+			}
+			res.setPhotoUrl(DataMaskingUtil.getDefaultMooctestUrl());//使用默认的慕测头像
+//			if (json.has("photoUrl") && !json.isNull("photoUrl")) {
+//				res.setPhotoUrl(json.getString("photoUrl"));
+//			}
+		}
+		//用户lebels
+		res.setLabels(getUserLabels(workerId));
+		Report userReport = extraService.findByWorker(caseTakeId,workerId);
+		List<Bug> bugList = extraService.getBugList(userReport.getId(),caseTakeId);
+		Collections.sort(bugList, Comparator.comparing(Bug::getCreate_time_millis));
+		JSONArray array=new JSONArray();
+//		Map<String,Integer> severityCount = new HashMap<>();
+//		int [] severityValueCount = new int[5];
+		for(Bug bug : bugList){
+//			severityValueCount[bug.getSeverity()]++;
+			JSONObject object = new JSONObject();
+			object.put("content",bug.getTitle());
+			object.put("timestamp", TimeUtil.timestamp2MonthDayHour(bug.getCreate_time_millis(),8));
+			array.put(object);
+		}
+//		int severityMax = Arrays.stream(severityValueCount).max().getAsInt();
+//		for(int i = 0 ;i<severityValueCount.length;i++){
+//			severityCount.put(BugSeverity.getValue(i).toString(),severityValueCount[i]*100/severityMax);
+//		}
+		JSONArray radarLabel = new JSONArray();
+		JSONArray radarData  = new JSONArray();
+		for(int i =0;i<radarInfo.length;i++){
+			radarLabel.put(radarInfo[i]);
+			radarData.put(radarValueStart[i]+workerId.length()>4?workerId.charAt(i)-'0':0);
+		}
+		JSONObject userRadar = new JSONObject();
+		userRadar.put("labels",radarLabel);
+		userRadar.put("data",radarData);
+		res.setUserRadar(userRadar);
+		res.setFirstActivate(bugList.size()==0?0:Long.parseLong(bugList.get(0).getCreate_time_millis()));
+		res.setLastActivate(bugList.size()==0?0:Long.parseLong(bugList.get(bugList.size()-1).getCreate_time_millis()));
+		res.setBugList(bugList);
+		res.setTimeLine(array);
+		return res;
+	}
+
+	private void getTimeDistribute(String workerId){
+		List<Report>reports=reportDao.findReportsByWorker(String.valueOf(workerId));
+		reports = reports.stream().filter(e->{
+			return Long.parseLong(e.getCreate_time_millis()) > monthAgoStart(5);
+		}).collect(Collectors.toList());
+		List<Bug> bugs = new ArrayList<>();
+		for(Report report : reports){
+			bugs.addAll(bdao.findByReport(report.getId(),report.getCase_take_id()));
+		}
+		Map<String,Integer> data = new HashMap<>(6);
+		for(Bug bug : bugs){
+
+		}
+	}
+
+	private long  monthAgoStart(int offset){
+		Calendar calendar = Calendar.getInstance();
+		calendar.set(Calendar.HOUR_OF_DAY, 0);
+		calendar.set(Calendar.MINUTE, 0);
+		calendar.set(Calendar.SECOND, 0);
+		calendar.set(Calendar.MILLISECOND, 0);
+		calendar.add(Calendar.MONTH, -offset);
+		calendar.set(Calendar.DAY_OF_MONTH,1);
+		return calendar.getTimeInMillis();
+	}
+
 	public AnalyseVO getReviewAnalyseVO(String caseId, String taskId){
 		Task task=taskDao.findById(taskId);
 		long startTime=0;
@@ -573,5 +783,405 @@ public class AnalyzeService {
 		return analyseVO;
 	}
 
+	public HistoricalDataVO getHistoricalData(Long workerId, int caseTypeId){
+		List<Report>reports=reportDao.findReportsByWorker(String.valueOf(workerId));
+		int reportNum=reports.size();
+		List<Double>reportScoreList=new ArrayList<>();
+		double totalScore=0;
+		int participateSimilarNum=0;
+		for(Report report:reports){
+			String reportId=report.getId();
+			List<String>bugIds=bdao.findByReport(reportId);
+			double score=0;
+			for(String bugId:bugIds){
+				BugScore bugScore=bsdao.findById(bugId);
+				if(bugScore!=null) {
+					score += bugScore.getGrade();
+				}
+			}
+			totalScore+=score;
+			reportScoreList.add(score);
+			int itemCaseType=1;
+			String brand=report.getDevice_os();
+			if(EnumUtils.isValidEnum(WebBrand.class, brand)){
+				itemCaseType=0;
+			}
+			if(itemCaseType==caseTypeId){
+				participateSimilarNum++;
+			}
+		}
+		HistoricalDataVO historicalDataVO=new HistoricalDataVO(reportNum,reportScoreList,totalScore,participateSimilarNum,reportNum);
+		return historicalDataVO;
+	}
+
+	/**
+	 * 根据用户信息获取用户的labels
+	 * @param wordkId
+	 * @return
+	 */
+	private List<String> getUserLabels(String wordkId){
+		List<UserLabel> labels = userLabelDao.findLabelsByWorkerId(wordkId);
+		List<String> userLabels = labels.stream().map(UserLabel::getLabel).collect(Collectors.toList());
+		userLabels.addAll(mockLabels);
+		return userLabels;
+	}
+
+
+	public AnalyseVO2 getReviewAnalyseVO2(String caseId, String taskId){
+
+//		Cache<String,String> cache = CacheBuilder.newBuilder().build();
+//		cache.put("word","Hello Guava Cache");
+//		System.out.println(cache.getIfPresent("word"));
+
+		Exam exam = examDao.findById(caseId);
+		Task task=taskDao.findById(taskId);
+
+
+
+		long startTime=0;
+		long endTime=0;
+		String taskName="";
+		double writeMins=0.0;
+		if(task!=null) {
+			startTime = task.getStart_time();
+			endTime = task.getEnd_time();
+			writeMins = task.getTotal_mins();
+		}
+		if(exam!=null){
+			taskName = exam.getName();
+		}
+		String caseTakeId=caseId+"-"+taskId;
+		List<Bug>bugs=bdao.findByCaseid(caseTakeId);
+		int bugNum=bugs.size();
+		List<Report>reports=reportDao.findByCaseTakeId(caseTakeId);
+		List<String>reportIds=new ArrayList<>();
+		int reportNum=reports.size();
+		int testCaseNum=0;
+
+		Map<String,String>reportWorkerMap=new HashMap<>();
+		for(Report report:reports){
+			reportIds.add(report.getId());
+			reportWorkerMap.put(report.getId(),report.getWorker_id());
+		}
+		List<TestCase>testCases=testCaseDao.findByReports(reportIds);
+		testCaseNum+=testCases.size();
+		List<BugMirror>bugMirrors=mdao.findByCase(caseTakeId);
+		int likeNum=0;
+		int dislikeNum=0;
+		for(BugMirror bugMirror:bugMirrors){
+			if(bugMirror.getGood()!=null){
+				likeNum+=bugMirror.getGood().size();
+			}
+			if(bugMirror.getBad()!=null){
+				dislikeNum+=bugMirror.getBad().size();
+			}
+		}
+
+		List<String>bugIds=new ArrayList<>();
+		Map<String,String>bugWorkerMap=new HashMap<>();
+		for(Bug bug:bugs){
+			bugIds.add(bug.getId());
+			String reportId=bug.getReport_id();
+			if(reportId!=null) {
+				String workerId=reportWorkerMap.get(reportId);
+				if (workerId!=null) {
+					bugWorkerMap.put(bug.getId(),workerId);
+				}
+			}
+		}
+
+		Map<Integer,Integer>gradeDistribution=new HashMap<>();
+		Map<String,Integer>workerDistribution=new HashMap<>();
+		List<BugScore>bugScores=bsdao.findByIds(bugIds);
+		for(BugScore bugScore:bugScores){
+			int grade = bugScore.getGrade();
+			String workerId=bugWorkerMap.get(bugScore.getId());
+			if(workerId!=null){
+				if (workerDistribution.containsKey(workerId)) {
+					workerDistribution.replace(workerId, workerDistribution.get(workerId) + grade);
+				} else {
+					workerDistribution.put(workerId, grade);
+				}
+			}
+			if (gradeDistribution.containsKey(grade)) {
+				gradeDistribution.replace(grade, gradeDistribution.get(grade) + 1);
+			} else {
+				gradeDistribution.put(grade, 1);
+			}
+		}
+
+		int forkNum=0;
+		List<BugHistory>bugHistories=bugHistoryDao.findBugHistoryList(bugIds);
+		for(BugHistory bugHistory:bugHistories){
+			if(bugHistory.getChildren()!=null&&bugHistory.getChildren().size()!=0){
+				forkNum+=1;
+			}
+		}
+		//分数排序
+		List<Map.Entry<String, Integer>> list = new ArrayList<>(workerDistribution.entrySet());
+		Collections.sort(list, new Comparator<Map.Entry<String, Integer>>()
+		{
+			@Override
+			public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2)
+			{
+				return o2.getValue().compareTo(o1.getValue());
+
+			}
+		});
+		List<WorkerVO>workerRank=new ArrayList<>();
+		Map<String,Integer>provinceDistribute=new HashMap<>();
+		for(int i=0;i<list.size();i++) {
+			String workerId = list.get(i).getKey();
+			int grade=list.get(i).getValue();
+			String result = HTTP.sendGet("http://114.55.91.83:8191/api/user/" + workerId, "");
+			String name = "";
+			String school = "";
+			String province="";
+			if (result != null && !result.equals("")) {
+				JSONObject json = new JSONObject(result);
+				if (json.has("name") && !json.isNull("name")) {
+//					name = json.getString("name");
+					name = DataMaskingUtil.nameMasking(json.getString("name"));
+				}
+				if (json.has("school") && !json.isNull("school")) {
+					school = json.getString("school");
+				}
+				if (json.has("province") && !json.isNull("province")) {
+					province = json.getString("province");
+					if(province.endsWith("省")||province.endsWith("市")){
+						province=province.substring(0,province.length()-1);
+					}
+					if (provinceDistribute.containsKey(province)) {
+						provinceDistribute.replace(province, provinceDistribute.get(province) + 1);
+					} else {
+						provinceDistribute.put(province, 1);
+					}
+				}
+				WorkerVO workerVO=new WorkerVO(workerId,name,school,grade);
+				workerRank.add(workerVO);
+			}
+		}
+		JSONArray workerDistribute=new JSONArray();
+		for(Map.Entry<String, Integer> entry : provinceDistribute.entrySet()){
+			String mapKey = entry.getKey();
+			int mapValue = entry.getValue();
+			JSONObject jsonObject=new JSONObject();
+			jsonObject.put("name",mapKey);
+			jsonObject.put("value",mapValue);
+			workerDistribute.put(jsonObject);
+		}
+		Map<String,Integer>coverMap=getPageCover(taskId,caseId);
+		int size=coverMap.size();
+		int noBugPage=0;
+		for (Map.Entry<String, Integer> entry : coverMap.entrySet()) {
+			if(entry.getValue()==0){
+				noBugPage++;
+			}
+		}
+		double pageCover=1 - noBugPage*1.0/size;
+		AnalyseVO2 analyseVO=new AnalyseVO2(likeNum,dislikeNum,forkNum,reportNum,testCaseNum,bugNum,startTime,endTime,reportNum,taskName,workerDistribute,workerRank,gradeDistribution,pageCover);
+		StringBuffer managerCheckUrl = new StringBuffer("http://");
+		managerCheckUrl.append(serverHost).append(":").append(serverPort).append("/report/managerCheck/")
+				.append(taskId).append("/").append(caseId);
+		if(reports.size()!=0)
+			managerCheckUrl.append("?identity=0&report_id=").append(reports.get(0).getId())
+					.append("&worker_id=").append(reports.get(0).getWorker_id());
+		analyseVO.setManagerCheck(managerCheckUrl.toString());
+		return analyseVO;
+	}
+
+
+	public Map<String,Integer> getPageCover(String taskId,String caseId){
+		String caseTakeId=caseId+"-"+taskId;
+		Map<String,Integer>coverMap=getBugDetail(caseTakeId);
+		List<String>pageStr=getPageStr(caseId);
+		for(String page:pageStr){
+			if(!coverMap.containsKey(page)){
+				coverMap.put(page,0);
+			}
+		}
+		return coverMap;
+	}
+
+	//将三级页面信息的jsonobject转为string
+	private List<String> getPageStr(String caseId){
+		List<String>result=new ArrayList<>();
+		Exam exam=extraService.getExam(String.valueOf(caseId));
+		JSONArray jsonArray=new JSONArray(exam.getJson());
+		LinkedList<String> res = new LinkedList<>();
+		if(jsonArray==null){
+			return res;
+		}
+		for(int i=0;i<jsonArray.length();i++){
+			JSONObject jsonObject=jsonArray.getJSONObject(i);
+			if(jsonObject==null||jsonObject.getString("item")==null)
+				return res;
+			solve(jsonObject, jsonObject.getString("item")+"-", res);
+		}
+		return res;
+	}
+
+
+	private void solve(JSONObject jsonObject, String cur, LinkedList<String> res) {
+		if(jsonObject==null||jsonObject.getString("item")==null)
+			return;
+		cur+=jsonObject.getString("item");
+		if (!jsonObject.has("children")||jsonObject.get("children")==null) {
+			res.add(cur);
+		} else {
+			JSONArray jsonArray=jsonObject.getJSONArray("children");
+			for(int i=0;i<jsonArray.length();i++){
+				JSONObject jsonObject1=jsonArray.getJSONObject(i);
+				solve(jsonObject1,cur+"-",res);
+			}
+		}
+	}
+
+	public int[][] getBugInfo(String taskId,String caseId){
+		String caseTakeId=caseId+"-"+taskId;
+		List<Bug>bugs=bdao.findByCaseid(caseTakeId);
+		int[][]bugInfo=new int[6][6];     //bug的复现程度和严重程度都为1-5
+		for(Bug bug:bugs){
+			int bugSeverity=bug.getSeverity();
+			int bugRecurrent=bug.getRecurrent();
+			bugInfo[bugSeverity][bugRecurrent]+=1;
+		}
+		return bugInfo;
+	}
+
+	public Map<String,Integer> getBugSubmitInfo(String taskId,String caseId,int piece){
+		Map<Integer,Integer>map=new HashMap<>(piece);
+		Map<String,Integer> res = new HashMap<>(piece);
+		if(piece<=0)return res;
+		Task task=taskDao.findById(taskId);
+		long startTime=0;
+		long endTime=0;
+		if(task!=null) {
+			startTime = task.getStart_time();
+			endTime = task.getEnd_time();
+		}
+		long pieceTime=(endTime-startTime)/piece;
+		String caseTakeId=caseId+"-"+taskId;
+		List<Bug>bugs=bdao.findByCaseid(caseTakeId);
+		map.put(0,0);
+		for(Bug bug:bugs){
+			long time=Long.parseLong(bug.getCreate_time_millis());
+			int index=(int)((time-startTime)/pieceTime)+1;
+			if(map.containsKey(index)){
+				map.replace(index,map.get(index)+1);
+			}
+			else{
+				map.put(index,1);
+			}
+		}
+		for(Map.Entry<Integer,Integer> e : map.entrySet()){
+			res.put(TimeUtil.timestamp2DayHour(startTime+e.getKey()*pieceTime,8),e.getValue());
+		}
+		return res;
+	}
+
+	public ShortToken tokenToDetail(String token){
+		return shortTokenDao.findByTokenString(token);
+	}
+
+	public ShortToken findTokenByDetail(String examId,String caseID,String userId){
+		return shortTokenDao.findByDetailInfo(examId,caseID,userId);
+	}
+
+	public String saveShortToken(ShortToken shortToken){
+		return shortTokenDao.save(shortToken);
+	}
+
+	public Double crowdTestProgressFromDB(String caseId,String taskId){
+		String case_take_id=caseId+"-"+taskId;
+		CrowdTest crowdTest=crowdTestDao.findByCaseTakeId(case_take_id);
+		if(crowdTest==null){
+			return crowdTestProgress(caseId,taskId);
+		}else{
+			return crowdTest.getProgress();
+		}
+	}
+
+	public Double crowdTestProgress(String caseId,String taskId) {
+		SimpleDateFormat formatLine = new SimpleDateFormat ("yyyy/MM/dd HH:mm");
+		SimpleDateFormat formatCon = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss");
+		List<BugForProgress> bugForProgressList=new ArrayList<>();
+		String caseTakeId=caseId+"-"+taskId;
+		List<Report> reportList = reportDao.findByCaseTakeId(caseTakeId);
+		for (Report report : reportList) {
+			String reportId = report.getId();
+			List<TestCase> testCaseList = testCaseDao.findByReport(reportId);
+			for (TestCase testCase : testCaseList) {
+				String testCaseId = testCase.getId();
+				List<String> bugIdList = ctbdao.findById(testCaseId);
+				for (String bugId : bugIdList) {
+					Bug bug = bdao.findByid(bugId);
+					if (bug != null) {
+						BugForProgress bugForProgress = new BugForProgress();
+						bugForProgress.setId(bugId);
+						bugForProgress.setTestCaseId(testCaseId);
+						bugForProgress.setTestCaseName(testCase.getName());
+						bugForProgress.setUserId(report.getWorker_id());
+						//bug基本属性
+						bugForProgress.setSeverity(TransUtil.severityTransFromInt(bug.getSeverity()));
+						bugForProgress.setBugPage(bug.getBug_page());
+						bugForProgress.setTitle(bug.getTitle());
+						bugForProgress.setDescription(bug.getDescription());
+						String time = TransUtil.formatTimeMillis(bug.getCreate_time_millis());
+						time = transferString(time);
+						Date submitTime  = null;
+						try {
+							if (time.contains("-")) {
+								submitTime = formatCon.parse(time);
+							} else {
+								submitTime = formatLine.parse(time);
+							}
+						}catch (ParseException e){
+							e.printStackTrace();
+						}
+						bugForProgress.setBugCreateTime(submitTime);
+						bugForProgressList.add(bugForProgress);
+					}
+				}
+			}
+		}
+		bugForProgressList.sort(new Comparator<BugForProgress>() {
+			@Override
+			public int compare(BugForProgress o1, BugForProgress o2) {
+				Date d1 = o1.getBugCreateTime();
+				Date d2 = o2.getBugCreateTime();
+				if (d1.before(d2)) {
+					return -1;
+				} else {
+					return 1;
+				}
+			}
+		});
+		TaskClosePrediction closePrediction = new TaskClosePrediction();
+		Double completeRatio = closePrediction.determineTaskProgressStatus(bugForProgressList);
+		completeRatio = completeRatio.intValue() * 1.0;
+		CrowdTest crowdTest=new CrowdTest();
+		crowdTest.setCaseId(caseId);
+		crowdTest.setTaskId(taskId);
+		crowdTest.setId(caseTakeId);
+		crowdTest.setCaseTakeId(caseTakeId);
+		crowdTest.setProgress(completeRatio);
+		crowdTestDao.save(crowdTest);
+		return completeRatio;
+	}
+
+
+	private String transferString ( String str ){
+		String result = str;
+		result = result.replaceAll( "\r\n", " " );
+		result = result.replaceAll( "\r", " " );
+		result = result.replaceAll( "\n", " " );
+		return result;
+	}
+
+
+
+
+
 
 }

+ 0 - 2
src/main/java/edu/nju/service/DataService.java

@@ -451,5 +451,3 @@ public class DataService {
         }
     }
 }
-
-

+ 40 - 2
src/main/java/edu/nju/service/ExtraService.java

@@ -9,9 +9,9 @@ import java.util.*;
 
 import edu.nju.dao.*;
 import edu.nju.entities.*;
-import edu.nju.model.BugRecurrent;
-import edu.nju.model.BugSeverity;
+import edu.nju.model.*;
 import edu.nju.util.*;
+import org.apache.commons.lang3.EnumUtils;
 import org.json.JSONArray;
 import org.json.JSONObject;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -286,6 +286,44 @@ public class ExtraService {
 		return pageUrl+caseId+".json";
 	}
 
+	public PageExamVO findPageAndExam(long examId, long caseId){
+		PageExamVO pageExamVO=new PageExamVO(examId,caseId);
+		Exam examCase=getExam(String.valueOf(caseId));
+		pageExamVO.setPageContent(examCase.getJson());
+		String json=examCase.getPaper_type();
+		int caseTypeId=getPaperType(json);
+		pageExamVO.setCaseTypeId(caseTypeId);
+		Task task=taskDao.findById(String.valueOf(examId));
+		Date startTime=null;
+		Date endTime=null;
+		if(task!=null){
+			startTime=new Date(task.getStart_time());
+			endTime=new Date(task.getEnd_time());
+		}
+		ExamVO examVO=new ExamVO(examId,caseId,0,caseTypeId,startTime,endTime);
+		pageExamVO.setExamVO(examVO);
+		return pageExamVO;
+	}
+
+	private int getPaperType(String json){
+		//json=json.substring(1,json.length()-1);
+		JSONObject jsonObject = new JSONObject(json);
+		JSONArray jsonArray=jsonObject.getJSONArray("subTitles");
+		int caseTypeId=1;//这里只对WEB和APP进行了判断
+		for(int i=0;i<jsonArray.length();i++) {
+			JSONObject item = jsonArray.getJSONObject(i);
+			String label=item.getString("name");
+			if(label.equals("操作系统")){
+				JSONArray brandList=item.getJSONArray("value");
+				String brand=String.valueOf(brandList.get(0));
+				if(EnumUtils.isValidEnum(WebBrand.class, brand)){
+					caseTypeId=0;
+				}
+				break;
+			}
+		}
+		return caseTypeId;
+	}
 
 
 

+ 17 - 0
src/main/java/edu/nju/service/FileService.java

@@ -0,0 +1,17 @@
+package edu.nju.service;
+
+import edu.nju.entities.BugDetail;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
+
+/**
+ * @Author JiaWei Xu
+ * @Date 2021-01-04 15:24
+ * @Email xjwhhh233@outlook.com
+ */
+public interface FileService {
+    public void uploadImage();
+    public List<BugDetail> importBugInfo(MultipartFile sourceZipFile, MultipartFile sourceJsonFile, String originalCaseId, String cpSerialNum);
+    public List<BugDetail> exportBugInfo(String caseId);
+}

+ 471 - 0
src/main/java/edu/nju/service/NginxFileService.java

@@ -0,0 +1,471 @@
+package edu.nju.service;
+
+import edu.nju.entities.BugDetail;
+import edu.nju.entities.Exam;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
+
+import java.io.File;
+import java.util.List;
+
+import com.alibaba.fastjson.JSON;
+import com.aliyun.oss.OSS;
+import edu.nju.dao.*;
+import edu.nju.entities.*;
+import edu.nju.util.OssAliyun;
+import edu.nju.util.TransUtil;
+import org.json.JSONArray;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.*;
+import java.lang.reflect.Field;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+
+/**
+ * @Author JiaWei Xu
+ * @Date 2021-01-04 15:27
+ * @Email xjwhhh233@outlook.com
+ */
+@Service
+@ConditionalOnExpression("${useOss}==false")
+public class NginxFileService implements FileService {
+
+    private static final int BUFFER_SIZE = 2048;
+    @Autowired
+    ExamDao examDao;
+
+    @Autowired
+    BugDao bugDao;
+
+    @Autowired
+    ReportDao reportDao;
+
+    @Autowired
+    TestCaseDao testCaseDao;
+
+    @Autowired
+    CaseToBugDao caseToBugDao;
+
+    @Autowired
+    BugScoreDao bugScoreDao;
+
+    @Autowired
+    BugMirrorDao bugMirrorDao;
+
+    @Autowired
+    BugHistoryDao bugHistoryDao;
+
+    @Autowired
+    BugDetailDao bugDetailDao;
+
+    @Value("${cpSerialNum}")
+    private String cpSerialNum;
+
+    @Value("${nginx.imageUrlPrefix}")
+    private String nginxImageUrlPrefix;
+
+    @Override
+    public void uploadImage() {
+
+    }
+
+    @Override
+    public List<BugDetail> importBugInfo(MultipartFile sourceZipFile, MultipartFile sourceJsonFile, String originalCaseId, String cpSerialNum) {
+       return saveBugDetail(sourceZipFile,sourceJsonFile,originalCaseId,cpSerialNum);
+    }
+
+    @Override
+    public List<BugDetail> exportBugInfo(String caseId) {
+        List<BugDetail> bugDetailList = getBugDetailListByCaseId(caseId);
+        bugDetailToFile(bugDetailList,caseId);
+        return bugDetailList;
+    }
+
+    private List<BugDetail> saveBugDetail(MultipartFile sourceZipFile, MultipartFile sourceJsonFile, String originalCaseId,String cpSerialNum){
+        try {
+            //读取文件流并保存在本地
+            String prefix="";
+            String zipFilePath=prefix+"/xinchuangdata/input/imageZip/"+originalCaseId+"/"+cpSerialNum+"/"+originalCaseId+".zip";
+            File zipFile=new File(zipFilePath);
+            if(!zipFile.getParentFile().exists()) { zipFile.getParentFile().mkdirs(); }
+            if(!sourceZipFile.isEmpty()) { sourceZipFile.transferTo(zipFile); }
+            String jsonFilePath=prefix+"/xinchuangdata/input/"+originalCaseId+"/"+cpSerialNum+"/"+originalCaseId+".json";
+            File jsonFile=new File(jsonFilePath);
+            if(!jsonFile.getParentFile().exists()) { jsonFile.getParentFile().mkdirs(); }
+            if(!sourceJsonFile.isEmpty()) { sourceJsonFile.transferTo(jsonFile); }
+            //读取本地文件
+            BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(jsonFile));
+            ByteArrayOutputStream buf = new ByteArrayOutputStream();
+            int result = bufferedInputStream.read();
+            while (result != -1) {
+                buf.write((byte) result);
+                result = bufferedInputStream.read();
+            }
+            String json = buf.toString();
+            //转为bugDetail
+            List<BugDetail> bugDetailList = JSON.parseArray(json, BugDetail.class);
+            for (BugDetail bugDetail : bugDetailList) {
+                bugDetail.setOriginalCaseId(originalCaseId);
+                //修改图片文件路径为本地路径
+                String imageUrl = bugDetail.getImgUrl();
+                String[] imageUrlArray = imageUrl.split(",");
+                StringBuilder stringBuilder = new StringBuilder();
+                for (String imageUrlStr : imageUrlArray) {
+                    if(!"".equals(imageUrl)) {
+                        String[] filePath = imageUrlStr.split("/");
+                        String fileName = filePath[filePath.length - 1];
+                        String newImageUrl = nginxImageUrlPrefix + originalCaseId + "/" + cpSerialNum + "/" + fileName;
+                        stringBuilder.append(newImageUrl).append(",");
+                    }
+                }
+                bugDetail.setImgUrl(stringBuilder.toString());
+                bugDetailDao.save(bugDetail);
+            }
+            //解压图片文件,保存至本地
+            String destPath=prefix+"/xinchuangdata/input/imageUnzip/"+originalCaseId+"/"+cpSerialNum;
+            File unzipFile=new File(destPath);
+            if(!unzipFile.getParentFile().exists()) { unzipFile.getParentFile().mkdirs(); }
+            unZip(zipFile,destPath,originalCaseId,cpSerialNum);
+            return bugDetailList;
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return new ArrayList<>();
+    }
+    private List<BugDetail> getBugDetailListByCaseId(String caseId) {
+        List<BugDetail> bugDetailList = new ArrayList<>();
+        Exam crowdCase = examDao.findById(caseId);
+        if (crowdCase != null) {
+            List<Report> reportList = reportDao.findByCaseId(caseId);
+            for (Report report : reportList) {
+                String reportId = report.getId();
+                List<TestCase> testCaseList = testCaseDao.findByReport(reportId);
+                for (TestCase testCase : testCaseList) {
+                    String testCaseId = testCase.getId();
+                    CaseToBug caseToBug = caseToBugDao.findById(testCaseId);
+                    if (caseToBug != null) {
+                        List<String> bugIdList = caseToBug.getBug_id();
+                        for (String bugId : bugIdList) {
+                            BugDetail bugDetail = new BugDetail();
+                            bugDetail.setId(bugId);
+                            //bug基本属性
+                            Bug bug = bugDao.findByid(bugId);
+                            if (bug != null) {
+                                bugDetail.setBugCategory(bug.getBug_category());
+                                bugDetail.setSeverity(TransUtil.severityTransFromInt(bug.getSeverity()));
+                                bugDetail.setRecurrent(TransUtil.recurrentTransFromInt(bug.getRecurrent()));
+                                bugDetail.setBugCreateTime(TransUtil.formatTimeMillis(bug.getCreate_time_millis()));
+                                bugDetail.setBugPage(bug.getBug_page());
+                                bugDetail.setTitle(bug.getTitle());
+                                bugDetail.setBugDescription(bug.getDescription());
+                                bugDetail.setImgUrl(bug.getImg_url());
+                            }
+                            //bugScore属性
+                            BugScore bugScore = bugScoreDao.findById(bugId);
+                            if (bugScore != null) {
+                                bugDetail.setScore(bugScore.getGrade());
+                            }
+                            //bugMirror属性
+                            BugMirror bugMirror = bugMirrorDao.findById(bugId);
+                            if (bugMirror != null) {
+                                Set<String> goodWorkerIdSet = new HashSet<>();
+                                Set<String> badWorkerIdSet = new HashSet<>();
+                                Set<String> goodReportIdSet = bugMirror.getGood();
+                                Set<String> badReportIdSet = bugMirror.getBad();
+                                int goodNum = 0;
+                                int badNum = 0;
+                                for (String goodReportId : goodReportIdSet) {
+                                    Report goodReport = reportDao.findById(goodReportId);
+                                    if (goodReport != null) {
+                                        goodNum++;
+                                        goodWorkerIdSet.add(goodReport.getWorker_id());
+                                    }
+                                }
+                                for (String badReportId : badReportIdSet) {
+                                    Report badReport = reportDao.findById(badReportId);
+                                    if (badReport != null) {
+                                        badNum++;
+                                        badWorkerIdSet.add(badReport.getWorker_id());
+                                    }
+                                }
+                                bugDetail.setGoodNum(goodNum);
+                                bugDetail.setBadNum(badNum);
+                                bugDetail.setGoodWorkerId(goodWorkerIdSet);
+                                bugDetail.setBadWorkerId(badWorkerIdSet);
+                            }
+                            //bugHistory属性
+                            BugHistory bugHistory = bugHistoryDao.findByid(bugId);
+                            if (bugHistory != null) {
+                                bugDetail.setParent(bugHistory.getParent());
+                                bugDetail.setChildren(bugHistory.getChildren());
+                                bugDetail.setRoot(bugHistory.getRoot());
+                            }
+                            //testCase属性
+                            bugDetail.setTestCaseId(testCase.getId());
+                            bugDetail.setTestCaseName(testCase.getName());
+                            bugDetail.setTestCaseFront(testCase.getFront());
+                            bugDetail.setTestCaseBehind(testCase.getBehind());
+                            bugDetail.setTestCaseDescription(testCase.getDescription());
+                            bugDetail.setTestCaseCreateTime(TransUtil.formatTimeMillis(testCase.getCreate_time_millis()));
+                            //report属性
+                            bugDetail.setReportId(report.getId());
+                            bugDetail.setReportName(report.getName());
+                            bugDetail.setScriptLocation(report.getScript_location());
+                            bugDetail.setReportLocation(report.getReport_location());
+                            bugDetail.setLogLocation(report.getLog_location());
+                            bugDetail.setDeviceModel(report.getDevice_model());
+                            bugDetail.setDeviceBrand(report.getDevice_brand());
+                            bugDetail.setDeviceOs(report.getDevice_os());
+                            //worker属性
+                            bugDetail.setWorkerId(report.getWorker_id());
+                            //众测任务属性
+                            bugDetail.setCaseAppName(crowdCase.getName());
+                            bugDetail.setCasePaperType(crowdCase.getPaper_type());
+                            bugDetail.setCaseTestType(crowdCase.getTest_type());
+                            bugDetail.setCaseDescription(crowdCase.getDescription());
+                            bugDetail.setCaseRequireDoc("");
+                            bugDetail.setCaseTakeId(report.getCase_take_id());
+                            //cp序列号
+                            bugDetail.setCpSerialNum(cpSerialNum);
+                            bugDetailList.add(bugDetail);
+                        }
+                    }
+                }
+            }
+        }
+        return bugDetailList;
+    }
+
+    private void bugDetailToFile(List<BugDetail> bugDetailList, String caseId) {
+        String[] titles = {"bug_id", "bug_category", "severity", "recurrent", "bug_create_time", "bug_page", "title",
+                "description", "img_url",
+                "score", "parent", "children", "root", "good_num", "good_worker_id", "bad_num", "bad_worker_id",
+                "test_case_id", "test_case_name", "test_case_front", "test_case_behind", "test_case_description", "test_case_create_time",
+                "report_id", "report_name", "report_create_time", "script_location", "report_location", "log_location", "device_model", "device_brand", "device_os",
+                "worker_id",
+                "case_app_name", "case_paper_type", "case_test_type", "case_description", "case_require_doc",
+                "case_take_id", "originalCaseId", "cpSerialNum"};
+        //导出文件
+        exportCsv(titles, bugDetailList, caseId);
+        exportJson(bugDetailList, caseId);
+        //导出图片zip包
+        String sourceFile = "/xinchuangdata/image/" + caseId;
+        try {
+            File dest = new File("/xinchuangdata/output/imageZip/" + caseId + ".zip");
+            if (!dest.getParentFile().exists()) {
+                dest.getParentFile().mkdirs();
+            }
+            FileOutputStream fileOutputStream = new FileOutputStream(dest);
+            toZip(sourceFile, fileOutputStream, false);
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+        }
+    }
+
+    private void exportJson(List<BugDetail> bugDetailList, String caseId) {
+        try {
+            File file = new File("/xinchuangdata/output/" + caseId + "/" + caseId + ".json");
+            if (!file.getParentFile().exists()) {
+                file.getParentFile().mkdirs();
+            }
+            JSONArray jsonArray = new JSONArray(bugDetailList);
+            Writer write = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8);
+            write.write(jsonArray.toString());
+            write.flush();
+            write.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    private <T> void exportCsv(String[] titles, List<T> list, String caseId) {
+        try {
+            File file = new File("/xinchuangdata/output/" + caseId + "/" + caseId + ".csv");
+            if (!file.getParentFile().exists()) {
+                file.getParentFile().mkdirs();
+            }
+            //构建输出流,同时指定编码
+            OutputStreamWriter ow = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8);
+            //csv文件是逗号分隔,除第一个外,每次写入一个单元格数据后需要输入逗号
+            for (String title : titles) {
+                ow.write(title);
+                ow.write(",");
+            }
+            //写完文件头后换行
+            ow.write("\r\n");
+            //写内容
+            for (Object obj : list) {
+                //利用反射获取所有字段
+                Field[] fields = obj.getClass().getDeclaredFields();
+                for (Field field : fields) {
+                    //设置字段可见性
+                    field.setAccessible(true);
+                    //防止某个field没有赋值
+                    if (field.get(obj) == null) {
+                        ow.write("");
+                    } else {
+                        //解决csv文件中对于逗号和双引号的转义问题
+                        ow.write("\"" + field.get(obj).toString().replaceAll("\"", "\"\"") + "\"");
+                    }
+                    ow.write(",");
+                }
+                //写完一行换行
+                ow.write("\r\n");
+            }
+            ow.flush();
+            ow.close();
+        } catch (IOException | IllegalAccessException e) {
+            e.printStackTrace();
+        }
+    }
+
+    private void toZip(String srcDir, OutputStream out, boolean keepDirStructure)
+            throws RuntimeException {
+        long start = System.currentTimeMillis();
+        ZipOutputStream zos = null;
+        try {
+            zos = new ZipOutputStream(out);
+            File sourceFile = new File(srcDir);
+            compress(sourceFile, zos, sourceFile.getName(), keepDirStructure);
+            long end = System.currentTimeMillis();
+            System.out.println("压缩完成,耗时:" + (end - start) + " ms");
+        } catch (Exception e) {
+            throw new RuntimeException("zip error from ZipUtils", e);
+        } finally {
+            if (zos != null) {
+                try {
+                    zos.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    /**
+     * 递归压缩方法
+     *
+     * @param sourceFile       源文件
+     * @param zos              zip输出流
+     * @param name             压缩后的名称
+     * @param keepDirStructure 是否保留原来的目录结构,true:保留目录结构;
+     *                         false:所有文件跑到压缩包根目录下(注意:不保留目录结构可能会出现同名文件,会压缩失败)
+     * @throws Exception
+     */
+    private void compress(File sourceFile, ZipOutputStream zos, String name,
+                          boolean keepDirStructure) throws Exception {
+        byte[] buf = new byte[BUFFER_SIZE];
+        if (sourceFile.isFile()) {
+            // 向zip输出流中添加一个zip实体,构造器中name为zip实体的文件的名字
+            zos.putNextEntry(new ZipEntry(name));
+            // copy文件到zip输出流中
+            int len;
+            FileInputStream in = new FileInputStream(sourceFile);
+            while ((len = in.read(buf)) != -1) {
+                zos.write(buf, 0, len);
+            }
+            // Complete the entry
+            zos.closeEntry();
+            in.close();
+        } else {
+            File[] listFiles = sourceFile.listFiles();
+            if (listFiles == null || listFiles.length == 0) {
+                // 需要保留原来的文件结构时,需要对空文件夹进行处理
+                if (keepDirStructure) {
+                    // 空文件夹的处理
+                    zos.putNextEntry(new ZipEntry(name + "/"));
+                    // 没有文件,不需要文件的copy
+                    zos.closeEntry();
+                }
+
+            } else {
+                for (File file : listFiles) {
+                    // 判断是否需要保留原来的文件结构
+                    if (keepDirStructure) {
+                        // 注意:file.getName()前面需要带上父文件夹的名字加一斜杠,
+                        // 不然最后压缩包中就不能保留原来的文件结构,即:所有文件都跑到压缩包根目录下了
+                        compress(file, zos, name + "/" + file.getName(), true);
+                    } else {
+                        compress(file, zos, file.getName(), false);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * zip解压
+     *
+     * @param srcFile     zip源文件
+     * @param destDirPath 解压后的目标文件夹
+     * @throws RuntimeException 解压失败会抛出运行时异常
+     */
+
+    private void unZip(File srcFile, String destDirPath,String originalCaseId,String fromCpSerialNum) throws RuntimeException {
+        long start = System.currentTimeMillis();
+        // 判断源文件是否存在
+        if (!srcFile.exists()) {
+            throw new RuntimeException(srcFile.getPath() + "所指文件不存在");
+        }
+        // 开始解压
+        ZipFile zipFile = null;
+        try {
+            zipFile = new ZipFile(srcFile);
+            Enumeration<?> entries = zipFile.entries();
+
+            while (entries.hasMoreElements()) {
+                ZipEntry entry = (ZipEntry) entries.nextElement();
+                System.out.println("解压" + entry.getName());
+                // 如果是文件夹,就创建个文件夹
+                if (entry.isDirectory()) {
+                    String dirPath = destDirPath + "/" + entry.getName();
+                    File dir = new File(dirPath);
+                    dir.mkdirs();
+                } else {
+                    // 如果是文件,就先创建一个文件,然后用io流把内容copy过去
+                    File targetFile = new File(destDirPath + "/" + entry.getName());
+                    // 保证这个文件的父文件夹必须要存在
+                    if (!targetFile.getParentFile().exists()) {
+                        targetFile.getParentFile().mkdirs();
+                    }
+                    targetFile.createNewFile();
+                    // 将压缩文件内容写入到这个文件中
+                    InputStream is = zipFile.getInputStream(entry);
+                    FileOutputStream fos = new FileOutputStream(targetFile);
+                    int len;
+                    byte[] buf = new byte[BUFFER_SIZE];
+                    while ((len = is.read(buf)) != -1) {
+                        fos.write(buf, 0, len);
+                    }
+                    // 关流顺序,先打开的后关闭
+                    fos.close();
+                    is.close();
+                }
+            }
+            long end = System.currentTimeMillis();
+            System.out.println("解压完成,耗时:" + (end - start) + " ms");
+        } catch (Exception e) {
+            throw new RuntimeException("unzip error from ZipUtils", e);
+        } finally {
+            if (zipFile != null) {
+                try {
+                    zipFile.close();
+
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+
+}

+ 17 - 0
src/main/java/edu/nju/service/NodeService.java

@@ -553,6 +553,23 @@ public class NodeService {
 
     }
 
+    public JSONObject uploadSingleCatchNodesToMoocTest(String jobId){
+        List<ReviewWorker>reviewWorkers=reviewWorkerDao.getWorkersByJob(jobId);
+        List<String>failList=new ArrayList<>();
+        if(reviewWorkers!=null){
+            for(int i=0;i<reviewWorkers.size();i++){
+                JSONObject result=uploadSingleCatchNodeToMoocTest(jobId,reviewWorkers.get(i).getId());
+                if(!result.get("status").equals("200")){
+                    failList.add(reviewWorkers.get(i).getId());
+                }
+            }
+        }
+        JSONArray jsonArray=new JSONArray(failList);
+        JSONObject result=new JSONObject();
+        result.put("failWorker",jsonArray);
+        return result;
+    }
+
 
 
 }

+ 4 - 0
src/main/java/edu/nju/service/ReportService.java

@@ -265,6 +265,10 @@ public class ReportService {
 		}
 		return map_sort(map);
 	}
+
+	public Bug findBugById(String budId){
+		return bdao.findByid(budId);
+	}
 	
 	private JSONObject rank_sort(Map<String, Integer> result) {
 		JSONObject json = new JSONObject(true);

+ 176 - 4
src/main/java/edu/nju/service/ReviewAnalyzeService.java

@@ -9,17 +9,17 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.Row;
 import org.apache.poi.ss.util.CellRangeAddress;
+import org.json.JSONArray;
 import org.json.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.io.File;
 import java.io.FileOutputStream;
 import java.text.DecimalFormat;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 @Service
 public class ReviewAnalyzeService {
@@ -37,6 +37,19 @@ public class ReviewAnalyzeService {
     @Autowired
     ReviewReportDao reviewReportDao;
 
+    @Autowired
+    BugDao bugDao;
+
+    @Autowired
+    BugScoreDao bugScoreDao;
+
+
+    @Autowired
+    AnalyzeService analyzeService;
+
+
+    Logger logger= LoggerFactory.getLogger(RecommendService.class);
+
 
     public JSONObject analyzeItem(String itemId,String reportId,String jobId){
         JSONObject jsonObject=new JSONObject();
@@ -97,6 +110,80 @@ public class ReviewAnalyzeService {
     }
 
 
+    public JSONArray getJsonExportByPaper( String paperId ) {
+        List<ReviewJob> jobs =    reviewJobDao.findJobsByPaper(paperId);
+        JSONArray res = new JSONArray();
+        for (ReviewJob job : jobs){
+            res.put(getJsonExport(job.getId()));
+        }
+        return res;
+    }
+
+    public JSONObject getJsonExport ( String jobId){
+        ReviewJob job = reviewJobDao.findJob(jobId) ;
+        JSONObject res = new JSONObject();
+        JSONArray reportInfo = new JSONArray();
+        List<ReviewReport > reports = reviewReportDao.getReportsByPaperId(job.getPaper_id());
+        JSONObject reportJsonInfo ;
+        for( ReviewReport r : reports){ // 便利所有的报告,报告报告的信息 和 评审信息
+            reportJsonInfo = new JSONObject();
+            reportJsonInfo.put("info",new JSONObject(r));
+            List<ReviewItem> items = reviewItemDao.findItemsByReport(r.getId());
+            JSONArray itemArray = new JSONArray();
+            for (ReviewItem i : items){
+                JSONObject itemJson = new JSONObject();
+                itemJson.put("description" , i.getDescription());
+                List<ReviewAnswer> answers = reviewAnswerDao.getItemReportJobAnswers(i.getId(),r.getId(),jobId);
+                int [] answerCount = new int [i.getOptions().size()];
+                StringBuffer sb = new StringBuffer() ;
+                JSONArray answerTemp = new JSONArray();
+                JSONObject jsonTemp ;
+                itemJson.put("type",i.getType());
+                switch (i.getType()){
+                    case "Single" :
+                    case "Multiple":
+                        for(ReviewAnswer answer : answers){
+                            for( int ii = 0 ;ii < answer.getAnswers().size();ii++){
+                                answerCount[ii] ++;
+                            }
+                        }
+                        for( int ii =0;ii<i.getOptions().size();ii++){
+                            jsonTemp = new JSONObject();
+                            jsonTemp.put(i.getOptions().get(ii),answerCount[ii]);
+                            answerTemp.put(jsonTemp);
+                        }
+                        break;
+                    case "Description" :
+                        for(ReviewAnswer answer : answers){
+                            sb.append(answer.getAnswers().toString()+"\n");
+                        }
+                        jsonTemp = new JSONObject();
+                        jsonTemp.put(i.getDescription(),sb.toString());
+                        answerTemp.put(jsonTemp);
+                        break;
+                    case "File":
+                        for(ReviewAnswer answer : answers){
+                            sb.append(answer.getFile_url()+"\n");
+                        }
+                        jsonTemp = new JSONObject();
+                        jsonTemp.put(i.getDescription(),sb.toString());
+                        answerTemp.put(jsonTemp);
+                        break;
+                    default:
+                        break;
+                }
+                itemJson.put("answer",answerTemp);
+                itemArray.put(itemJson);
+            }
+            reportJsonInfo.put("checkItem",itemArray);
+            reportInfo.put(reportJsonInfo);
+        }
+        res.put("reportInfo",reportInfo);
+        res.put("jobInfo",new JSONObject(job));
+        return res;
+    }
+
+
 
     public String getExcel (String jobId){
         int rIndex = 0;
@@ -193,4 +280,89 @@ public class ReviewAnalyzeService {
             return null;
         }
     }
+
+    public JSONObject crowdReviewGradeToCrowdTest (String jobId){
+        JSONObject result=new JSONObject();
+        JSONObject updateBugScore=uploadCrowdTestBugGrade(jobId);
+        if("500".equals(updateBugScore.get("status"))){
+            return updateBugScore;
+        }else{
+            ReviewJob reviewJob=reviewJobDao.findJob(jobId);
+            if(reviewJob==null){
+                result.put("status","500");
+                result.put("计算工人分数并上传","不存在该job");
+            }else {
+//                String caseId =reviewJob.getCase_id();
+//                String examId=reviewJob.getExam_id();
+//                String caseTakeId =caseId+"-"+examId;
+                List<ReviewReport> reviewReportList = reviewReportDao.getReportsByPaperId(reviewJob.getPaper_id());
+                Bug bug=bugDao.findByid(reviewReportList.get(0).getOriginal_id());
+                logger.info(bug.getId());
+                logger.info(bug.getCase_take_id());
+                JSONArray json=analyzeService.getScores(bug.getCase_take_id());
+                logger.info(json.toString());
+                result.put("status","200");
+                result.put("计算工人分数并上传","成功");
+                result.put("jsonArray",json.toString());
+            }
+        }
+        return result;
+    }
+
+
+
+    //回写众审结束后的bug分数至bugScore
+    private JSONObject uploadCrowdTestBugGrade(String jobId){
+        ReviewJob reviewJob=reviewJobDao.findJob(jobId);
+        JSONObject result=new JSONObject();
+        if(reviewJob==null){
+            result.put("status","500");
+            result.put("更新bugScore","不存在该job");
+        }else {
+            ReviewPaper reviewPaper = reviewPaperDao.findPaper(reviewJob.getPaper_id());
+            if (reviewPaper.getType().equals("众包测试")) {
+                List<ReviewReport> reviewReportList = reviewReportDao.getReportsByPaperId(reviewJob.getPaper_id());
+                if(reviewReportList==null){
+                    result.put("status","500");
+                    result.put("更新bugScore","该job内不存在report");
+                }else {
+                    //一个report对应一个bug
+                    for (ReviewReport reviewReport : reviewReportList) {
+                        String bugId = reviewReport.getOriginal_id();
+                        List<ReviewItem> reviewItemList = reviewItemDao.findItemsByReport(reviewReport.getId());
+                        //众测转成的众审,item只有一个,单选题,选择得几分
+                        if (reviewItemList != null && reviewItemList.size() == 1) {
+                            ReviewItem reviewItem = reviewItemList.get(0);
+                            if (reviewItem.getType().equals("Single")) {
+                                int allScore = 0;//总分
+                                int count = 0;//共有几人评分
+                                List<ReviewAnswer> reviewAnswerList = reviewAnswerDao.getItemReportJobAnswers(reviewItem.getId(), reviewReport.getId(), jobId);
+                                for (ReviewAnswer reviewAnswer : reviewAnswerList) {
+                                    List<String> answers = reviewAnswer.getAnswers();
+                                    //该题进行了选择
+                                    if (answers != null && answers.size() > 0) {
+                                        for (int i = 0; i < answers.size(); i++) {
+                                            if ("1".equals(answers.get(i))) {
+                                                allScore += i;
+                                                count++;
+                                                break;
+                                            }
+                                        }
+                                    }
+                                }
+                                int grade = allScore / count;
+                                //新建bugScore并保存
+                                BugScore bugScore = new BugScore(bugId, grade, 0);
+                                bugScoreDao.save(bugScore);
+                            }
+                        }
+                    }
+                    result.put("status","200");
+                    result.put("更新bugScore","更新bugScore成功");
+                }
+            }
+        }
+        return result;
+    }
+
 }

+ 11 - 10
src/main/java/edu/nju/service/ReviewJobService.java

@@ -138,17 +138,22 @@ public class ReviewJobService {
         String caseId=jobJsonDTO.getCaseId();
         JSONArray workerList_Array=new JSONArray(jobJsonDTO.getWorker_list());
         String paperUrl=jobJsonDTO.getPaperUrl();
-        System.out.println("基本读取成功");
         List<String>workerList=new ArrayList<>();
         for(int i=0;i<workerList_Array.length();i++){
             workerList.add(String.valueOf(workerList_Array.get(i)));
         }
         MessageVO messageVO=new MessageVO();
+
+        ReviewJob reviewJob=findJobByExamCase(examId,caseId);
+        JSONObject jsonObject=null;
         try {
+            if(reviewJob!=null){
+                reviewPaperService.delPaper(reviewJob.getPaper_id());
+            }
             String paperJson=readStringFromUrl(paperUrl);
             JSONObject paperResult=reviewPaperService.uploadPaper(paperJson);
             System.out.println("paperJson拉成功");
-            if(!paperResult.getString("status").equals("success")){
+            if(!paperResult.getString("status").equals("success")) {
                 messageVO.setStatus("500");
                 messageVO.setMessage("创建paper失败");
                 return messageVO;
@@ -158,17 +163,12 @@ public class ReviewJobService {
             if (examId!=null&&(!examId.equals(""))){
                 crowdSourceToReviewPaperDao.save(new CrowdSourceToReviewPaper(paperId,examId+"-"+caseId,paperUrl));
             }
-            List<ReviewReport>reports=reviewPaperService.getReportsByPaperId(paperId);
-            List<String>reportIds=new ArrayList<>();
-            for(int i=0;i<reports.size();i++){
-                reportIds.add(reports.get(i).getId());
-            }
-            ReviewJob reviewJob=findJobByExamCase(examId,caseId);
-            JSONObject jsonObject=new JSONObject();
+
             if(reviewJob==null) {
                 jsonObject = uploadJob("", examId, caseId, jobName, jobDescription, paperId, startTime, endTime, 0, 0, workerList, "", 0);
             }
-            else {
+            else{
+                reviewPaperService.delPaper(reviewJob.getPaper_id());
                 jsonObject = updateJob(reviewJob.getId(), jobName,jobDescription,paperId,startTime,endTime,0, 0, workerList, "", 0);
             }
             // groupDao.save(new ReviewGroup("default","",workerList,jobId,reportIds));
@@ -194,6 +194,7 @@ public class ReviewJobService {
         reviewJob.setStart_time(startTime);
         reviewJob.setEnd_time(endTime);
         reviewJob.setMax_worker(maxWorker);
+        reviewJob.setPaper_id(paperId);
         jobDao.save(reviewJob);
         groupDao.removeByJob(jobId);
         reviewWorkerDao.removeByJob(jobId);

+ 8 - 0
src/main/java/edu/nju/service/ReviewPaperService.java

@@ -117,6 +117,14 @@ public class ReviewPaperService {
         JSONObject object = new JSONObject();
         try {
             JSONObject jsonObject = new JSONObject(paperJson);
+            if(jsonObject.has("paper_id")){
+                String paperId=jsonObject.getString("paper_id");
+                if(reviewPaperDao.findPaper(paperId)!=null){
+                    object.put("status","success");
+                    object.put("paperId",paperId);
+                    return object;
+                }
+            }
             ReviewPaperVO reviewPaperVO = getReviewPaperVO(jsonObject);
             reviewPaperVO.setCreate_time(Long.toString(System.currentTimeMillis()));
             ReviewPaper reviewPaper = new ReviewPaper(reviewPaperVO);

+ 13 - 5
src/main/java/edu/nju/service/ReviewService.java

@@ -6,8 +6,15 @@ import edu.nju.model.ReviewWorkerVO;
 import edu.nju.util.HTTP;
 import org.json.JSONObject;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.converter.StringHttpMessageConverter;
 import org.springframework.stereotype.Service;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.client.RestTemplate;
 
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -172,7 +179,7 @@ public class ReviewService {
         return reviewReports;
     }
 
-    //回写众审结束后的bug分数
+    //回写众审结束后的bug分数至bugScore
     public void UploadCrowdTestBugGrade(String jobId){
         ReviewJob reviewJob=reviewJobDao.findJob(jobId);
         ReviewPaper reviewPaper=reviewPaperDao.findPaper(reviewJob.getPaper_id());
@@ -181,8 +188,8 @@ public class ReviewService {
             //一个report对应一个bug
             for (ReviewReport reviewReport : reviewReportList) {
                 String bugId = reviewReport.getOriginal_id();
-                Bug bug=bugDao.findByid(bugId);
-                BugScore bugScore=bugScoreDao.findById(bug.getId());
+//                Bug bug=bugDao.findByid(bugId);
+//                BugScore bugScore=bugScoreDao.findById(bug.getId());
                 List<ReviewItem> reviewItemList=reviewItemDao.findItemsByReport(reviewReport.getId());
                 //众测转成的众审,item只有一个,单选题,选择得几分
                 if(reviewItemList!=null&&reviewItemList.size()==1) {
@@ -205,7 +212,9 @@ public class ReviewService {
                             }
                         }
                         int grade=allScore/count;
-                        bugScore.setGrade(grade);
+                        //新建bugScore
+                        BugScore bugScore=new BugScore(bugId,grade,0);
+//                        bugScore.setGrade(grade);
                         bugScoreDao.save(bugScore);
                     }
                 }
@@ -214,7 +223,6 @@ public class ReviewService {
 
     }
 
-
 //    //生成一次众审任务的数据统计报告
 //    public void generateResultStatisticsReport(String jobId){
 //    }

+ 51 - 0
src/main/java/edu/nju/util/AESUtil.java

@@ -0,0 +1,51 @@
+package edu.nju.util;
+
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.net.URLEncoder;
+import java.util.Base64;
+
+public class AESUtil {
+
+    //偏移量
+    private static String IV ="mooctestmooctest";
+    //钥匙
+    private static String KEY = "TESTMOOCTESTMOOC";
+
+    //加密
+    public static String encrypt(String str) {
+        try {
+            byte[] bytes = str.getBytes();
+            IvParameterSpec ivParameterSpec = new IvParameterSpec(IV.getBytes());
+            SecretKeySpec secretKeySpec = new SecretKeySpec(KEY.getBytes(), "AES");
+            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
+            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
+            bytes = cipher.doFinal(bytes);
+            bytes = Base64.getEncoder().encode(bytes);
+            String res  = new String(bytes);
+            return URLEncoder.encode(res);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    //解密
+    public static String decrypt(String str) {
+        try {
+            byte[] bytes = Base64.getDecoder().decode(str);
+            IvParameterSpec ivParameterSpec = new IvParameterSpec(IV.getBytes());
+            SecretKeySpec secretKeySpec = new SecretKeySpec(KEY.getBytes(), "AES");
+            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
+            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
+            bytes = cipher.doFinal(bytes);
+            return new String(bytes);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+}

+ 233 - 61
src/main/java/edu/nju/util/BlockChainAspect.java

@@ -2,14 +2,22 @@ package edu.nju.util;
 
 import edu.nju.dao.BugDao;
 import edu.nju.dao.ReportDao;
+import edu.nju.dao.StuInfoDao;
+import edu.nju.dao.TaskDao;
 import edu.nju.entities.Bug;
 import edu.nju.entities.Report;
+import edu.nju.entities.StuInfo;
+import edu.nju.entities.Task;
 import org.aspectj.lang.JoinPoint;
 import org.aspectj.lang.ProceedingJoinPoint;
 import org.aspectj.lang.annotation.*;
+import org.json.JSONArray;
+import org.json.JSONObject;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
 import javax.servlet.http.HttpServletResponse;
+import java.util.List;
 
 
 /**
@@ -28,6 +36,17 @@ public class BlockChainAspect {
     @Autowired
     ReportDao reportDao;
 
+    @Autowired
+    TaskDao taskDao;
+
+    @Autowired
+    StuInfoDao stuInfoDao;
+
+    private static final String blockChainHost="http://111.231.68.200:8082/";
+
+    @Value("${mooctest.url}")
+    private String MOOCTEST_HOST;
+
 
     /**
      * 定义切入点,切入点为com.example.demo.aop.AopController中的所有函数
@@ -42,34 +61,13 @@ public class BlockChainAspect {
     public void saveBugGrade(){
 
     }
-    /**
-     * @description  在连接点执行之前执行的通知
-     */
-    @Before("saveBugGrade()")
-    public void doBeforeGame(JoinPoint joinPoint){
-        Object[] obj = joinPoint.getArgs();
-        for (Object argItem : obj) {
-            System.out.println("---->now-->argItem:" + argItem);
-        }
-
-    }
-
-    /**
-     * @description  在连接点执行之后执行的通知(返回通知和异常通知的异常)
-     */
-    @After("saveBugGrade()")
-    public void doAfterGame(JoinPoint joinPoint){
-        Object[] obj = joinPoint.getArgs();
-        for (Object argItem : obj) {
-            System.out.println("---->now-->argItem:" + argItem);
-        }
-    }
 
     /**
      * @description  保存bug分数后传递给区块链
      */
     @AfterReturning(value="saveBugGrade()",returning = "keys")
     public void doAfterReturningSaveBugGrade(JoinPoint joinPoint,Object keys){
+        System.out.println("传递给区块链");
         Object[] obj = joinPoint.getArgs();
         for (Object argItem : obj) {
             System.out.println("---->now-->argItem:" + argItem);
@@ -82,57 +80,231 @@ public class BlockChainAspect {
 
         Bug bug=bugDao.findByid(bugId);
         Report report=reportDao.findById(bug.getReport_id());
-        String crowdTestId=report.getCase_take_id();
 
-        String bugReviewerId="default";
+
+
+        String defaultString="慕测管理员";
+
+        JSONObject bugReviewVO=new JSONObject();
+
+        if(report==null){
+            bugReviewVO.put("bugReportId",bugId);
+            bugReviewVO.put("bugReportScore",Integer.parseInt(grade));
+            bugReviewVO.put("reportReviewer",defaultString);
+            bugReviewVO.put("taskId",defaultString);
+            bugReviewVO.put("taskName",defaultString);
+            bugReviewVO.put("testReportId",defaultString);
+            bugReviewVO.put("type",0);
+            bugReviewVO.put("updateTime",System.currentTimeMillis());
+        }else{
+            bugReviewVO.put("bugReportId",bugId);
+            bugReviewVO.put("bugReportScore",Integer.parseInt(grade));
+            bugReviewVO.put("reportReviewer",defaultString);
+            bugReviewVO.put("taskId",report.getCase_take_id());
+
+            Task task=taskDao.findById(report.getTask_id());
+            if(task==null){
+                task=getAndSaveTaskInfo(report.getTask_id());
+                if(task==null){
+                    bugReviewVO.put("taskName",defaultString);
+                }else{
+                    bugReviewVO.put("taskName",task.getName());
+                }
+            }else {
+                bugReviewVO.put("taskName",task.getName());
+            }
+            bugReviewVO.put("testReportId",report.getId());
+            bugReviewVO.put("type",0);
+            bugReviewVO.put("updateTime",System.currentTimeMillis());
+        }
+
+//        System.out.println(bugReviewVO);
+        String url=blockChainHost+"reportReview";
+        try {
+            String result = HTTP.postBody(url, bugReviewVO.toString());
+                    if (!result.equals("")) {
+                        JSONObject resultJson = new JSONObject(result);
+                        System.out.println(resultJson);
+                    }
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+
     }
 
-    /**
-     * @description  上传bug后传递给区块链
-     */
-    @AfterReturning(value="bugSubmit()",returning = "keys")
-    public void doAfterReturningBugSubmit(JoinPoint joinPoint,Object keys){
-        Object[] obj = joinPoint.getArgs();
-        for (Object argItem : obj) {
-            System.out.println("---->now-->argItem:" + argItem);
+    private Task getAndSaveTaskInfo(String id){
+        String result = HTTP.sendGet(MOOCTEST_HOST+"/api/exam/" + id + "/info", "");
+        if (!"".equals(result)) {
+            JSONObject json = new JSONObject(result);
+            long beginTime = json.getLong("beginTime");
+            long endTime = json.getLong("endTime");
+            String name=json.getString("name");
+            double totalMins = (endTime - beginTime) / 1000 / 60.0;
+            Task newTask = new Task(id, name,beginTime, endTime, totalMins, totalMins);
+            taskDao.save(newTask);
+            return newTask;
+        }else{
+            return null;
         }
-        //todo 将该信息传递给区块链服务 如何获得该bugID????
-        //任务ID、缺陷报告hash、缺陷报告 ID、众测工人ID
+    }
 
 
-        String bugId= (String) obj[0];
-        String grade=(String) obj[1];
+    //将一场众测的所有报告上传至区块链
+    public void uploadTestReportInfo(String case_take_id){
+        String defaultString="defaultString";
+        List<Report> reportList=reportDao.findByCaseTakeId(case_take_id);
+        if(reportList!=null){
+            for(Report report:reportList){
+                JSONObject testReportVO=new JSONObject();
+                testReportVO.put("reportHash",defaultString);
+                testReportVO.put("taskId",report.getCase_take_id());
+                Task task=taskDao.findById(report.getTask_id());
+                if(task==null){
+                    task=getAndSaveTaskInfo(report.getTask_id());
+                    if(task==null){
+                        testReportVO.put("taskName",defaultString);
+                    }else{
+                        testReportVO.put("taskName",task.getName());
+                    }
+                }else {
+                    testReportVO.put("taskName",task.getName());
+                }
+                testReportVO.put("testReportId",report.getId());
+                testReportVO.put("testReportName",report.getName());
+                testReportVO.put("type",0);
+                testReportVO.put("updateTime",System.currentTimeMillis());
+                testReportVO.put("workerId",report.getWorker_id());
+                String workerName=stuInfoDao.findWorkerName(report.getId());
+                if(!"null".equals(workerName)){
+                    testReportVO.put("workerName",workerName);
+                }else{
+                    testReportVO.put("workerName",defaultString);
+                }
+                List<Bug> bugList=bugDao.findByReport(report.getId(),case_take_id);
+                JSONArray bugReportList=new JSONArray();
+                for(Bug bug:bugList){
+                    JSONObject bugInfo=new JSONObject();
+                    bugInfo.put("bugId",bug.getId());
+                    bugInfo.put("bugName",bug.getTitle());
+                    bugReportList.put(bugInfo);
+                }
+                testReportVO.put("bugReportList",bugReportList);
+//                System.out.println(testReportVO);
+                String url=blockChainHost+"testReport";
+                try {
+                    String result = HTTP.postBody(url, testReportVO.toString());
+//                    if (!result.equals("")) {
+//                        JSONObject resultJson = new JSONObject(result);
+//                        System.out.println(resultJson);
+//                    }
+                }catch (Exception e){
+                    e.printStackTrace();
+                }
 
-        Bug bug=bugDao.findByid(bugId);
-        Report report=reportDao.findById(bug.getReport_id());
-        String crowdTestId=report.getCase_take_id();
+            }
+        }
+    }
+
+
+    public boolean uploadTestReportInfoToBlockChain(String bug_id){
+        Bug bug=bugDao.findByid(bug_id);
+        String report_id=bug.getReport_id();
+        String defaultString="defaultString";
+        Report report=reportDao.findById(report_id);
+        if(report!=null) {
+            JSONObject testReportVO = new JSONObject();
+            testReportVO.put("reportHash", defaultString);
+            testReportVO.put("taskId", report.getCase_take_id());
+            Task task = taskDao.findById(report.getTask_id());
+            if (task == null) {
+                task = getAndSaveTaskInfo(report.getTask_id());
+                if (task == null) {
+                    testReportVO.put("taskName", defaultString);
+                } else {
+                    testReportVO.put("taskName", task.getName());
+                }
+            } else {
+                testReportVO.put("taskName", task.getName());
+            }
+            testReportVO.put("testReportId", report.getId());
+            testReportVO.put("testReportName", report.getName());
+            testReportVO.put("type", 0);
+            testReportVO.put("updateTime", System.currentTimeMillis());
+            testReportVO.put("workerId", report.getWorker_id());
+            String workerName = stuInfoDao.findWorkerName(report.getId());
+            if (!"null".equals(workerName)) {
+                testReportVO.put("workerName", workerName);
+            } else {
+                testReportVO.put("workerName", defaultString);
+            }
+            List<Bug> bugList = bugDao.findByReport(report.getId(), report.getCase_take_id());
+            JSONArray bugReportList = new JSONArray();
+            JSONObject bugInfo = new JSONObject();
+            bugInfo.put("bugId", bug.getId());
+            bugInfo.put("bugName", bug.getTitle());
+            bugReportList.put(bugInfo);
+            testReportVO.put("bugReportList", bugReportList);
+            String url = blockChainHost + "testReport";
+            try {
+                String result = HTTP.postBody(url, testReportVO.toString());
+                    if (!result.equals("")) {
+                        JSONObject resultJson = new JSONObject(result);
+//                        System.out.println(resultJson);
+//                        System.out.println(resultJson.get("code").toString());
+                        if("200".equals(resultJson.get("code").toString())){
+                            return true;
+                        }else{
+                            return false;
+                        }
 
-        String bugReviewerId="default";
+                    }
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+        return false;
     }
-//
-//    /**
-//     * @description  在连接点执行之后执行的通知(异常通知)
-//     */
-//    @AfterThrowing("BugSubmit()")
-//    public void doAfterThrowingGame(){
-//        System.out.println("异常通知:球迷要求退票!");
-//    }
 
-//    /**
-//     * @description  使用环绕通知
-//     */
-//    @Around("saveBugGrade()")
-//    public void doAroundGameData(ProceedingJoinPoint pjp) throws Throwable {
-//        try{
-//            System.out.println("球星上场前热身!");
-//            pjp.proceed();
-//
-//            System.out.println("球星本场得到" + point + "分" );
-//        }
-//        catch(Throwable e){
-//            System.out.println("异常通知:球迷要求退票!");
+//    public static void main(String[] args){
+//        String url=blockChainHost+"testReport";
+////        String json="{\"workerId\":\"22383\",\"reportHash\":\"defaultString\",\"taskName\":\"12-1众包测试\",\"updateTime\":1585284050330,\"type\":0,\"workerName\":\"李陈龙\",\"testReportName\":\"宋少行\",\"taskId\":\"1281-2724\",\"testReportId\":\"5cbc1a9f825a8960cdc7bd4f\",\"bugReportList\":[{\"bugId\":\"5cbc1b5c825a8960cdc7bd53\",\"bugName\":\"我再测试测试这个单独分离的\"},{\"bugId\":\"5cbc1b37825a8960cdc7bd52\",\"bugName\":\"帮助出错了\"},{\"bugId\":\"5cbc38f9825a8960cdc7bd57\",\"bugName\":\"测试图片能不能上传\"},{\"bugId\":\"5cbc1d31825a8960cdc7bd54\",\"bugName\":\"无法打开最近账薄\"},{\"bugId\":\"5cbc3919825a8960cdc7bd58\",\"bugName\":\"测试图片\"},{\"bugId\":\"5cbc3ab3825a8960cdc7bd5a\",\"bugName\":\"测试fork\"},{\"bugId\":\"5cbc3a50825a8960cdc7bd59\",\"bugName\":\"测试图片上传\"},{\"bugId\":\"5cbc3e9b825a8960cdc7bd5b\",\"bugName\":\"测试一键fork\"},{\"bugId\":\"5cde9be7825a8948e757cac1\",\"bugName\":\"测试下不选择页面会咋样\"},{\"bugId\":\"5cdfa0cc825a8948e757cade\",\"bugName\":\"打开一下就闪退了\"},{\"bugId\":\"5d402ef3f00e7a801b85e472\",\"bugName\":\"账薄有问题\"},{\"bugId\":\"5d7e1ac33c5a507c1c1cda33\",\"bugName\":\"账薄有问题\"},{\"bugId\":\"5d7e1b003c5a507c1c1cda37\",\"bugName\":\"账薄有问题\"},{\"bugId\":\"5d7e1c363c5a507c60f0766d\",\"bugName\":\"账薄有问题\"},{\"bugId\":\"5d7e1d3a3c5a507c9120b76a\",\"bugName\":\"test\"},{\"bugId\":\"5d7e1e1b3c5a507c9120b76f\",\"bugName\":\"继续测试\"},{\"bugId\":\"5d7f4254f52b558caaaee01a\",\"bugName\":\"11\"},{\"bugId\":\"5d7f42e1f52b558cecef1ffd\",\"bugName\":\"222\"},{\"bugId\":\"5dd761e307bcfb195d0dfe56\",\"bugName\":\"test\"},{\"bugId\":\"5df8a2a2eea9d780220b1b24\",\"bugName\":\"mm\"},{\"bugId\":\"5df8af01eea9d78664436920\",\"bugName\":\"kkkkk\"},{\"bugId\":\"5df9e097336bd0ad48b598b2\",\"bugName\":\"cninvorm o\"},{\"bugId\":\"5e463a89709308afcfb15a2c\",\"bugName\":\"。。。。\"}]}";
+////        String json="{\"workerId\":\"22383\",\"reportHash\":\"defaultString\",\"taskName\":\"12-1众包测试\",\"updateTime\":1585284050330,\"type\":0,\"workerName\":\"李陈龙\",\"testReportName\":\"宋少行\",\"taskId\":\"1281-2724\",\"testReportId\":\"5cbc1a9f825a8960cdc7bd4f\",\"bugReportList\":[{\"bugId\":\"5cbc1b5c825a8960cdc7bd53\",\"bugName\":\"我再测试测试这个单独分离的\"},{\"bugId\":\"5cbc1b37825a8960cdc7bd52\",\"bugName\":\"帮助出错了\"},{\"bugId\":\"5cbc38f9825a8960cdc7bd57\",\"bugName\":\"测试图片能不能上传\"},{\"bugId\":\"5cbc1d31825a8960cdc7bd54\",\"bugName\":\"无法打开最近账薄\"},{\"bugId\":\"5cbc3919825a8960cdc7bd58\",\"bugName\":\"测试图片\"},{\"bugId\":\"5cbc3ab3825a8960cdc7bd5a\",\"bugName\":\"测试fork\"},{\"bugId\":\"5cbc3a50825a8960cdc7bd59\",\"bugName\":\"测试图片上传\"},{\"bugId\":\"5cbc3e9b825a8960cdc7bd5b\",\"bugName\":\"测试一键fork\"},{\"bugId\":\"5cde9be7825a8948e757cac1\",\"bugName\":\"测试下不选择页面会咋样\"},{\"bugId\":\"5cdfa0cc825a8948e757cade\",\"bugName\":\"打开一下就闪退了\"},{\"bugId\":\"5d402ef3f00e7a801b85e472\",\"bugName\":\"账薄有问题\"},{\"bugId\":\"5d7e1ac33c5a507c1c1cda33\",\"bugName\":\"账薄有问题\"},{\"bugId\":\"5d7e1b003c5a507c1c1cda37\",\"bugName\":\"账薄有问题\"},{\"bugId\":\"5d7e1c363c5a507c60f0766d\",\"bugName\":\"账薄有问题\"},{\"bugId\":\"5d7e1d3a3c5a507c9120b76a\",\"bugName\":\"test\"},{\"bugId\":\"5d7e1e1b3c5a507c9120b76f\",\"bugName\":\"继续测试\"},{\"bugId\":\"5d7f4254f52b558caaaee01a\",\"bugName\":\"11\"},{\"bugId\":\"5d7f42e1f52b558cecef1ffd\",\"bugName\":\"222\"},{\"bugId\":\"5dd761e307bcfb195d0dfe56\",\"bugName\":\"test\"},{\"bugId\":\"5df8a2a2eea9d780220b1b24\",\"bugName\":\"mm\"},{\"bugId\":\"5df8af01eea9d78664436920\",\"bugName\":\"kkkkk\"},{\"bugId\":\"5df9e097336bd0ad48b598b2\",\"bugName\":\"cninvorm o\"},{\"bugId\":\"5e463a89709308afcfb15a2c\",\"bugName\":\"。。。。\"}]}";
+//        String json="{\n" +
+//                "  \"bugReportList\": [\n" +
+//                "    {\n" +
+//                "      \"bugId\": \"string\",\n" +
+//                "      \"bugName\": \"string\"\n" +
+//                "    },\n" +
+//                "   {\n" +
+//                "      \"bugId\": \"string\",\n" +
+//                "      \"bugName\": \"string\"\n" +
+//                "    }\n" +
+//                "\n" +
+//                "  ],\n" +
+//                "  \"reportHash\": \"string\",\n" +
+//                "  \"taskId\": \"string\",\n" +
+//                "  \"taskName\": \"string\",\n" +
+//                "  \"testReportId\": \"string\",\n" +
+//                "  \"testReportName\": \"string\",\n" +
+//                "  \"type\": 0,\n" +
+//                "  \"updateTime\": 0,\n" +
+//                "  \"workerId\": \"string\",\n" +
+//                "  \"workerName\": \"string\"\n" +
+//                "}";
+//        try {
+//            String result = HTTP.postBody(url, json);
+//            if(!result.equals("")){
+//                JSONObject resultJson = new JSONObject(result);
+//                System.out.println(resultJson);
+//            }
+//        }catch (Exception e){
+//            e.printStackTrace();
 //        }
+//
 //    }
 
 
+
+
+
 }

+ 32 - 0
src/main/java/edu/nju/util/DataMaskingUtil.java

@@ -0,0 +1,32 @@
+package edu.nju.util;
+
+import com.google.common.base.Strings;
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * 数据脱敏工具类
+ */
+public class DataMaskingUtil {
+
+    public static String nameMasking(String name){
+        name  = name.trim();
+        if(name.length()<2){
+            return name;
+        }else if(name.length()==2){
+            return name.charAt(0)+"*";
+        }else{
+            int unitLength = name.length()/3;
+            return StringUtils.left(name,unitLength)
+                    .concat(Strings.repeat("*",name.length()-2*unitLength))
+                    .concat(StringUtils.right(name,unitLength));
+        }
+    }
+
+    public static String getDefaultMooctestUrl(){
+        return "http://www.mooctest.net/assets/img/mooctest.png";
+    }
+
+
+
+
+}

+ 8 - 1
src/main/java/edu/nju/util/HTTP.java

@@ -2,6 +2,7 @@ package edu.nju.util;
 
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
+import edu.nju.service.RecommendService;
 import org.json.JSONException;
 
 import java.io.*;
@@ -12,9 +13,13 @@ import java.nio.charset.Charset;
 import java.util.List;
 import java.util.Map;
 import org.apache.commons.io.IOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class HTTP {
 
+    static Logger logger= LoggerFactory.getLogger(RecommendService.class);
+
     /**
      * 向指定URL发送GET方法的请求
      *
@@ -143,6 +148,7 @@ public class HTTP {
     public static boolean sendPut(String host, String url, String param) {
         try {
             String urlNameString = url + "?" + param;
+            logger.info(urlNameString);
             URL realUrl = new URL(urlNameString);
             // 打开和URL之间的连接
             HttpURLConnection connection;
@@ -165,6 +171,7 @@ public class HTTP {
             }
             return true;
         } catch (Exception e) {
+            logger.info("发送put出错");
             System.out.println("发送PUT请求出现异常!" + e);
             e.printStackTrace();
             return false;
@@ -191,7 +198,7 @@ public class HTTP {
             // 获取URLConnection对象对应的输出流
             out = new PrintWriter(conn.getOutputStream());
             // 发送请求参数
-            out.print(JSON.toJSONString(json));
+            out.print(json);
             // flush输出流的缓冲
             out.flush();
             // 定义BufferedReader输入流来读取URL的响应

+ 28 - 0
src/main/java/edu/nju/util/TimeUtil.java

@@ -5,6 +5,15 @@ import java.text.SimpleDateFormat;
 import java.util.Date;
 
 public class TimeUtil {
+
+    private static final String format  = "MM-dd HH:mm:ss";
+    private static final String monthDayHour  = "MM-dd HH:mm";
+    private static final String dayHour = "dd HH:mm";
+    private static final SimpleDateFormat sdf = new SimpleDateFormat(format);
+    private static final SimpleDateFormat monthDayHourFormat = new SimpleDateFormat(monthDayHour);
+    private static final SimpleDateFormat dayHourFormat = new SimpleDateFormat(dayHour);
+    private static final long hourMillisecond = 3600000;
+
     public static Date StringToDate(String datetime){
         SimpleDateFormat sdFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
         Date date = new Date();
@@ -16,4 +25,23 @@ public class TimeUtil {
         }
         return date;
     }
+
+    public static String timeStamp2Date(String seconds) {
+        if (seconds == null || seconds.isEmpty() || seconds.equals("null")) {
+            return "";
+        }
+        return sdf.format(new Date(Long.valueOf(seconds)));
+    }
+
+    public static String timestamp2MonthDayHour(String timestamp,int hourOffset) {
+        if (timestamp == null || timestamp.isEmpty() || timestamp.equals("null")) {
+            return "";
+        }
+        return monthDayHourFormat.format(new Date(Long.valueOf(timestamp)+hourMillisecond*hourOffset));
+    }
+
+    public static String timestamp2DayHour(long timeStamp,int hourOffset){
+        return dayHourFormat.format(new Date(timeStamp+hourMillisecond*hourOffset));
+    }
+
 }

+ 2 - 2
src/main/java/paperjson

@@ -1,8 +1,8 @@
 {
-	"description": "job描述ddd",
+	"description": "job??ddd",
 	"name": "jobname",
 	"create_time":"2019/10/02",
-	"type":"漏洞扫描分析",
+	"type":"??????",
 	"application_url":"url1",
 	"requirement_url":"url2",
 	"item_group_list": [{

+ 2 - 2
src/main/resources/logback.xml

@@ -4,7 +4,7 @@
 
     <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
         <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
-<!--            <fileNamePattern>/back_end/logs/crowdsource-backend.log.%d{yyyy-MM-dd}.log</fileNamePattern>-->
+            <!--<fileNamePattern>/back_end/logs/crowdsource-backend.log.%d{yyyy-MM-dd}.log</fileNamePattern>-->
             <fileNamePattern>./logs/crowdsource-backend.log.%d{yyyy-MM-dd}.log</fileNamePattern>
             <maxHistory>30</maxHistory>
         </rollingPolicy>
@@ -19,7 +19,7 @@
 
     <appender name="recommendAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
         <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
-<!--            <fileNamePattern>/back_end/logs/recommend.log.%d{yyyy-MM-dd}.log</fileNamePattern>-->
+            <!--<fileNamePattern>/back_end/logs/recommend.log.%d{yyyy-MM-dd}.log</fileNamePattern>-->
             <fileNamePattern>./logs/recommend.log.%d{yyyy-MM-dd}.log</fileNamePattern>
         </rollingPolicy>
         <encoder>

+ 12 - 0
src/workerDIstribution

@@ -0,0 +1,12 @@
+{
+	name:"dis1",
+	"description:"des1",
+	"worker":{"worker1","worker2","worker3"},
+	"report":{"rep1","rep2","rep3"}
+},
+{
+    name:"dis2",
+	"description:"des2",
+	"worker":{"worker4","worker5","worker6"},
+	"report":{"rep4","rep5"}
+}

Некоторые файлы не были показаны из-за большого количества измененных файлов