From 2e7753d4b807b0089a5b572b3712f8d7c5b45167 Mon Sep 17 00:00:00 2001 From: Juhi Date: Wed, 11 Jan 2023 01:19:50 +0530 Subject: [PATCH 01/21] changes for redis cache implementation with jedis connection pool --- pom.xml | 19 + sb-cb-ext.iml | 379 ------------------ .../service/AssessmentServiceV2Impl.java | 34 +- .../service/AssessmentUtilServiceV2Impl.java | 12 +- .../java/org/sunbird/cache/RedisCacheMgr.java | 80 ++-- .../cache/service/RedisCacheServiceImpl.java | 4 +- .../common/util/CbExtServerProperties.java | 12 - .../org/sunbird/core/config/RedisConfig.java | 46 +-- .../controller/SearchByController.java | 4 +- .../searchby/service/SearchByService.java | 29 +- .../service/UserRegistrationServiceImpl.java | 8 +- 11 files changed, 166 insertions(+), 461 deletions(-) delete mode 100644 sb-cb-ext.iml diff --git a/pom.xml b/pom.xml index 93d43dec3..92f1cec66 100644 --- a/pom.xml +++ b/pom.xml @@ -171,6 +171,25 @@ poi-ooxml 3.11 + + org.springframework.boot + spring-boot-starter-data-redis + + + io.lettuce + lettuce-core + + + + + redis.clients + jedis + + + org.apache.commons + commons-pool2 + 2.11.1 + diff --git a/sb-cb-ext.iml b/sb-cb-ext.iml deleted file mode 100644 index 9f592f5e6..000000000 --- a/sb-cb-ext.iml +++ /dev/null @@ -1,379 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java b/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java index df6a22f48..268ed73c5 100644 --- a/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java +++ b/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java @@ -1,5 +1,6 @@ package org.sunbird.assessment.service; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.collections.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -48,8 +49,13 @@ public SBApiResponse readAssessment(String assessmentIdentifier, String token) t try { String userId = RequestInterceptor.fetchUserIdFromAccessToken(token); if (userId != null) { - Map assessmentAllDetail = (Map) redisCacheMgr + Map assessmentAllDetail = new HashMap<>(); + String assessment = redisCacheMgr .getCache(Constants.ASSESSMENT_ID + assessmentIdentifier); + if (!ObjectUtils.isEmpty(assessment)) { + assessmentAllDetail = mapper.readValue(assessment, new TypeReference>() { + }); + } boolean isSuccess = true; if (ObjectUtils.isEmpty(assessmentAllDetail)) { Map hierarcyReadApiResponse = getReadHierarchyApiResponse(assessmentIdentifier, token); @@ -80,13 +86,16 @@ public SBApiResponse readQuestionList(Map requestBody, String au List identifierList = getQuestionIdList(requestBody); List questionList = new ArrayList<>(); List newIdentifierList = new ArrayList<>(); - List map = redisCacheMgr.mget(identifierList); - int size = map.size(); - for (int i = 0; i < map.size(); i++) { - if (ObjectUtils.isEmpty(map.get(i))) { - newIdentifierList.add(identifierList.get(i)); - } else { - questionList.add(filterQuestionMapDetail((Map) map.get(i))); + List questions = redisCacheMgr.mget(identifierList); + if (questions!=null) { + int size = questions.size(); + for (int i = 0; i < questions.size(); i++) { + if (ObjectUtils.isEmpty(questions.get(i))) { + newIdentifierList.add(identifierList.get(i)); + } else { + Map question = mapper.readValue(questions.get(i), new TypeReference>(){}); + questionList.add(filterQuestionMapDetail(question)); + } } } if (newIdentifierList.size() > 0) { @@ -116,8 +125,13 @@ public SBApiResponse readQuestionList(Map requestBody, String au public SBApiResponse submitAssessment(Map data, String authUserToken) throws Exception { SBApiResponse outgoingResponse = new SBApiResponse(); String assessmentId = (String) data.get(Constants.IDENTIFIER); - Map assessmentHierarchy = (Map) redisCacheMgr + Map assessmentHierarchy = new HashMap<>(); + String assessment = redisCacheMgr .getCache(Constants.ASSESSMENT_ID + assessmentId); + if (!ObjectUtils.isEmpty(assessment)) { + assessmentHierarchy = mapper.readValue(assessment, new TypeReference>() { + }); + } // logger.info("Submit Assessment: userId: " + userId + ", data: " + // data.toString()); // Check User exists @@ -125,7 +139,7 @@ public SBApiResponse submitAssessment(Map data, String authUserT // throw new BadRequestException("Invalid UserId."); // } String userId = RequestInterceptor.fetchUserIdFromAccessToken(authUserToken); - if (userId != null) { + if (userId != null && !ObjectUtils.isEmpty(assessmentHierarchy)) { Date assessmentStartTime = assessmentRepository.fetchUserAssessmentStartTime(userId, Constants.ASSESSMENT_ID + assessmentId); if (assessmentStartTime != null) { Timestamp submissionTime = new Timestamp(new Date().getTime()); diff --git a/src/main/java/org/sunbird/assessment/service/AssessmentUtilServiceV2Impl.java b/src/main/java/org/sunbird/assessment/service/AssessmentUtilServiceV2Impl.java index e7384b23b..601bf80b2 100644 --- a/src/main/java/org/sunbird/assessment/service/AssessmentUtilServiceV2Impl.java +++ b/src/main/java/org/sunbird/assessment/service/AssessmentUtilServiceV2Impl.java @@ -6,6 +6,8 @@ import java.util.List; import java.util.Map; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; @@ -21,6 +23,9 @@ public class AssessmentUtilServiceV2Impl implements AssessmentUtilServiceV2 { @Autowired RedisCacheMgr redisCacheMgr; + @Autowired + ObjectMapper mapper; + private CbExtLogger logger = new CbExtLogger(getClass().getName()); public static final String QUESTION_TYPE = "qType"; @@ -121,9 +126,12 @@ private Map getQumlAnswers(List questions) throws Except Map ret = new HashMap<>(); for (String questionId : questions) { List correctOption = new ArrayList<>(); - - Map question = (Map) redisCacheMgr + Map question = new HashMap<>(); + String questionString = redisCacheMgr .getCache(Constants.QUESTION_ID + questionId); + if (!ObjectUtils.isEmpty(questionString)) { + question = mapper.readValue(questionString, new TypeReference>(){}); + } if (ObjectUtils.isEmpty(question)) { logger.error(new Exception("Failed to get the answer for question: " + questionId)); // TODO - Need to handle this scenario. diff --git a/src/main/java/org/sunbird/cache/RedisCacheMgr.java b/src/main/java/org/sunbird/cache/RedisCacheMgr.java index 318257200..1acbdac0a 100644 --- a/src/main/java/org/sunbird/cache/RedisCacheMgr.java +++ b/src/main/java/org/sunbird/cache/RedisCacheMgr.java @@ -1,37 +1,44 @@ package org.sunbird.cache; -import java.util.*; -import java.util.concurrent.TimeUnit; - +import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import org.sunbird.common.util.CbExtServerProperties; import org.sunbird.common.util.Constants; import org.sunbird.core.logger.CbExtLogger; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPool; + +import java.util.*; @Component public class RedisCacheMgr { - private static final int cache_ttl = 84600; - @Autowired - private RedisTemplate redisTemplate; + private JedisPool jedisPool; @Autowired CbExtServerProperties cbExtServerProperties; private CbExtLogger logger = new CbExtLogger(getClass().getName()); + public Jedis getJedis() { + try (Jedis jedis = jedisPool.getResource()) { + return jedis; + } + } + public void putCache(String key, Object object) { try { int ttl = cache_ttl; if (!StringUtils.isEmpty(cbExtServerProperties.getRedisTimeout())) { ttl = Integer.parseInt(cbExtServerProperties.getRedisTimeout()); } - redisTemplate.opsForValue().set(Constants.REDIS_COMMON_KEY + key, object); - redisTemplate.expire(Constants.REDIS_COMMON_KEY + key, ttl, TimeUnit.SECONDS); + ObjectMapper objectMapper = new ObjectMapper(); + String data = objectMapper.writeValueAsString(object); + getJedis().set(Constants.REDIS_COMMON_KEY + key, data); + getJedis().expire(Constants.REDIS_COMMON_KEY + key, ttl); logger.info("Cache_key_value " + Constants.REDIS_COMMON_KEY + key + " is saved in redis"); } catch (Exception e) { logger.error(e); @@ -40,7 +47,8 @@ public void putCache(String key, Object object) { public boolean deleteKeyByName(String key) { try { - redisTemplate.delete(Constants.REDIS_COMMON_KEY + key); + key = key.toUpperCase(); + getJedis().del(Constants.REDIS_COMMON_KEY + key); logger.info("Cache_key_value " + Constants.REDIS_COMMON_KEY + key + " is deleted from redis"); return true; } catch (Exception e) { @@ -49,12 +57,12 @@ public boolean deleteKeyByName(String key) { } } - public boolean deleteAllCBExtKey() { + public boolean deleteAllKey() { try { String keyPattern = Constants.REDIS_COMMON_KEY + "*"; - Set keys = redisTemplate.keys(keyPattern); + Set keys = getJedis().keys(keyPattern); for (String key : keys) { - redisTemplate.delete(key); + getJedis().del(key); } logger.info("All Keys starts with " + Constants.REDIS_COMMON_KEY + " is deleted from redis"); return true; @@ -64,34 +72,56 @@ public boolean deleteAllCBExtKey() { } } - public Object getCache(String key) { + public String getCache(String key) { try { - return redisTemplate.opsForValue().get(Constants.REDIS_COMMON_KEY + key); + return getJedis().get(Constants.REDIS_COMMON_KEY + key); } catch (Exception e) { logger.error(e); return null; } } - public List mget(List fields) { + + + public List mget(List fields) { try { List ls = new ArrayList<>(); for (int i = 0; i < fields.size(); i++) { - ls.add(Constants.REDIS_COMMON_KEY + Constants.QUESTION_ID + fields.get(i)); + ls.add(Constants.REDIS_COMMON_KEY + Constants.QUESTION_ID + fields.get(i)); } - Collection questionIdList = ls; - return redisTemplate.opsForValue().multiGet(questionIdList); + String[] keysForRedis = ls.toArray(new String[ls.size()]); + return getJedis().mget(keysForRedis); } catch (Exception e) { logger.error(e); } return null; } - public Set getAllKeyNames() { + public boolean deleteCache() { + try { + String keyPattern = "*"; + Set keys = getJedis().keys(keyPattern); + if (!keys.isEmpty()) { + for (String key : keys) { + getJedis().del(key); + } + logger.info("All Keys in Redis Cache is Deleted"); + return true; + } else { + return false; + } + } catch (Exception e) { + logger.error(e); + return false; + } + } + + public Set getAllKeys() { Set keys = null; try { - String keyPattern = Constants.REDIS_COMMON_KEY + "*"; - keys = redisTemplate.keys(keyPattern); + String keyPattern = "*"; + keys = getJedis().keys(keyPattern); + } catch (Exception e) { logger.error(e); return Collections.emptySet(); @@ -102,13 +132,13 @@ public Set getAllKeyNames() { public List> getAllKeysAndValues() { List> result = new ArrayList>(); try { - String keyPattern = Constants.REDIS_COMMON_KEY + "*"; + String keyPattern = "*"; Map res = new HashMap<>(); - Set keys = redisTemplate.keys(keyPattern); + Set keys = getJedis().keys(keyPattern); if (!keys.isEmpty()) { for (String key : keys) { Object entries; - entries = redisTemplate.opsForValue().get(key); + entries = getJedis().get(key); res.put(key, entries); } result.add(res); diff --git a/src/main/java/org/sunbird/cache/service/RedisCacheServiceImpl.java b/src/main/java/org/sunbird/cache/service/RedisCacheServiceImpl.java index 8e47db0be..56aef60dc 100644 --- a/src/main/java/org/sunbird/cache/service/RedisCacheServiceImpl.java +++ b/src/main/java/org/sunbird/cache/service/RedisCacheServiceImpl.java @@ -23,7 +23,7 @@ public class RedisCacheServiceImpl implements RedisCacheService { @Override public SBApiResponse deleteCache() throws Exception { SBApiResponse response = new SBApiResponse(Constants.API_REDIS_DELETE); - boolean res = redisCache.deleteAllCBExtKey(); + boolean res = redisCache.deleteAllKey(); if (res) { response.getParams().setStatus(Constants.SUCCESSFUL); response.setResponseCode(HttpStatus.OK); @@ -39,7 +39,7 @@ public SBApiResponse deleteCache() throws Exception { @Override public SBApiResponse getKeys() throws Exception { SBApiResponse response = new SBApiResponse(Constants.API_REDIS_GET_KEYS); - Set res = redisCache.getAllKeyNames(); + Set res = redisCache.getAllKeys(); if (!res.isEmpty()) { logger.info("All Keys in Redis Cache is Fetched"); response.getParams().setStatus(Constants.SUCCESSFUL); diff --git a/src/main/java/org/sunbird/common/util/CbExtServerProperties.java b/src/main/java/org/sunbird/common/util/CbExtServerProperties.java index 8c56b252b..75c47f334 100644 --- a/src/main/java/org/sunbird/common/util/CbExtServerProperties.java +++ b/src/main/java/org/sunbird/common/util/CbExtServerProperties.java @@ -194,9 +194,6 @@ public class CbExtServerProperties { @Value("${redis.host.name}") private String redisHostName; - @Value("${redis.port}") - private String redisPort; - @Value("${redis.timeout}") private String redisTimeout; @@ -753,15 +750,6 @@ public String getCourseBatchCreateEndpoint() { public void setCourseBatchCreateEndpoint(String courseBatchCreateEndpoint) { this.courseBatchCreateEndpoint = courseBatchCreateEndpoint; } - - public String getRedisPort() { - return redisPort; - } - - public void setRedisPort(String redisPort) { - this.redisPort = redisPort; - } - public String getRedisHostName() { return redisHostName; } diff --git a/src/main/java/org/sunbird/core/config/RedisConfig.java b/src/main/java/org/sunbird/core/config/RedisConfig.java index 9ffad7d7c..4290f5b8a 100644 --- a/src/main/java/org/sunbird/core/config/RedisConfig.java +++ b/src/main/java/org/sunbird/core/config/RedisConfig.java @@ -4,12 +4,11 @@ import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.connection.RedisStandaloneConfiguration; -import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; -import org.springframework.data.redis.serializer.StringRedisSerializer; import org.sunbird.common.util.CbExtServerProperties; +import redis.clients.jedis.JedisPool; +import redis.clients.jedis.JedisPoolConfig; + +import java.time.Duration; @Configuration @EnableCaching @@ -18,25 +17,26 @@ public class RedisConfig { @Autowired CbExtServerProperties cbProperties; - @Bean - public JedisConnectionFactory jedisConnectionFactory() { - RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(); - redisStandaloneConfiguration.setHostName(cbProperties.getRedisHostName()); - redisStandaloneConfiguration.setPort(Integer.parseInt(cbProperties.getRedisPort())); - - JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(redisStandaloneConfiguration); - return jedisConnectionFactory; + public JedisPoolConfig buildPoolConfig() { + final JedisPoolConfig poolConfig = new JedisPoolConfig(); + poolConfig.setMaxIdle(128); + poolConfig.setMaxTotal(3000); + poolConfig.setMinIdle(100); + poolConfig.setTestOnBorrow(true); + poolConfig.setTestOnReturn(true); + poolConfig.setTestWhileIdle(true); + poolConfig.setMinEvictableIdleTimeMillis(120000); + poolConfig.setTimeBetweenEvictionRunsMillis(30000); + poolConfig.setNumTestsPerEvictionRun(3); + poolConfig.setBlockWhenExhausted(true); + return poolConfig; } @Bean - public RedisTemplate redisTemplate() { - RedisTemplate redisTemplate = new RedisTemplate<>(); - redisTemplate.setConnectionFactory(jedisConnectionFactory()); - redisTemplate.setKeySerializer(new StringRedisSerializer()); - redisTemplate.setHashKeySerializer(new JdkSerializationRedisSerializer()); - redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer()); - redisTemplate.setEnableTransactionSupport(true); - redisTemplate.afterPropertiesSet(); - return redisTemplate; + public JedisPool jedisPool() + { + final JedisPoolConfig poolConfig = buildPoolConfig(); + JedisPool jedisPool = new JedisPool(poolConfig, cbProperties.getRedisHostName()); + return jedisPool; } -} +} \ No newline at end of file diff --git a/src/main/java/org/sunbird/searchby/controller/SearchByController.java b/src/main/java/org/sunbird/searchby/controller/SearchByController.java index 38546cada..b33cda4c4 100644 --- a/src/main/java/org/sunbird/searchby/controller/SearchByController.java +++ b/src/main/java/org/sunbird/searchby/controller/SearchByController.java @@ -10,6 +10,8 @@ import org.sunbird.common.util.Constants; import org.sunbird.searchby.service.SearchByService; +import java.io.IOException; + @RestController public class SearchByController { @@ -29,7 +31,7 @@ public ResponseEntity browseByProvider(@RequestHeader(Constants.X_AUTH_TOKEN) } @GetMapping("/v1/listPositions") - public ResponseEntity listPositions(@RequestHeader(Constants.X_AUTH_TOKEN) String userToken) { + public ResponseEntity listPositions(@RequestHeader(Constants.X_AUTH_TOKEN) String userToken) throws IOException { FracApiResponse response = searchByService.listPositions(userToken); return new ResponseEntity<>(response, HttpStatus.valueOf(response.getStatusInfo().getStatusCode())); } diff --git a/src/main/java/org/sunbird/searchby/service/SearchByService.java b/src/main/java/org/sunbird/searchby/service/SearchByService.java index 935c889f5..5245bd074 100644 --- a/src/main/java/org/sunbird/searchby/service/SearchByService.java +++ b/src/main/java/org/sunbird/searchby/service/SearchByService.java @@ -1,5 +1,6 @@ package org.sunbird.searchby.service; +import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -8,6 +9,7 @@ import java.util.List; import java.util.Map; +import com.fasterxml.jackson.core.type.TypeReference; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; @@ -40,12 +42,19 @@ public class SearchByService { @Autowired RedisCacheMgr redisCacheMgr; + @Autowired + ObjectMapper mapper; + @Autowired OutboundRequestHandlerServiceImpl outboundRequestHandlerService; public Collection getCompetencyDetails(String authUserToken) throws Exception { - Map competencyMap = (Map) redisCacheMgr + Map competencyMap = new HashMap<>(); + String competency = redisCacheMgr .getCache(Constants.COMPETENCY_CACHE_NAME); + if (!StringUtils.isEmpty(competency)) { + competencyMap = mapper.readValue(competency, new TypeReference>(){}); + } if (CollectionUtils.isEmpty(competencyMap)) { logger.info("Initializing/Refreshing the Cache Value for Key : " + Constants.COMPETENCY_CACHE_NAME); @@ -56,9 +65,13 @@ public Collection getCompetencyDetails(String authUserToken) thr } public Collection getProviderDetails(String authUserToken) throws Exception { - Map providerMap = (Map) redisCacheMgr + Map providerMap = new HashMap<>(); + String provider = redisCacheMgr .getCache(Constants.PROVIDER_CACHE_NAME); - + if (!StringUtils.isEmpty(provider)) { + providerMap = mapper.readValue(provider, new TypeReference>() { + }); + } if (CollectionUtils.isEmpty(providerMap)) { logger.info("Initializing/Refreshing the Cache Value for Key : " + Constants.PROVIDER_CACHE_NAME); providerMap = updateProviderDetails(authUserToken); @@ -66,13 +79,17 @@ public Collection getProviderDetails(String authUserToken) throws return providerMap.values(); } - public FracApiResponse listPositions(String userToken) { + public FracApiResponse listPositions(String userToken) throws IOException { FracApiResponse response = new FracApiResponse(); response.setStatusInfo(new FracStatusInfo()); response.getStatusInfo().setStatusCode(HttpStatus.OK.value()); - - Map> positionMap = (Map>) redisCacheMgr + Map> positionMap = new HashMap<>(); + String positions = redisCacheMgr .getCache(Constants.POSITIONS_CACHE_NAME); + if (!StringUtils.isEmpty(positions)) { + positionMap = mapper.readValue(positions, new TypeReference>>() { + }); + } if (ObjectUtils.isEmpty(positionMap) || CollectionUtils.isEmpty(positionMap.get(Constants.POSITIONS_CACHE_NAME))) { logger.info("Initializing / Refreshing the Cache value for key : " + Constants.POSITIONS_CACHE_NAME); diff --git a/src/main/java/org/sunbird/user/registration/service/UserRegistrationServiceImpl.java b/src/main/java/org/sunbird/user/registration/service/UserRegistrationServiceImpl.java index 592cd9924..e8a18ae4d 100644 --- a/src/main/java/org/sunbird/user/registration/service/UserRegistrationServiceImpl.java +++ b/src/main/java/org/sunbird/user/registration/service/UserRegistrationServiceImpl.java @@ -13,6 +13,7 @@ import java.util.Set; import java.util.regex.Pattern; +import com.fasterxml.jackson.core.type.TypeReference; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.RandomStringUtils; import org.apache.commons.lang.StringUtils; @@ -169,8 +170,13 @@ public SBApiResponse getDeptDetails() { SBApiResponse response = createDefaultResponse(Constants.USER_REGISTRATION_DEPT_INFO_API); try { - Map> deptListMap = (Map>) redisCacheMgr + Map> deptListMap = new HashMap<>(); + String deptListMapString = redisCacheMgr .getCache(Constants.DEPARTMENT_LIST_CACHE_NAME); + if (!ObjectUtils.isEmpty(deptListMapString)) { + deptListMap = mapper.readValue(deptListMapString, new TypeReference>>() { + }); + } List orgList = null; if (ObjectUtils.isEmpty(deptListMap) || CollectionUtils.isEmpty(deptListMap.get(Constants.DEPARTMENT_LIST_CACHE_NAME))) { From 261d1598b983105c26ca704801002468ff62d258 Mon Sep 17 00:00:00 2001 From: Juhi Date: Wed, 11 Jan 2023 01:27:21 +0530 Subject: [PATCH 02/21] changes for redis cache implementation with jedis connection pool --- src/main/java/org/sunbird/cache/RedisCacheMgr.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/sunbird/cache/RedisCacheMgr.java b/src/main/java/org/sunbird/cache/RedisCacheMgr.java index 1acbdac0a..bdb520f60 100644 --- a/src/main/java/org/sunbird/cache/RedisCacheMgr.java +++ b/src/main/java/org/sunbird/cache/RedisCacheMgr.java @@ -119,7 +119,7 @@ public boolean deleteCache() { public Set getAllKeys() { Set keys = null; try { - String keyPattern = "*"; + String keyPattern = Constants.REDIS_COMMON_KEY + "*"; keys = getJedis().keys(keyPattern); } catch (Exception e) { @@ -132,7 +132,7 @@ public Set getAllKeys() { public List> getAllKeysAndValues() { List> result = new ArrayList>(); try { - String keyPattern = "*"; + String keyPattern = Constants.REDIS_COMMON_KEY + "*"; Map res = new HashMap<>(); Set keys = getJedis().keys(keyPattern); if (!keys.isEmpty()) { From 98af8784ee9fa6907380681bb8752012939a9849 Mon Sep 17 00:00:00 2001 From: Juhi Date: Wed, 11 Jan 2023 12:14:08 +0530 Subject: [PATCH 03/21] changes for redis cache implementation with jedis connection pool~ --- pom.xml | 11 ----------- src/main/java/org/sunbird/cache/RedisCacheMgr.java | 2 +- .../sunbird/cache/service/RedisCacheServiceImpl.java | 2 +- 3 files changed, 2 insertions(+), 13 deletions(-) diff --git a/pom.xml b/pom.xml index 92f1cec66..93382af23 100644 --- a/pom.xml +++ b/pom.xml @@ -174,22 +174,11 @@ org.springframework.boot spring-boot-starter-data-redis - - - io.lettuce - lettuce-core - - redis.clients jedis - - org.apache.commons - commons-pool2 - 2.11.1 - diff --git a/src/main/java/org/sunbird/cache/RedisCacheMgr.java b/src/main/java/org/sunbird/cache/RedisCacheMgr.java index bdb520f60..48140b1b7 100644 --- a/src/main/java/org/sunbird/cache/RedisCacheMgr.java +++ b/src/main/java/org/sunbird/cache/RedisCacheMgr.java @@ -57,7 +57,7 @@ public boolean deleteKeyByName(String key) { } } - public boolean deleteAllKey() { + public boolean deleteAllCBExtKey() { try { String keyPattern = Constants.REDIS_COMMON_KEY + "*"; Set keys = getJedis().keys(keyPattern); diff --git a/src/main/java/org/sunbird/cache/service/RedisCacheServiceImpl.java b/src/main/java/org/sunbird/cache/service/RedisCacheServiceImpl.java index 56aef60dc..f1ba632f5 100644 --- a/src/main/java/org/sunbird/cache/service/RedisCacheServiceImpl.java +++ b/src/main/java/org/sunbird/cache/service/RedisCacheServiceImpl.java @@ -23,7 +23,7 @@ public class RedisCacheServiceImpl implements RedisCacheService { @Override public SBApiResponse deleteCache() throws Exception { SBApiResponse response = new SBApiResponse(Constants.API_REDIS_DELETE); - boolean res = redisCache.deleteAllKey(); + boolean res = redisCache.deleteAllCBExtKey(); if (res) { response.getParams().setStatus(Constants.SUCCESSFUL); response.setResponseCode(HttpStatus.OK); From f1757553e2b1fe5b7f581a87692482171e119f0c Mon Sep 17 00:00:00 2001 From: Juhi Date: Wed, 11 Jan 2023 12:42:04 +0530 Subject: [PATCH 04/21] changes for redis cache implementation with jedis connection pool~ --- pom.xml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pom.xml b/pom.xml index 93382af23..a0501d899 100644 --- a/pom.xml +++ b/pom.xml @@ -171,10 +171,6 @@ poi-ooxml 3.11 - - org.springframework.boot - spring-boot-starter-data-redis - redis.clients jedis From a678c10620f744a7fa88242a78f4da11a9fa1c94 Mon Sep 17 00:00:00 2001 From: Juhi Date: Mon, 16 Jan 2023 19:19:46 +0530 Subject: [PATCH 05/21] canges to merge redis and assessment code --- .../controller/AssessmentController.java | 10 +- .../sunbird/assessment/model/Competency.java | 196 ++++ .../assessment/repo/AssessmentRepository.java | 19 +- .../repo/AssessmentRepositoryImpl.java | 69 +- .../service/AssessmentServiceV2.java | 2 + .../service/AssessmentServiceV2Impl.java | 970 +++++++++++++----- .../service/AssessmentUtilServiceV2.java | 8 + .../service/AssessmentUtilServiceV2Impl.java | 329 ++++-- .../common/util/CbExtServerProperties.java | 57 + .../org/sunbird/common/util/Constants.java | 63 +- 10 files changed, 1332 insertions(+), 391 deletions(-) create mode 100644 src/main/java/org/sunbird/assessment/model/Competency.java diff --git a/src/main/java/org/sunbird/assessment/controller/AssessmentController.java b/src/main/java/org/sunbird/assessment/controller/AssessmentController.java index ec5b3bb08..c2bd3056c 100644 --- a/src/main/java/org/sunbird/assessment/controller/AssessmentController.java +++ b/src/main/java/org/sunbird/assessment/controller/AssessmentController.java @@ -147,6 +147,12 @@ public ResponseEntity readQuestionList(@Valid @RequestBody Map(response, response.getResponseCode()); } - // QUML based Assessment APIs - // ======================= + + @GetMapping("/v1/quml/assessment/retake/{assessmentIdentifier}") + public ResponseEntity retakeAssessment( + @PathVariable("assessmentIdentifier") String assessmentIdentifier, + @RequestHeader(Constants.X_AUTH_TOKEN) String token) throws Exception { + SBApiResponse readResponse = assessmentServiceV2.retakeAssessment(assessmentIdentifier, token); + return new ResponseEntity<>(readResponse, readResponse.getResponseCode()); + } } diff --git a/src/main/java/org/sunbird/assessment/model/Competency.java b/src/main/java/org/sunbird/assessment/model/Competency.java new file mode 100644 index 000000000..ba505aff3 --- /dev/null +++ b/src/main/java/org/sunbird/assessment/model/Competency.java @@ -0,0 +1,196 @@ +package org.sunbird.assessment.model; + +import javax.annotation.Generated; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({ +"id", +"name", +"description", +"competencyType", +"competencyArea", +"source", +"selectedLevelId", +"selectedLevelLevel", +"selectedLevelName", +"selectedLevelDescription" +}) +public class Competency { + +@JsonProperty("id") +private String id; +@JsonProperty("name") +private String name; +@JsonProperty("description") +private String description; +@JsonProperty("competencyType") +private String competencyType; +@JsonProperty("competencyArea") +private String competencyArea; +@JsonProperty("source") +private String source; +@JsonProperty("selectedLevelId") +private String selectedLevelId; +@JsonProperty("selectedLevelLevel") +private String selectedLevelLevel; +@JsonProperty("selectedLevelName") +private String selectedLevelName; +@JsonProperty("selectedLevelDescription") +private String selectedLevelDescription; + +@JsonProperty("id") +public String getId() { +return id; +} + +@JsonProperty("id") +public void setId(String id) { +this.id = id; +} + +@JsonProperty("name") +public String getName() { +return name; +} + +@JsonProperty("name") +public void setName(String name) { +this.name = name; +} + +@JsonProperty("description") +public String getDescription() { +return description; +} + +@JsonProperty("description") +public void setDescription(String description) { +this.description = description; +} + +@JsonProperty("competencyType") +public String getCompetencyType() { +return competencyType; +} + +@JsonProperty("competencyType") +public void setCompetencyType(String competencyType) { +this.competencyType = competencyType; +} + +@JsonProperty("competencyArea") +public String getCompetencyArea() { +return competencyArea; +} + +@JsonProperty("competencyArea") +public void setCompetencyArea(String competencyArea) { +this.competencyArea = competencyArea; +} + +@JsonProperty("source") +public String getSource() { +return source; +} + +@JsonProperty("source") +public void setSource(String source) { +this.source = source; +} + +@JsonProperty("selectedLevelId") +public String getSelectedLevelId() { +return selectedLevelId; +} + +@JsonProperty("selectedLevelId") +public void setSelectedLevelId(String selectedLevelId) { +this.selectedLevelId = selectedLevelId; +} + +@JsonProperty("selectedLevelLevel") +public String getSelectedLevelLevel() { +return selectedLevelLevel; +} + +@JsonProperty("selectedLevelLevel") +public void setSelectedLevelLevel(String selectedLevelLevel) { +this.selectedLevelLevel = selectedLevelLevel; +} + +@JsonProperty("selectedLevelName") +public String getSelectedLevelName() { +return selectedLevelName; +} + +@JsonProperty("selectedLevelName") +public void setSelectedLevelName(String selectedLevelName) { +this.selectedLevelName = selectedLevelName; +} + +@JsonProperty("selectedLevelDescription") +public String getSelectedLevelDescription() { +return selectedLevelDescription; +} + +@JsonProperty("selectedLevelDescription") +public void setSelectedLevelDescription(String selectedLevelDescription) { +this.selectedLevelDescription = selectedLevelDescription; +} + +@Override +public String toString() { +StringBuilder sb = new StringBuilder(); +sb.append(Competency.class.getName()).append('@').append(Integer.toHexString(System.identityHashCode(this))).append('['); +sb.append("id"); +sb.append('='); +sb.append(((this.id == null)?"":this.id)); +sb.append(','); +sb.append("name"); +sb.append('='); +sb.append(((this.name == null)?"":this.name)); +sb.append(','); +sb.append("description"); +sb.append('='); +sb.append(((this.description == null)?"":this.description)); +sb.append(','); +sb.append("competencyType"); +sb.append('='); +sb.append(((this.competencyType == null)?"":this.competencyType)); +sb.append(','); +sb.append("competencyArea"); +sb.append('='); +sb.append(((this.competencyArea == null)?"":this.competencyArea)); +sb.append(','); +sb.append("source"); +sb.append('='); +sb.append(((this.source == null)?"":this.source)); +sb.append(','); +sb.append("selectedLevelId"); +sb.append('='); +sb.append(((this.selectedLevelId == null)?"":this.selectedLevelId)); +sb.append(','); +sb.append("selectedLevelLevel"); +sb.append('='); +sb.append(((this.selectedLevelLevel == null)?"":this.selectedLevelLevel)); +sb.append(','); +sb.append("selectedLevelName"); +sb.append('='); +sb.append(((this.selectedLevelName == null)?"":this.selectedLevelName)); +sb.append(','); +sb.append("selectedLevelDescription"); +sb.append('='); +sb.append(((this.selectedLevelDescription == null)?"":this.selectedLevelDescription)); +sb.append(','); +if (sb.charAt((sb.length()- 1)) == ',') { +sb.setCharAt((sb.length()- 1), ']'); +} else { +sb.append(']'); +} +return sb.toString(); +} + +} \ No newline at end of file diff --git a/src/main/java/org/sunbird/assessment/repo/AssessmentRepository.java b/src/main/java/org/sunbird/assessment/repo/AssessmentRepository.java index 9895962df..62891dc70 100644 --- a/src/main/java/org/sunbird/assessment/repo/AssessmentRepository.java +++ b/src/main/java/org/sunbird/assessment/repo/AssessmentRepository.java @@ -11,7 +11,7 @@ public interface AssessmentRepository { /** * gets answer key for the assessment given the url - * + * * @param artifactUrl * @return * @throws Exception @@ -20,7 +20,7 @@ public interface AssessmentRepository { /** * gets answerkey for the quiz submission - * + * * @param quizMap * @return * @throws Exception @@ -29,7 +29,7 @@ public interface AssessmentRepository { /** * inserts quiz or assessments for a user - * + * * @param persist * @param isAssessment * @return @@ -40,7 +40,7 @@ public Map insertQuizOrAssessment(Map persist, B /** * gets assessment for a user given a content id - * + * * @param courseId * @param userId * @return @@ -49,7 +49,12 @@ public Map insertQuizOrAssessment(Map persist, B public List> getAssessmentbyContentUser(String rootOrg, String courseId, String userId) throws Exception; - boolean addUserAssesmentStartTime(String userId, String assessmentIdentifier, Timestamp startTime); + List> fetchUserAssessmentDataFromDB(String userId, String assessmentIdentifier); - Date fetchUserAssessmentStartTime(String userId, String s); -} + boolean addUserAssesmentDataToDB(String userId, String assessmentId, Timestamp startTime, Timestamp endTime, + Map questionSet, String status); + + Boolean updateUserAssesmentDataToDB(String userId, String assessmentIdentifier, + Map submitAssessmentRequest, Map submitAssessmentResponse, String status, + Date startTime); +} \ No newline at end of file diff --git a/src/main/java/org/sunbird/assessment/repo/AssessmentRepositoryImpl.java b/src/main/java/org/sunbird/assessment/repo/AssessmentRepositoryImpl.java index f3575b006..7092c5a56 100644 --- a/src/main/java/org/sunbird/assessment/repo/AssessmentRepositoryImpl.java +++ b/src/main/java/org/sunbird/assessment/repo/AssessmentRepositoryImpl.java @@ -1,6 +1,14 @@ package org.sunbird.assessment.repo; -import com.datastax.driver.core.utils.UUIDs; +import java.math.BigDecimal; +import java.sql.Timestamp; +import java.text.SimpleDateFormat; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.sunbird.assessment.dto.AssessmentSubmissionDTO; @@ -9,10 +17,8 @@ import org.sunbird.common.util.Constants; import org.sunbird.core.logger.CbExtLogger; -import java.math.BigDecimal; -import java.sql.Timestamp; -import java.text.SimpleDateFormat; -import java.util.*; +import com.datastax.driver.core.utils.UUIDs; +import com.google.gson.Gson; @Service public class AssessmentRepositoryImpl implements AssessmentRepository { @@ -22,7 +28,7 @@ public class AssessmentRepositoryImpl implements AssessmentRepository { public static final String SOURCE_ID = "sourceId"; public static final String USER_ID = "userId"; private CbExtLogger logger = new CbExtLogger(getClass().getName()); - + @Autowired UserAssessmentSummaryRepository userAssessmentSummaryRepo; @@ -128,23 +134,50 @@ public List> getAssessmentbyContentUser(String rootOrg, Stri } @Override - public boolean addUserAssesmentStartTime(String userId, String assessmentIdentifier, Timestamp startTime) { + public boolean addUserAssesmentDataToDB(String userId, String assessmentIdentifier, Timestamp startTime, + Timestamp endTime, Map questionSet, String status) { Map request = new HashMap<>(); request.put(Constants.USER_ID, userId); - request.put(Constants.IDENTIFIER, assessmentIdentifier); - cassandraOperation.deleteRecord(Constants.KEYSPACE_SUNBIRD, Constants.TABLE_USER_ASSESSMENT_TIME, request); - request.put("starttime", startTime); - SBApiResponse resp = cassandraOperation.insertRecord(Constants.KEYSPACE_SUNBIRD, Constants.TABLE_USER_ASSESSMENT_TIME, request); + request.put(Constants.ASSESSMENT_ID_KEY, assessmentIdentifier); + request.put(Constants.START_TIME, startTime); + request.put(Constants.END_TIME, endTime); + request.put(Constants.ASSESSMENT_READ_RESPONSE, new Gson().toJson(questionSet)); + request.put(Constants.STATUS, status); + SBApiResponse resp = cassandraOperation.insertRecord(Constants.KEYSPACE_SUNBIRD, + Constants.TABLE_USER_ASSESSMENT_DATA, request); return resp.get(Constants.RESPONSE).equals(Constants.SUCCESS); } - @Override - public Date fetchUserAssessmentStartTime(String userId, String assessmentIdentifier) { + @Override + public List> fetchUserAssessmentDataFromDB(String userId, String assessmentIdentifier) { Map request = new HashMap<>(); request.put(Constants.USER_ID, userId); - request.put(Constants.IDENTIFIER, assessmentIdentifier); - Map existingDataList = cassandraOperation.getRecordsByProperties(Constants.KEYSPACE_SUNBIRD, - Constants.TABLE_USER_ASSESSMENT_TIME, request, null).get(0); - return (Date) existingDataList.get("starttime"); + request.put(Constants.ASSESSMENT_ID_KEY, assessmentIdentifier); + List> existingDataList = cassandraOperation.getRecordsByProperties( + Constants.KEYSPACE_SUNBIRD, Constants.TABLE_USER_ASSESSMENT_DATA, request, null); + return existingDataList; + } + + @Override + public Boolean updateUserAssesmentDataToDB(String userId, String assessmentIdentifier, + Map submitAssessmentRequest, Map submitAssessmentResponse, String status, + Date startTime) { + Map compositeKeys = new HashMap<>(); + compositeKeys.put(Constants.USER_ID, userId); + compositeKeys.put(Constants.ASSESSMENT_ID_KEY, assessmentIdentifier); + compositeKeys.put(Constants.START_TIME, startTime); + Map fieldsToBeUpdated = new HashMap<>(); + if (!submitAssessmentRequest.isEmpty()) { + fieldsToBeUpdated.put("submitassessmentrequest", new Gson().toJson(submitAssessmentRequest)); + } + if (!submitAssessmentResponse.isEmpty()) { + fieldsToBeUpdated.put("submitassessmentresponse", new Gson().toJson(submitAssessmentResponse)); + } + if (!status.isEmpty()) { + fieldsToBeUpdated.put(Constants.STATUS, status); + } + cassandraOperation.updateRecord(Constants.KEYSPACE_SUNBIRD, Constants.TABLE_USER_ASSESSMENT_DATA, + fieldsToBeUpdated, compositeKeys); + return true; } -} +} \ No newline at end of file diff --git a/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2.java b/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2.java index 84a9b3ec0..e6159dbfd 100644 --- a/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2.java +++ b/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2.java @@ -17,4 +17,6 @@ public interface AssessmentServiceV2 { public SBApiResponse readAssessment(String assessmentIdentifier, String token) throws Exception; public SBApiResponse readQuestionList(Map requestBody, String authUserToken) throws Exception; + + public SBApiResponse retakeAssessment(String assessmentIdentifier, String token) throws Exception; } diff --git a/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java b/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java index 268ed73c5..6e6c13678 100644 --- a/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java +++ b/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java @@ -1,8 +1,19 @@ package org.sunbird.assessment.service; +import com.beust.jcommander.internal.Lists; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.base.Predicates; +import com.google.common.collect.Iterables; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.time.DateUtils; +import org.joda.time.DateTime; +import org.mortbay.util.ajax.JSON; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; @@ -10,218 +21,643 @@ import org.sunbird.assessment.repo.AssessmentRepository; import org.sunbird.cache.RedisCacheMgr; import org.sunbird.common.model.SBApiResponse; -import org.sunbird.common.model.SunbirdApiResp; import org.sunbird.common.service.OutboundRequestHandlerServiceImpl; import org.sunbird.common.util.CbExtServerProperties; import org.sunbird.common.util.Constants; import org.sunbird.common.util.RequestInterceptor; -import org.sunbird.core.exception.ApplicationLogicError; -import org.sunbird.core.logger.CbExtLogger; +import org.sunbird.core.producer.Producer; +import java.io.IOException; import java.sql.Timestamp; import java.util.*; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import static java.util.stream.Collectors.toList; + @Service @SuppressWarnings("unchecked") public class AssessmentServiceV2Impl implements AssessmentServiceV2 { - private final CbExtLogger logger = new CbExtLogger(getClass().getName()); - private final ObjectMapper mapper = new ObjectMapper(); + private final Logger logger = LoggerFactory.getLogger(AssessmentServiceV2Impl.class); @Autowired AssessmentUtilServiceV2 assessUtilServ; @Autowired - RedisCacheMgr redisCacheMgr; + CbExtServerProperties serverProperties; + + @Autowired + Producer kafkaProducer; + + @Autowired + AssessmentRepository assessmentRepository; @Autowired - CbExtServerProperties cbExtServerProperties; + RedisCacheMgr redisCacheMgr; @Autowired OutboundRequestHandlerServiceImpl outboundRequestHandlerService; @Autowired - AssessmentRepository assessmentRepository; + ObjectMapper mapper; - public SBApiResponse readAssessment(String assessmentIdentifier, String token) throws Exception { - SBApiResponse response = new SBApiResponse(); + public SBApiResponse readAssessment(String assessmentIdentifier, String token) { + logger.info("AssessmentServiceV2Impl::readAssessment... Started"); + SBApiResponse response = createDefaultResponse(Constants.API_QUESTIONSET_HIERARCHY_GET); + String errMsg; try { - String userId = RequestInterceptor.fetchUserIdFromAccessToken(token); + String userId = validateAuthTokenAndFetchUserId(token); if (userId != null) { + logger.info("readAssessment.. userId :" + userId); Map assessmentAllDetail = new HashMap<>(); - String assessment = redisCacheMgr - .getCache(Constants.ASSESSMENT_ID + assessmentIdentifier); - if (!ObjectUtils.isEmpty(assessment)) { - assessmentAllDetail = mapper.readValue(assessment, new TypeReference>() { - }); - } - boolean isSuccess = true; - if (ObjectUtils.isEmpty(assessmentAllDetail)) { - Map hierarcyReadApiResponse = getReadHierarchyApiResponse(assessmentIdentifier, token); - if (!Constants.OK.equalsIgnoreCase((String) hierarcyReadApiResponse.get(Constants.RESPONSE_CODE))) { - isSuccess = false; + errMsg = fetchReadHierarchyDetails(assessmentAllDetail, token, assessmentIdentifier); + if (errMsg.isEmpty() && !((String) assessmentAllDetail.get(Constants.PRIMARY_CATEGORY)) + .equalsIgnoreCase(Constants.PRACTICE_QUESTION_SET)) { + logger.info("Fetched assessment Details... for : " + assessmentIdentifier); + List> existingDataList = assessmentRepository + .fetchUserAssessmentDataFromDB(userId, assessmentIdentifier); + Timestamp assessmentStartTime = new Timestamp(new Date().getTime()); + if (existingDataList.isEmpty()) { + logger.info("Assessment read first time for user."); + response.getResult().put(Constants.QUESTION_SET, readAssessmentLevelData(assessmentAllDetail)); + redisCacheMgr.putCache(Constants.USER_ASSESS_REQ + assessmentIdentifier + "_" + token, response.getResult().get(Constants.QUESTION_SET)); + int expectedDuration = (Integer) assessmentAllDetail.get(Constants.EXPECTED_DURATION); + Boolean isAssessmentUpdatedToDB = assessmentRepository.addUserAssesmentDataToDB(userId, + assessmentIdentifier, assessmentStartTime, + calculateAssessmentSubmitTime(expectedDuration, assessmentStartTime), + (Map) (response.getResult().get(Constants.QUESTION_SET)), + Constants.NOT_SUBMITTED); + if (Boolean.FALSE.equals(isAssessmentUpdatedToDB)) { + errMsg = Constants.ASSESSMENT_DATA_START_TIME_NOT_UPDATED; + } } else { - assessmentAllDetail = (Map) ((Map) hierarcyReadApiResponse - .get(Constants.RESULT)).get(Constants.QUESTION_SET); - redisCacheMgr.putCache(Constants.ASSESSMENT_ID + assessmentIdentifier, assessmentAllDetail); + logger.info("Assessment read... user has details... "); + Date existingAssessmentEndTime = (Date) (existingDataList.get(0).get(Constants.END_TIME)); + if (assessmentStartTime.compareTo(existingAssessmentEndTime) < 0 && ((String) existingDataList.get(0).get(Constants.STATUS)) + .equalsIgnoreCase(Constants.NOT_SUBMITTED)) { + Map questionSetFromAssessment; + String userQuestionSet = redisCacheMgr + .getCache(Constants.USER_ASSESS_REQ + assessmentIdentifier + "_" + token); + if (!ObjectUtils.isEmpty(userQuestionSet)) { + questionSetFromAssessment = mapper.readValue(userQuestionSet, new TypeReference>() { + }); + } else { + String questionSetFromAssessmentString = (String) existingDataList.get(0) + .get(Constants.ASSESSMENT_READ_RESPONSE); + questionSetFromAssessment = new Gson().fromJson( + questionSetFromAssessmentString, new TypeToken>() { + }.getType()); + redisCacheMgr.putCache(Constants.USER_ASSESS_REQ + assessmentIdentifier + "_" + token, questionSetFromAssessment); + } + response.getResult().put(Constants.QUESTION_SET, questionSetFromAssessment); + } else { + logger.info("Assessment read... adding user data to db..."); + response.getResult().put(Constants.QUESTION_SET, + readAssessmentLevelData(assessmentAllDetail)); + int expectedDuration = (Integer) assessmentAllDetail.get(Constants.EXPECTED_DURATION); + Boolean isAssessmentUpdatedToDB = assessmentRepository.addUserAssesmentDataToDB(userId, + assessmentIdentifier, assessmentStartTime, + calculateAssessmentSubmitTime(expectedDuration, assessmentStartTime), + (Map) (response.getResult().get(Constants.QUESTION_SET)), + Constants.NOT_SUBMITTED); + redisCacheMgr.putCache(Constants.USER_ASSESS_REQ + assessmentIdentifier + "_" + token, response.getResult().get(Constants.QUESTION_SET)); + if (Boolean.FALSE.equals(isAssessmentUpdatedToDB)) { + errMsg = Constants.ASSESSMENT_DATA_START_TIME_NOT_UPDATED; + } + } } + } else if (errMsg.isEmpty() && ((String) assessmentAllDetail.get(Constants.PRIMARY_CATEGORY)) + .equalsIgnoreCase(Constants.PRACTICE_QUESTION_SET)) { + response.getResult().put(Constants.QUESTION_SET, readAssessmentLevelData(assessmentAllDetail)); + redisCacheMgr.putCache(Constants.USER_ASSESS_REQ + assessmentIdentifier + "_" + token, response.getResult().get(Constants.QUESTION_SET)); } - response = prepareAssessmentResponse(assessmentAllDetail, isSuccess); - redisCacheMgr.putCache(Constants.USER_ASSESS_REQ + token, response.getResult().get(Constants.QUESTION_SET)); - if (assessmentAllDetail.get(Constants.DURATION) != null) { - boolean resp = assessmentRepository.addUserAssesmentStartTime(userId, Constants.ASSESSMENT_ID + assessmentIdentifier, new Timestamp(new Date().getTime())); - return response; - } + } else { + errMsg = Constants.USER_ID_DOESNT_EXIST; } } catch (Exception e) { - logger.error(e); - throw new ApplicationLogicError("REQUEST_COULD_NOT_BE_PROCESSED", e); + logger.error(String.format("Exception in %s : %s", "read Assessment", e.getMessage()), e); + errMsg = "Failed to read Assessment. Exception: " + e.getMessage(); + } + if (StringUtils.isNotBlank(errMsg)) { + response.getParams().setStatus(Constants.FAILED); + response.getParams().setErrmsg(errMsg); + response.setResponseCode(HttpStatus.INTERNAL_SERVER_ERROR); } return response; } - public SBApiResponse readQuestionList(Map requestBody, String authUserToken) throws Exception { + public SBApiResponse readQuestionList(Map requestBody, String authUserToken) { + SBApiResponse response = createDefaultResponse(Constants.API_SUBMIT_ASSESSMENT); + String errMsg; + String primaryCategory = ""; + Map result = new HashMap<>(); try { - List identifierList = getQuestionIdList(requestBody); + List identifierList = new ArrayList<>(); List questionList = new ArrayList<>(); - List newIdentifierList = new ArrayList<>(); - List questions = redisCacheMgr.mget(identifierList); - if (questions!=null) { - int size = questions.size(); - for (int i = 0; i < questions.size(); i++) { - if (ObjectUtils.isEmpty(questions.get(i))) { + result = validateQuestionListAPI(requestBody, authUserToken, identifierList); + errMsg = result.get(Constants.ERROR_MESSAGE); + if (errMsg.isEmpty()) { + List newIdentifierList = new ArrayList<>(); + List map = redisCacheMgr.mget(identifierList); + for (int i = 0; i < map.size(); i++) { + if (ObjectUtils.isEmpty(map.get(i))) { newIdentifierList.add(identifierList.get(i)); } else { - Map question = mapper.readValue(questions.get(i), new TypeReference>(){}); - questionList.add(filterQuestionMapDetail(question)); + Map questionString = mapper.readValue(map.get(i), new TypeReference>() { + }); + questionList.add(assessUtilServ.filterQuestionMapDetail(questionString, result.get(Constants.PRIMARY_CATEGORY))); } } - } - if (newIdentifierList.size() > 0) { - Map questionMapResponse = readQuestionDetails(newIdentifierList); - if (questionMapResponse != null && Constants.OK.equalsIgnoreCase((String) questionMapResponse.get(Constants.RESPONSE_CODE))) { - List> questionMap = ((List>) ((Map) questionMapResponse - .get(Constants.RESULT)).get(Constants.QUESTIONS)); - for (Map qmap : questionMap) { - if (!ObjectUtils.isEmpty(questionMap)) { - redisCacheMgr.putCache(Constants.QUESTION_ID + qmap.get(Constants.IDENTIFIER), qmap); - questionList.add(filterQuestionMapDetail(qmap)); - } else { - logger.error(new Exception("Failed to get Question Details for Id: " + qmap.get(Constants.IDENTIFIER))); + if (!newIdentifierList.isEmpty()) { + List> newQuestionList = assessUtilServ.readQuestionDetails(newIdentifierList); + if (!newQuestionList.isEmpty()) { + for (Map questionMap : newQuestionList) { + if (!ObjectUtils.isEmpty(questionMap) && !ObjectUtils.isEmpty(((Map) questionMap.get(Constants.RESULT)) + .get(Constants.QUESTIONS))) { + List> questions = (List>) ((Map) questionMap.get(Constants.RESULT)) + .get(Constants.QUESTIONS); + for (Map question : questions) { + if (!question.isEmpty()) { + redisCacheMgr.putCache(Constants.QUESTION_ID + question.get(Constants.IDENTIFIER), question); + questionList.add(assessUtilServ.filterQuestionMapDetail(question, result.get(Constants.PRIMARY_CATEGORY))); + } + } + } } + } else { + errMsg = Constants.FAILED_TO_GET_QUESTION_DETAILS; + logger.error(String.valueOf(new Exception("Failed to get Question Details for Ids"))); } } + if (errMsg.isEmpty() && identifierList.size() == questionList.size()) { + response.getResult().put(Constants.QUESTIONS, questionList); + } } - return prepareQuestionResponse(questionList, questionList.size() > 0); } catch (Exception e) { - logger.error(e); - throw new ApplicationLogicError("REQUEST_COULD_NOT_BE_PROCESSED", e); + logger.error(String.format("Exception in %s : %s", "get Question List", e.getMessage()), e); + errMsg = "Failed to fetch the question list. Exception: " + e.getMessage(); } + if (StringUtils.isNotBlank(errMsg)) { + response.getParams().setStatus(Constants.FAILED); + response.getParams().setErrmsg(errMsg); + response.setResponseCode(HttpStatus.BAD_REQUEST); + } + return response; } + private String validateAuthTokenAndFetchUserId(String authUserToken) { + return RequestInterceptor.fetchUserIdFromAccessToken(authUserToken); + } + + private String fetchReadHierarchyDetails(Map assessmentAllDetail, String token, + String assessmentIdentifier) throws IOException { + String assessmentData = redisCacheMgr + .getCache(Constants.ASSESSMENT_ID + assessmentIdentifier); + if (!ObjectUtils.isEmpty(assessmentData)) { + assessmentAllDetail.putAll(mapper.readValue(assessmentData, new TypeReference>() { + })); + } else { + Map readHierarchyApiResponse = assessUtilServ.getReadHierarchyApiResponse(assessmentIdentifier, + token); + if (ObjectUtils.isEmpty(readHierarchyApiResponse) + || !Constants.OK.equalsIgnoreCase((String) readHierarchyApiResponse.get(Constants.RESPONSE_CODE))) { + return Constants.ASSESSMENT_HIERARCHY_READ_FAILED; + } + assessmentAllDetail + .putAll((Map) ((Map) readHierarchyApiResponse.get(Constants.RESULT)) + .get(Constants.QUESTION_SET)); + redisCacheMgr + .putCache(Constants.ASSESSMENT_ID + assessmentIdentifier, ((Map) readHierarchyApiResponse.get(Constants.RESULT)) + .get(Constants.QUESTION_SET)); + } + return StringUtils.EMPTY; + } + + private Map validateQuestionListAPI(Map requestBody, String authUserToken, + List identifierList) throws IOException { + Map result = new HashMap<>(); + String userId = validateAuthTokenAndFetchUserId(authUserToken); + if (StringUtils.isBlank(userId)) { + result.put(Constants.ERROR_MESSAGE, Constants.USER_ID_DOESNT_EXIST); + return result; + } + String assessmentIdFromRequest = (String) requestBody.get(Constants.ASSESSMENT_ID_KEY); + if (StringUtils.isBlank(assessmentIdFromRequest)) { + result.put(Constants.ERROR_MESSAGE, Constants.ASSESSMENT_ID_KEY_IS_NOT_PRESENT_IS_EMPTY); + return result; + } + identifierList.addAll(getQuestionIdList(requestBody)); + if (identifierList.isEmpty()) { + result.put(Constants.ERROR_MESSAGE, Constants.IDENTIFIER_LIST_IS_EMPTY); + return result; + } + Map assessmentAllDetail = new HashMap<>(); + String errMsg = fetchReadHierarchyDetails(assessmentAllDetail, authUserToken, assessmentIdFromRequest); + Map userAssessmentAllDetail; + if (errMsg.isEmpty()) { + userAssessmentAllDetail = new HashMap<>(); + String userQuestionSet = redisCacheMgr + .getCache(Constants.USER_ASSESS_REQ + assessmentIdFromRequest + "_" + authUserToken); + if (!ObjectUtils.isEmpty(userQuestionSet)) { + userAssessmentAllDetail.putAll(mapper.readValue(userQuestionSet, new TypeReference>() { + })); + } else if (ObjectUtils.isEmpty(userQuestionSet)) { + if (!((String) assessmentAllDetail.get(Constants.PRIMARY_CATEGORY)) + .equalsIgnoreCase(Constants.PRACTICE_QUESTION_SET)) { + List> existingDataList = assessmentRepository.fetchUserAssessmentDataFromDB(userId, + assessmentIdFromRequest); + String questionSetFromAssessmentString = (!existingDataList.isEmpty()) + ? (String) existingDataList.get(0).get(Constants.ASSESSMENT_READ_RESPONSE) + : ""; + if (!questionSetFromAssessmentString.isEmpty()) { + userAssessmentAllDetail.putAll(new Gson().fromJson(questionSetFromAssessmentString, + new TypeToken>() { + }.getType())); + } else { + result.put(Constants.ERROR_MESSAGE, Constants.USER_ASSESSMENT_DATA_NOT_PRESENT); + return result; + } + } + } else { + result.put(Constants.ERROR_MESSAGE, Constants.ASSESSMENT_ID_INVALID_SESSION_EXPIRED); + return result; + } + } else { + result.put(Constants.ERROR_MESSAGE, errMsg); + return result; + } + String assessmentIdFromDatabase = (String) (userAssessmentAllDetail.get(Constants.IDENTIFIER)); + if (assessmentIdFromDatabase.equalsIgnoreCase(assessmentIdFromRequest)) { + result.put(Constants.PRIMARY_CATEGORY, (String) userAssessmentAllDetail.get(Constants.PRIMARY_CATEGORY)); + List questionsFromAssessment = new ArrayList<>(); + List> sections = (List>) userAssessmentAllDetail + .get(Constants.CHILDREN); + for (Map section : sections) { + questionsFromAssessment.addAll((List) section.get(Constants.CHILD_NODES)); + // Out of the list of questions received in the payload, checking if the request + // has only those ids which are a part of the user's latest assessment + // Fetching all the remaining questions details from the Redis + if (Boolean.FALSE.equals(validateQuestionListRequest(identifierList, questionsFromAssessment))) { + result.put(Constants.ERROR_MESSAGE, Constants.THE_QUESTIONS_IDS_PROVIDED_DONT_MATCH); + return result; + } + } + result.put(Constants.ERROR_MESSAGE, ""); + return result; + } else { + result.put(Constants.ERROR_MESSAGE, Constants.ASSESSMENT_ID_INVALID); + return result; + } + } + @Override - public SBApiResponse submitAssessment(Map data, String authUserToken) throws Exception { - SBApiResponse outgoingResponse = new SBApiResponse(); - String assessmentId = (String) data.get(Constants.IDENTIFIER); + public SBApiResponse submitAssessment(Map submitRequest, String authUserToken) throws IOException { + SBApiResponse outgoingResponse = createDefaultResponse(Constants.API_SUBMIT_ASSESSMENT); + String errMsg; + List> sectionListFromSubmitRequest = new ArrayList<>(); + List> hierarchySectionList = new ArrayList<>(); + List questionsListFromAssessmentHierarchy = new ArrayList<>(); Map assessmentHierarchy = new HashMap<>(); - String assessment = redisCacheMgr - .getCache(Constants.ASSESSMENT_ID + assessmentId); - if (!ObjectUtils.isEmpty(assessment)) { - assessmentHierarchy = mapper.readValue(assessment, new TypeReference>() { - }); - } - // logger.info("Submit Assessment: userId: " + userId + ", data: " + - // data.toString()); - // Check User exists - // if (!userUtilService.validateUser(userId)) { - // throw new BadRequestException("Invalid UserId."); - // } - String userId = RequestInterceptor.fetchUserIdFromAccessToken(authUserToken); - if (userId != null && !ObjectUtils.isEmpty(assessmentHierarchy)) { - Date assessmentStartTime = assessmentRepository.fetchUserAssessmentStartTime(userId, Constants.ASSESSMENT_ID + assessmentId); - if (assessmentStartTime != null) { - Timestamp submissionTime = new Timestamp(new Date().getTime()); - Calendar cal = Calendar.getInstance(); - cal.setTimeInMillis(new Timestamp(assessmentStartTime.getTime()).getTime()); - cal.add(Calendar.SECOND, Integer.valueOf((String) assessmentHierarchy.get(Constants.DURATION)).intValue() + Integer.valueOf(cbExtServerProperties.getUserAssessmentSubmissionDuration())); - Timestamp later = new Timestamp(cal.getTime().getTime()); - int time = submissionTime.compareTo(later); - if (time <= 0) { - outgoingResponse.setResponseCode(HttpStatus.OK); - outgoingResponse.getResult().put(Constants.IDENTIFIER, assessmentId); - outgoingResponse.getResult().put(Constants.OBJECT_TYPE, assessmentHierarchy.get(Constants.OBJECT_TYPE)); - outgoingResponse.getResult().put(Constants.PRIMARY_CATEGORY, assessmentHierarchy.get(Constants.PRIMARY_CATEGORY)); - - // Check Sections are available - if (data.containsKey(Constants.CHILDREN) - && !CollectionUtils.isEmpty((List>) data.get(Constants.CHILDREN))) { - List> sectionList = (List>) data.get(Constants.CHILDREN); - - for (Map section : sectionList) { - String id = (String) section.get(Constants.IDENTIFIER); - String scoreCutOffType = ((String) section.get(Constants.SCORE_CUTOFF_TYPE)).toLowerCase(); - switch (scoreCutOffType) { - case Constants.ASSESSMENT_LEVEL_SCORE_CUTOFF: { - if (sectionList.size() > 1) { - // There should be only one section -- if not -- throw error - } - validateAssessmentLevelScore(outgoingResponse, section, assessmentHierarchy); - } - break; - case Constants.SECTION_LEVEL_SCORE_CUTOFF: { - } + errMsg = validateSubmitAssessmentRequest(submitRequest, authUserToken, hierarchySectionList, + sectionListFromSubmitRequest, assessmentHierarchy); + if (errMsg.isEmpty()) { + String userId = validateAuthTokenAndFetchUserId(authUserToken); + String scoreCutOffType = ((String) assessmentHierarchy.get(Constants.SCORE_CUTOFF_TYPE)).toLowerCase(); + List> existingDataList = new ArrayList<>(); + List> sectionLevelsResults = new ArrayList<>(); + for (Map hierarchySection : hierarchySectionList) { + String hierarchySectionId = (String) hierarchySection.get(Constants.IDENTIFIER); + String userSectionId = ""; + Map userSectionData = new HashMap<>(); + for (Map sectionFromSubmitRequest : sectionListFromSubmitRequest) { + userSectionId = (String) sectionFromSubmitRequest.get(Constants.IDENTIFIER); + if (userSectionId.equalsIgnoreCase(hierarchySectionId)) { + userSectionData = sectionFromSubmitRequest; + break; + } + } + if (!((String) (assessmentHierarchy.get(Constants.PRIMARY_CATEGORY))) + .equalsIgnoreCase(Constants.PRACTICE_QUESTION_SET)) { + Map questionSetFromAssessment = new HashMap<>(); + String assessmentData = redisCacheMgr + .getCache(Constants.USER_ASSESS_REQ + (String) submitRequest.get(Constants.IDENTIFIER) + "_" + authUserToken); + if (!ObjectUtils.isEmpty(assessmentData)) { + questionSetFromAssessment.putAll(mapper.readValue(assessmentData, new TypeReference>() { + })); + } else { + existingDataList = assessmentRepository.fetchUserAssessmentDataFromDB(userId, + (String) submitRequest.get(Constants.IDENTIFIER)); + String questionSetFromAssessmentString = (!existingDataList.isEmpty()) + ? (String) existingDataList.get(0).get(Constants.ASSESSMENT_READ_RESPONSE) + : ""; + if (!questionSetFromAssessmentString.isEmpty()) { + questionSetFromAssessment = new Gson() + .fromJson(questionSetFromAssessmentString, new TypeToken>() { + }.getType()); + } + } + if (questionSetFromAssessment != null + && questionSetFromAssessment.get(Constants.CHILDREN) != null) { + List> sections = (List>) questionSetFromAssessment + .get(Constants.CHILDREN); + for (Map section : sections) { + String sectionId = (String) section.get(Constants.IDENTIFIER); + if (userSectionId.equalsIgnoreCase(sectionId)) { + questionsListFromAssessmentHierarchy = (List) section + .get(Constants.CHILD_NODES); break; - default: - break; } } } else { - // TODO - // At least one section details should be available in the submit request... - // throw error if no section details. + errMsg = "Question Set From The Database returns Null"; + outgoingResponse.getResult().clear(); + break; + } + + hierarchySection.put(Constants.SCORE_CUTOFF_TYPE, scoreCutOffType); + List> questionsListFromSubmitRequest = new ArrayList<>(); + if (userSectionData.containsKey(Constants.CHILDREN) + && !ObjectUtils.isEmpty(userSectionData.get(Constants.CHILDREN))) { + questionsListFromSubmitRequest = (List>) userSectionData + .get(Constants.CHILDREN); + } + Map result = new HashMap<>(); + switch (scoreCutOffType) { + case Constants.ASSESSMENT_LEVEL_SCORE_CUTOFF: { + result.putAll(createResponseMapWithProperStructure(hierarchySection, + assessUtilServ.validateQumlAssessment(questionsListFromAssessmentHierarchy, + questionsListFromSubmitRequest))); + outgoingResponse.getResult().putAll(calculateAssessmentFinalResults(result)); + writeDataToDatabaseAndTriggerKafkaEvent(submitRequest, userId, existingDataList, result, + (String) assessmentHierarchy.get(Constants.PRIMARY_CATEGORY)); + return outgoingResponse; + } + case Constants.SECTION_LEVEL_SCORE_CUTOFF: { + result.putAll(createResponseMapWithProperStructure(hierarchySection, + assessUtilServ.validateQumlAssessment(questionsListFromAssessmentHierarchy, + questionsListFromSubmitRequest))); + sectionLevelsResults.add(result); + } + break; + default: + break; + } + + } else { + hierarchySection.put(Constants.SCORE_CUTOFF_TYPE, scoreCutOffType); + List> questionsListFromSubmitRequest = new ArrayList<>(); + if (userSectionData.containsKey(Constants.CHILDREN) + && !ObjectUtils.isEmpty(userSectionData.get(Constants.CHILDREN))) { + questionsListFromSubmitRequest = (List>) userSectionData + .get(Constants.CHILDREN); + } + List desiredKeys = Lists.newArrayList(Constants.IDENTIFIER); + List questionsList = questionsListFromSubmitRequest.stream() + .flatMap(x -> desiredKeys.stream().filter(x::containsKey).map(x::get)).collect(toList()); + questionsListFromAssessmentHierarchy = questionsList.stream() + .map(object -> Objects.toString(object, null)).collect(Collectors.toList()); + Map result = new HashMap<>(); + switch (scoreCutOffType) { + case Constants.ASSESSMENT_LEVEL_SCORE_CUTOFF: { + result.putAll(createResponseMapWithProperStructure(hierarchySection, + assessUtilServ.validateQumlAssessment(questionsListFromAssessmentHierarchy, + questionsListFromSubmitRequest))); + outgoingResponse.getResult().putAll(calculateAssessmentFinalResults(result)); + return outgoingResponse; + } + case Constants.SECTION_LEVEL_SCORE_CUTOFF: { + result.putAll(createResponseMapWithProperStructure(hierarchySection, + assessUtilServ.validateQumlAssessment(questionsListFromAssessmentHierarchy, + questionsListFromSubmitRequest))); + sectionLevelsResults.add(result); + } + break; + default: + break; } } } + if (errMsg.isEmpty() && !ObjectUtils.isEmpty(scoreCutOffType) + && scoreCutOffType.equalsIgnoreCase(Constants.SECTION_LEVEL_SCORE_CUTOFF)) { + Map result = calculateSectionFinalResults(sectionLevelsResults); + outgoingResponse.getResult().putAll(result); + writeDataToDatabaseAndTriggerKafkaEvent(submitRequest, userId, existingDataList, result, + (String) assessmentHierarchy.get(Constants.PRIMARY_CATEGORY)); + return outgoingResponse; + } + } + if (StringUtils.isNotBlank(errMsg)) { + outgoingResponse.getParams().setStatus(Constants.FAILED); + outgoingResponse.getParams().setErrmsg(errMsg); + outgoingResponse.setResponseCode(HttpStatus.BAD_REQUEST); } return outgoingResponse; } - private Map getReadHierarchyApiResponse(String assessmentIdentifier, String token) { + private void writeDataToDatabaseAndTriggerKafkaEvent(Map submitRequest, String userId, + List> existingDataList, Map result, String primaryCategory) { try { - StringBuilder sbUrl = new StringBuilder(cbExtServerProperties.getAssessmentHost()); - sbUrl.append(cbExtServerProperties.getAssessmentHierarchyReadPath()); - String serviceURL = sbUrl.toString().replace(Constants.IDENTIFIER_REPLACER, assessmentIdentifier); - Map headers = new HashMap<>(); - headers.put(Constants.X_AUTH_TOKEN, token); - headers.put(Constants.AUTHORIZATION, cbExtServerProperties.getSbApiKey()); - Object o = outboundRequestHandlerService.fetchUsingGetWithHeaders(serviceURL, headers); - return mapper.convertValue(o, Map.class); + Date startTime = (!existingDataList.isEmpty()) ? (Date) existingDataList.get(0).get(Constants.START_TIME) + : null; + Boolean isAssessmentUpdatedToDB = assessmentRepository.updateUserAssesmentDataToDB(userId, + (String) submitRequest.get(Constants.IDENTIFIER), submitRequest, result, Constants.SUBMITTED, + startTime); + if (Boolean.TRUE.equals(isAssessmentUpdatedToDB)) { + Map kafkaResult = new HashMap<>(); + kafkaResult.put(Constants.CONTENT_ID_KEY, submitRequest.get(Constants.IDENTIFIER)); + kafkaResult.put(Constants.COURSE_ID, submitRequest.get(Constants.COURSE_ID) != null ? submitRequest.get(Constants.COURSE_ID) : ""); + kafkaResult.put(Constants.BATCH_ID, submitRequest.get(Constants.BATCH_ID) != null ? submitRequest.get(Constants.BATCH_ID) : ""); + kafkaResult.put(Constants.USER_ID, submitRequest.get(Constants.USER_ID)); + kafkaResult.put(Constants.ASSESSMENT_ID_KEY, submitRequest.get(Constants.IDENTIFIER)); + kafkaResult.put(Constants.PRIMARY_CATEGORY, primaryCategory); + kafkaResult.put(Constants.TOTAL_SCORE, result.get(Constants.OVERALL_RESULT)); + if ((primaryCategory.equalsIgnoreCase("Competency Assessment") && submitRequest.containsKey("competencies_v3") && submitRequest.get("competencies_v3") != null)) { + Object[] obj = (Object[]) JSON.parse((String) submitRequest.get("competencies_v3")); + if (obj != null) { + Object map = obj[0]; + ObjectMapper m = new ObjectMapper(); + Map props = m.convertValue(map, Map.class); + kafkaResult.put(Constants.COMPETENCY, props.isEmpty() ? "" : props); + System.out.println(obj); + + } + System.out.println(obj); + } + logger.info(kafkaResult.toString()); + kafkaProducer.push(serverProperties.getAssessmentSubmitTopic(), kafkaResult); + } } catch (Exception e) { - logger.error(e); - throw new ApplicationLogicError(e.getMessage()); + logger.info(e.getMessage()); } } - private SBApiResponse prepareAssessmentResponse(Map hierarchyResponse, boolean isSuccess) { - SBApiResponse outgoingResponse = new SBApiResponse(); - outgoingResponse.setId(Constants.API_QUESTIONSET_HIERARCHY_GET); - outgoingResponse.setVer(Constants.VER); - outgoingResponse.getParams().setResmsgid(UUID.randomUUID().toString()); - if (isSuccess) { - outgoingResponse.getParams().setStatus(Constants.SUCCESS); - outgoingResponse.setResponseCode(HttpStatus.OK); - readAssessmentLevelData(hierarchyResponse, outgoingResponse); + private String validateSubmitAssessmentRequest(Map submitRequest, String authUserToken, + List> hierarchySectionList, List> sectionListFromSubmitRequest, + Map assessmentHierarchy) throws IOException { + String userId = validateAuthTokenAndFetchUserId(authUserToken); + if (ObjectUtils.isEmpty(userId)) { + return Constants.USER_ID_DOESNT_EXIST; + } + submitRequest.put(Constants.USER_ID, userId); + if (StringUtils.isEmpty((String) submitRequest.get(Constants.IDENTIFIER))) { + return Constants.INVALID_ASSESSMENT_ID; + } + String assessmentIdFromRequest = (String) submitRequest.get(Constants.IDENTIFIER); + String errMsg = fetchReadHierarchyDetails(assessmentHierarchy, authUserToken, assessmentIdFromRequest); + if (!errMsg.isEmpty()) { + return errMsg; + } + if (ObjectUtils.isEmpty(assessmentHierarchy)) { + return Constants.READ_ASSESSMENT_FAILED; + } + hierarchySectionList.addAll((List>) assessmentHierarchy.get(Constants.CHILDREN)); + sectionListFromSubmitRequest.addAll((List>) submitRequest.get(Constants.CHILDREN)); + if (((String) (assessmentHierarchy.get(Constants.PRIMARY_CATEGORY))) + .equalsIgnoreCase(Constants.PRACTICE_QUESTION_SET)) + return ""; + List> existingDataList = assessmentRepository.fetchUserAssessmentDataFromDB(userId, + assessmentIdFromRequest); + Date assessmentStartTime = (!existingDataList.isEmpty()) + ? (Date) existingDataList.get(0).get(Constants.START_TIME) + : null; + if (assessmentStartTime == null) { + return Constants.READ_ASSESSMENT_START_TIME_FAILED; + } + int expectedDuration = (Integer) assessmentHierarchy.get(Constants.EXPECTED_DURATION); + Timestamp later = calculateAssessmentSubmitTime(expectedDuration, assessmentStartTime); + Timestamp submissionTime = new Timestamp(new Date().getTime()); + int time = submissionTime.compareTo(later); + if (time <= 0) { + List desiredKeys = Lists.newArrayList(Constants.IDENTIFIER); + List hierarchySectionIds = hierarchySectionList.stream() + .flatMap(x -> desiredKeys.stream().filter(x::containsKey).map(x::get)).collect(toList()); + List submitSectionIds = sectionListFromSubmitRequest.stream() + .flatMap(x -> desiredKeys.stream().filter(x::containsKey).map(x::get)).collect(toList()); + if (!new HashSet<>(hierarchySectionIds).containsAll(submitSectionIds)) { + return Constants.WRONG_SECTION_DETAILS; + } else { + String areQuestionIdsSame = validateIfQuestionIdsAreSame(submitRequest, sectionListFromSubmitRequest, + desiredKeys, userId); + if (!areQuestionIdsSame.isEmpty()) + return areQuestionIdsSame; + } } else { - outgoingResponse.getParams().setStatus(Constants.FAILED); - outgoingResponse.setResponseCode(HttpStatus.INTERNAL_SERVER_ERROR); + return Constants.ASSESSMENT_SUBMIT_EXPIRED; } - return outgoingResponse; + return ""; + } + + private String validateIfQuestionIdsAreSame(Map submitRequest, + List> sectionListFromSubmitRequest, List desiredKeys, String userId) { + List> existingDataList = assessmentRepository.fetchUserAssessmentDataFromDB(userId, + (String) submitRequest.get(Constants.IDENTIFIER)); + String questionSetFromAssessmentString = (!existingDataList.isEmpty()) + ? (String) existingDataList.get(0).get(Constants.ASSESSMENT_READ_RESPONSE) + : ""; + if (!questionSetFromAssessmentString.isEmpty()) { + Map questionSetFromAssessment = new Gson().fromJson(questionSetFromAssessmentString, + new TypeToken>() { + }.getType()); + if (questionSetFromAssessment != null && questionSetFromAssessment.get(Constants.CHILDREN) != null) { + List> sections = (List>) questionSetFromAssessment + .get(Constants.CHILDREN); + List desiredKey = Lists.newArrayList(Constants.CHILD_NODES); + List questionList = sections.stream() + .flatMap(x -> desiredKey.stream().filter(x::containsKey).map(x::get)).collect(toList()); + List questionIdsFromAssessmentHierarchy = new ArrayList<>(); + List> questionsListFromSubmitRequest = new ArrayList<>(); + for (Object question : questionList) { + questionIdsFromAssessmentHierarchy.addAll((List) question); + } + for (Map userSectionData : sectionListFromSubmitRequest) { + if (userSectionData.containsKey(Constants.CHILDREN) + && !ObjectUtils.isEmpty(userSectionData.get(Constants.CHILDREN))) { + questionsListFromSubmitRequest + .addAll((List>) userSectionData.get(Constants.CHILDREN)); + } + } + List userQuestionIdsFromSubmitRequest = questionsListFromSubmitRequest.stream() + .flatMap(x -> desiredKeys.stream().filter(x::containsKey).map(x::get)) + .collect(Collectors.toList()); + if (!new HashSet<>(questionIdsFromAssessmentHierarchy).containsAll(userQuestionIdsFromSubmitRequest)) { + return Constants.ASSESSMENT_SUBMIT_INVALID_QUESTION; + } + } + } else { + return Constants.ASSESSMENT_SUBMIT_QUESTION_READ_FAILED; + } + return ""; + } + + private Timestamp calculateAssessmentSubmitTime(int expectedDuration, Date assessmentStartTime) { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(new Timestamp(assessmentStartTime.getTime()).getTime()); + if (serverProperties.getUserAssessmentSubmissionDuration().isEmpty()) { + serverProperties.setUserAssessmentSubmissionDuration("120"); + } + cal.add(Calendar.SECOND, + expectedDuration + Integer.parseInt(serverProperties.getUserAssessmentSubmissionDuration())); + return new Timestamp(cal.getTime().getTime()); } - private void readAssessmentLevelData(Map assessmentAllDetail, SBApiResponse outgoingResponse) { - List assessmentParams = cbExtServerProperties.getAssessmentLevelParams(); + private Map calculateAssessmentFinalResults(Map assessmentLevelResult) { + Map res = new HashMap<>(); + try { + res.put(Constants.CHILDREN, Collections.singletonList(assessmentLevelResult)); + Double result = (Double) assessmentLevelResult.get(Constants.RESULT); + res.put(Constants.OVERALL_RESULT, result); + res.put(Constants.TOTAL, assessmentLevelResult.get(Constants.TOTAL)); + res.put(Constants.BLANK, assessmentLevelResult.get(Constants.BLANK)); + res.put(Constants.CORRECT, assessmentLevelResult.get(Constants.CORRECT)); + res.put(Constants.PASS_PERCENTAGE, assessmentLevelResult.get(Constants.PASS_PERCENTAGE)); + res.put(Constants.INCORRECT, assessmentLevelResult.get(Constants.INCORRECT)); + Integer minimumPassPercentage = (Integer) assessmentLevelResult.get(Constants.PASS_PERCENTAGE); + res.put(Constants.PASS, result >= minimumPassPercentage); + } catch (Exception e) { + logger.info(e.getMessage()); + } + return res; + } + + private Map calculateSectionFinalResults(List> sectionLevelResults) { + Map res = new HashMap<>(); + Double result; + Integer correct = 0; + Integer blank = 0; + Integer inCorrect = 0; + Integer total = 0; + int pass = 0; + Double totalResult = 0.0; + try { + for (Map sectionChildren : sectionLevelResults) { + res.put(Constants.CHILDREN, sectionLevelResults); + result = (Double) sectionChildren.get(Constants.RESULT); + totalResult += result; + total += (Integer) sectionChildren.get(Constants.TOTAL); + blank += (Integer) sectionChildren.get(Constants.BLANK); + correct += (Integer) sectionChildren.get(Constants.CORRECT); + inCorrect += (Integer) sectionChildren.get(Constants.INCORRECT); + Integer minimumPassPercentage = (Integer) sectionChildren.get(Constants.PASS_PERCENTAGE); + if (result >= minimumPassPercentage) { + pass++; + } + } + res.put(Constants.OVERALL_RESULT, totalResult / sectionLevelResults.size()); + res.put(Constants.TOTAL, total); + res.put(Constants.BLANK, blank); + res.put(Constants.CORRECT, correct); + res.put(Constants.INCORRECT, inCorrect); + res.put(Constants.PASS, (pass == sectionLevelResults.size())); + } catch (Exception e) { + logger.info(e.getMessage()); + } + return res; + } + + private Map readAssessmentLevelData(Map assessmentAllDetail) { + List assessmentParams = serverProperties.getAssessmentLevelParams(); Map assessmentFilteredDetail = new HashMap<>(); for (String assessmentParam : assessmentParams) { if ((assessmentAllDetail.containsKey(assessmentParam))) { @@ -229,15 +665,15 @@ private void readAssessmentLevelData(Map assessmentAllDetail, SB } } readSectionLevelParams(assessmentAllDetail, assessmentFilteredDetail); - outgoingResponse.getResult().put(Constants.QUESTION_SET, assessmentFilteredDetail); + return assessmentFilteredDetail; } private void readSectionLevelParams(Map assessmentAllDetail, Map assessmentFilteredDetail) { List> sectionResponse = new ArrayList<>(); - List sectionParams = cbExtServerProperties.getAssessmentSectionParams(); + List sectionIdList = new ArrayList<>(); + List sectionParams = serverProperties.getAssessmentSectionParams(); List> sections = (List>) assessmentAllDetail.get(Constants.CHILDREN); - List sectionIdList = new ArrayList(); for (Map section : sections) { sectionIdList.add((String) section.get(Constants.IDENTIFIER)); Map newSection = new HashMap<>(); @@ -246,7 +682,7 @@ private void readSectionLevelParams(Map assessmentAllDetail, newSection.put(sectionParam, section.get(sectionParam)); } } - List allQuestionIdList = new ArrayList(); + List allQuestionIdList = new ArrayList<>(); List> questions = (List>) section.get(Constants.CHILDREN); for (Map question : questions) { allQuestionIdList.add((String) question.get(Constants.IDENTIFIER)); @@ -255,7 +691,7 @@ private void readSectionLevelParams(Map assessmentAllDetail, List childNodeList = new ArrayList<>(); if (!ObjectUtils.isEmpty(section.get(Constants.MAX_QUESTIONS))) { int maxQuestions = (int) section.get(Constants.MAX_QUESTIONS); - childNodeList = allQuestionIdList.stream().limit(maxQuestions).collect(Collectors.toList()); + childNodeList = allQuestionIdList.stream().limit(maxQuestions).collect(toList()); } newSection.put(Constants.CHILD_NODES, childNodeList); sectionResponse.add(newSection); @@ -264,150 +700,146 @@ private void readSectionLevelParams(Map assessmentAllDetail, assessmentFilteredDetail.put(Constants.CHILD_NODES, sectionIdList); } - private List getQuestionIdList(Map questionListRequest) throws Exception { - if (questionListRequest.containsKey(Constants.REQUEST)) { - Map request = (Map) questionListRequest.get(Constants.REQUEST); - if ((!ObjectUtils.isEmpty(request)) && request.containsKey(Constants.SEARCH)) { - Map searchObj = (Map) request.get(Constants.SEARCH); - if (!ObjectUtils.isEmpty(searchObj) && searchObj.containsKey(Constants.IDENTIFIER)) { - List identifierList = (List) searchObj.get(Constants.IDENTIFIER); - if (!CollectionUtils.isEmpty(identifierList)) { - return identifierList; + private List getQuestionIdList(Map questionListRequest) { + try { + if (questionListRequest.containsKey(Constants.REQUEST)) { + Map request = (Map) questionListRequest.get(Constants.REQUEST); + if ((!ObjectUtils.isEmpty(request)) && request.containsKey(Constants.SEARCH)) { + Map searchObj = (Map) request.get(Constants.SEARCH); + if (!ObjectUtils.isEmpty(searchObj) && searchObj.containsKey(Constants.IDENTIFIER) + && !CollectionUtils.isEmpty((List) searchObj.get(Constants.IDENTIFIER))) { + return (List) searchObj.get(Constants.IDENTIFIER); } } } - } - throw new Exception("Failed to process the questionList request body."); - } - - private Map readQuestionDetails(List identifiers) throws Exception { - try { - StringBuilder sbUrl = new StringBuilder(cbExtServerProperties.getAssessmentHost()); - sbUrl.append(cbExtServerProperties.getAssessmentQuestionListPath()); - Map headers = new HashMap<>(); - headers.put(Constants.AUTHORIZATION, cbExtServerProperties.getSbApiKey()); - Map requestBody = new HashMap(); - Map requestData = new HashMap(); - Map searchData = new HashMap(); - searchData.put(Constants.IDENTIFIER, identifiers); - requestData.put(Constants.SEARCH, searchData); - requestBody.put(Constants.REQUEST, requestData); - return outboundRequestHandlerService.fetchResultUsingPost(sbUrl.toString(), requestBody, headers); } catch (Exception e) { - logger.error(e); - throw new Exception("Failed to process the readQuestionDetails."); + logger.error(String.format("Failed to process the questionList request body. %s", e.getMessage())); } + return Collections.emptyList(); } - private Map filterQuestionMapDetail(Map questionMapResponse) { - List questionParams = cbExtServerProperties.getAssessmentQuestionParams(); - Map updatedQuestionMap = new HashMap(); - for (String questionParam : questionParams) { - if (questionMapResponse.containsKey(questionParam)) { - updatedQuestionMap.put(questionParam, questionMapResponse.get(questionParam)); - } - } - if (questionMapResponse.containsKey(Constants.CHOICES) && updatedQuestionMap.containsKey(Constants.PRIMARY_CATEGORY) && !updatedQuestionMap.get(Constants.PRIMARY_CATEGORY).toString().equalsIgnoreCase(Constants.FTB_QUESTION)) { - Map choicesObj = (Map) questionMapResponse.get(Constants.CHOICES); - Map updatedChoicesMap = new HashMap<>(); - if (choicesObj.containsKey(Constants.OPTIONS)) { - List> optionsMapList = (List>) choicesObj - .get(Constants.OPTIONS); - updatedChoicesMap.put(Constants.OPTIONS, optionsMapList); - } - updatedQuestionMap.put(Constants.CHOICES, updatedChoicesMap); - } - if (questionMapResponse.containsKey(Constants.RHS_CHOICES) && updatedQuestionMap.containsKey(Constants.PRIMARY_CATEGORY) && updatedQuestionMap.get(Constants.PRIMARY_CATEGORY).toString().equalsIgnoreCase(Constants.MTF_QUESTION)) { - List rhsChoicesObj = (List) questionMapResponse.get(Constants.RHS_CHOICES); - updatedQuestionMap.put(Constants.RHS_CHOICES, rhsChoicesObj); + public Map createResponseMapWithProperStructure(Map hierarchySection, + Map resultMap) { + Map sectionLevelResult = new HashMap<>(); + sectionLevelResult.put(Constants.IDENTIFIER, hierarchySection.get(Constants.IDENTIFIER)); + sectionLevelResult.put(Constants.OBJECT_TYPE, hierarchySection.get(Constants.OBJECT_TYPE)); + sectionLevelResult.put(Constants.PRIMARY_CATEGORY, hierarchySection.get(Constants.PRIMARY_CATEGORY)); + sectionLevelResult.put(Constants.PASS_PERCENTAGE, hierarchySection.get(Constants.MINIMUM_PASS_PERCENTAGE)); + Double result; + if (!ObjectUtils.isEmpty(resultMap)) { + result = (Double) resultMap.get(Constants.RESULT); + sectionLevelResult.put(Constants.RESULT, result); + sectionLevelResult.put(Constants.TOTAL, resultMap.get(Constants.TOTAL)); + sectionLevelResult.put(Constants.BLANK, resultMap.get(Constants.BLANK)); + sectionLevelResult.put(Constants.CORRECT, resultMap.get(Constants.CORRECT)); + sectionLevelResult.put(Constants.INCORRECT, resultMap.get(Constants.INCORRECT)); + } else { + result = 0.0; + sectionLevelResult.put(Constants.RESULT, result); + List childNodes = (List) hierarchySection.get(Constants.CHILDREN); + sectionLevelResult.put(Constants.TOTAL, childNodes.size()); + sectionLevelResult.put(Constants.BLANK, childNodes.size()); + sectionLevelResult.put(Constants.CORRECT, 0); + sectionLevelResult.put(Constants.INCORRECT, 0); } - - return updatedQuestionMap; + sectionLevelResult.put(Constants.PASS, + result >= ((Integer) hierarchySection.get(Constants.MINIMUM_PASS_PERCENTAGE))); + sectionLevelResult.put(Constants.OVERALL_RESULT, result); + return sectionLevelResult; } - private SBApiResponse prepareQuestionResponse(List updatedQuestions, boolean isSuccess) { - SBApiResponse outgoingResponse = new SBApiResponse(); - outgoingResponse.setId(Constants.API_QUESTIONS_LIST); - outgoingResponse.setVer(Constants.VER); - if (isSuccess) { - outgoingResponse.setResponseCode(HttpStatus.OK); - outgoingResponse.getResult().put(Constants.QUESTIONS, updatedQuestions); - } else { - outgoingResponse.setResponseCode(HttpStatus.INTERNAL_SERVER_ERROR); - } - return outgoingResponse; + private SBApiResponse createDefaultResponse(String api) { + SBApiResponse response = new SBApiResponse(); + response.setId(api); + response.setVer(Constants.VER); + response.getParams().setResmsgid(UUID.randomUUID().toString()); + response.getParams().setStatus(Constants.SUCCESS); + response.setResponseCode(HttpStatus.OK); + response.setTs(DateTime.now().toString()); + return response; } - private void validateSectionLevelScore(SBApiResponse outgoingResponse, Map userSectionData, - SunbirdApiResp assessmentHierarchy) { + private Boolean validateQuestionListRequest(List identifierList, List questionsFromAssessment) { + return (new HashSet<>(questionsFromAssessment).containsAll(identifierList)) ? Boolean.TRUE : Boolean.FALSE; } - private void validateAssessmentLevelScore(SBApiResponse outgoingResponse, Map userSectionData, - Map assessmentHierarchy) { - // First Get the Hierarchy of given AssessmentId - List> hierarchySectionList = (List>) assessmentHierarchy - .get(Constants.CHILDREN); - if (CollectionUtils.isEmpty(hierarchySectionList)) { - logger.error(new Exception("There are no section details in Assessment hierarchy.")); - // TODO Throw error - return; - } - String userSectionId = (String) userSectionData.get(Constants.IDENTIFIER); - - Map hierarchySection = null; - for (Map section : hierarchySectionList) { - String hierarchySectionId = (String) section.get(Constants.IDENTIFIER); - if (userSectionId.equalsIgnoreCase(hierarchySectionId)) { - hierarchySection = section; - break; - } - } + public SBApiResponse retakeAssessment(String assessmentIdentifier, String token) throws Exception { + logger.info("AssessmentServiceV2Impl::retakeAssessment... Started"); + SBApiResponse response = createDefaultResponse(Constants.API_RETAKE_ASSESSMENT_GET); + String errMsg = ""; + long time = 0; + int duration = 0; + Boolean retakeAssessments = Boolean.FALSE; + try { + String userId = validateAuthTokenAndFetchUserId(token); + if (userId != null) { + List> existingDataList = assessmentRepository.fetchUserAssessmentDataFromDB(userId, + assessmentIdentifier); - if (ObjectUtils.isEmpty(hierarchySection)) { - // TODO - throw error - return; - } + Map assessmentAllDetail = new HashMap<>(); + errMsg = fetchReadHierarchyDetails(assessmentAllDetail, token, assessmentIdentifier); + duration = (int) assessmentAllDetail.get(Constants.RETAKE_ASSESSMENT_DURATION); + int count = (int) assessmentAllDetail.get(Constants.MAX_ASSESSMENT_RETAKE_ATTEMPTS); + if (!existingDataList.isEmpty()) { + Date assessmentEndTime = (Date) existingDataList.get(0).get(Constants.END_TIME); + if (assessmentEndTime != null) { + if (errMsg.isEmpty() && ((String) assessmentAllDetail.get(Constants.PRIMARY_CATEGORY)).equalsIgnoreCase(Constants.PRACTICE_QUESTION_SET)) { + retakeAssessments = Boolean.TRUE; + } else if (errMsg.isEmpty() + && (assessmentAllDetail.get(Constants.RETAKE_ASSESSMENT_DURATION)) != null && (assessmentAllDetail.get(Constants.MAX_ASSESSMENT_RETAKE_ATTEMPTS) != null)) { + if (count > 0) { + int assessmentCount = calculateAssessmentRetakeCount(count, userId, existingDataList); + if (assessmentCount > 0) { + time = calculateAssessmentRetakeTime( + duration, + assessmentEndTime); + if (time == 0) + retakeAssessments = Boolean.TRUE; + } + } - // We have both hierarchySection and userSection - // Get the list of question Identifier's from userSectionData - List questionIdList = new ArrayList(); - List> userQuestionList = (List>) hierarchySection.get(Constants.CHILDREN); - for (Map question : userQuestionList) { - questionIdList.add((String) question.get(Constants.IDENTIFIER)); + } + } + } else { + retakeAssessments = Boolean.TRUE; + } + } else { + errMsg = Constants.USER_ID_DOESNT_EXIST; + } + } catch (Exception e) { + logger.error(String.format("Exception in %s : %s", "read Assessment", e.getMessage()), e); + errMsg = "Failed to read Assessment. Exception: " + e.getMessage(); } + if (StringUtils.isNotBlank(errMsg)) { + response.getParams().setStatus(Constants.FAILED); + response.getParams().setErrmsg(errMsg); + response.setResponseCode(HttpStatus.INTERNAL_SERVER_ERROR); + } else { + response.getResult().put(Constants.RETAKE_ASSESSMENT, retakeAssessments); + response.getResult().put(Constants.RETAKE_SECONDS_LEFT, time); + response.getResult().put(Constants.RETAKE_ASSESSMENT_DURATION, duration); + } + return response; + } - // We have both answer and user given data. This needs to be compared and result - // should be return. - Map resultMap = assessUtilServ.validateQumlAssessment(questionIdList, - (List>) userSectionData.get(Constants.CHILDREN)); - - Double result = (Double) resultMap.get(Constants.RESULT); - int passPercentage = (Integer) hierarchySection.get(Constants.MINIMUM_PASS_PERCENTAGE); - Map sectionLevelResult = new HashMap(); - sectionLevelResult.put(Constants.IDENTIFIER, hierarchySection.get(Constants.IDENTIFIER)); - sectionLevelResult.put(Constants.OBJECT_TYPE, hierarchySection.get(Constants.OBJECT_TYPE)); - sectionLevelResult.put(Constants.PRIMARY_CATEGORY, hierarchySection.get(Constants.PRIMARY_CATEGORY)); - sectionLevelResult.put(Constants.SCORE_CUTOFF_TYPE, hierarchySection.get(Constants.SCORE_CUTOFF_TYPE)); - sectionLevelResult.put(Constants.PASS_PERCENTAGE, passPercentage); - sectionLevelResult.put(Constants.RESULT, result); - sectionLevelResult.put(Constants.TOTAL, resultMap.get(Constants.TOTAL)); - sectionLevelResult.put(Constants.BLANK, resultMap.get(Constants.BLANK)); - sectionLevelResult.put(Constants.CORRECT, resultMap.get(Constants.CORRECT)); - sectionLevelResult.put(Constants.PASS_PERCENTAGE, hierarchySection.get(Constants.MINIMUM_PASS_PERCENTAGE)); - sectionLevelResult.put(Constants.INCORRECT, resultMap.get(Constants.INCORRECT)); - sectionLevelResult.put(Constants.PASS, result >= passPercentage); - - List> sectionChildren = new ArrayList>(); - sectionChildren.add(sectionLevelResult); - outgoingResponse.getResult().put(Constants.CHILDREN, sectionChildren); - - outgoingResponse.getResult().put(Constants.OVERALL_RESULT, result); - outgoingResponse.getResult().put(Constants.TOTAL, resultMap.get(Constants.TOTAL)); - outgoingResponse.getResult().put(Constants.BLANK, resultMap.get(Constants.BLANK)); - outgoingResponse.getResult().put(Constants.CORRECT, resultMap.get(Constants.CORRECT)); - outgoingResponse.getResult().put(Constants.PASS_PERCENTAGE, hierarchySection.get(Constants.MINIMUM_PASS_PERCENTAGE)); - outgoingResponse.getResult().put(Constants.INCORRECT, resultMap.get(Constants.INCORRECT)); - outgoingResponse.getResult().put(Constants.PASS, result >= passPercentage); + private int calculateAssessmentRetakeCount(int count, String userId, List> userAssessmentData) { + List desiredKeys = Lists.newArrayList(Constants.SUBMIT_ASSESSMENT_RESPONSE); + List values = userAssessmentData.stream() + .flatMap(x -> desiredKeys.stream() + .filter(x::containsKey) + .map(x::get) + ).collect(toList()); + Iterables.removeIf(values, Predicates.isNull()); + return ((count - values.size() < 0) ? 0 : count - values.size()); } -} + private long calculateAssessmentRetakeTime(int retakeAssessmentDuration, Date assessmentEndTime) { + assessmentEndTime = DateUtils.addSeconds(assessmentEndTime, retakeAssessmentDuration); + Date now = new Date(); + if (now.compareTo(assessmentEndTime) < 0) { + return TimeUnit.MILLISECONDS + .toSeconds(Math.abs(assessmentEndTime.getTime() - now.getTime())); + } + return 0; + } +} \ No newline at end of file diff --git a/src/main/java/org/sunbird/assessment/service/AssessmentUtilServiceV2.java b/src/main/java/org/sunbird/assessment/service/AssessmentUtilServiceV2.java index dc3f02514..4cbdc29cf 100644 --- a/src/main/java/org/sunbird/assessment/service/AssessmentUtilServiceV2.java +++ b/src/main/java/org/sunbird/assessment/service/AssessmentUtilServiceV2.java @@ -6,4 +6,12 @@ public interface AssessmentUtilServiceV2 { public Map validateQumlAssessment(List originalQuestionList, List> userQuestionList); + + public String fetchQuestionIdentifierValue(List identifierList, List questionList, String primaryCategory) throws Exception; + + Map filterQuestionMapDetail(Map questionMapResponse, String primaryCategory); + + List> readQuestionDetails(List identifiers); + + public Map getReadHierarchyApiResponse(String assessmentIdentifier, String token); } diff --git a/src/main/java/org/sunbird/assessment/service/AssessmentUtilServiceV2Impl.java b/src/main/java/org/sunbird/assessment/service/AssessmentUtilServiceV2Impl.java index 601bf80b2..6a2451127 100644 --- a/src/main/java/org/sunbird/assessment/service/AssessmentUtilServiceV2Impl.java +++ b/src/main/java/org/sunbird/assessment/service/AssessmentUtilServiceV2Impl.java @@ -7,46 +7,38 @@ import java.util.Map; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; import org.sunbird.cache.RedisCacheMgr; +import org.sunbird.common.service.OutboundRequestHandlerServiceImpl; +import org.sunbird.common.util.CbExtServerProperties; import org.sunbird.common.util.Constants; -import org.sunbird.core.exception.ApplicationLogicError; -import org.sunbird.core.logger.CbExtLogger; + +import com.fasterxml.jackson.databind.ObjectMapper; @Service public class AssessmentUtilServiceV2Impl implements AssessmentUtilServiceV2 { + @Autowired + CbExtServerProperties serverProperties; + + @Autowired + OutboundRequestHandlerServiceImpl outboundRequestHandlerService; + @Autowired RedisCacheMgr redisCacheMgr; @Autowired ObjectMapper mapper; - private CbExtLogger logger = new CbExtLogger(getClass().getName()); - - public static final String QUESTION_TYPE = "qType"; - public static final String OPTIONS = "options"; - public static final String IS_CORRECT = "isCorrect"; - public static final String OPTION_ID = "optionId"; - public static final String MCQ_SCA = "mcq-sca"; - public static final String MCQ_MCA = "mcq-mca"; - public static final String FTB = "ftb"; - public static final String MTF = "mtf"; - public static final String QUESTION_ID = "questionId"; - public static final String RESPONSE = "response"; - public static final String ANSWER = "answer"; - public static final String VALUE = "value"; - public static final String EDITOR_STATE = "editorState"; - public static final String BODY = "body"; - public static final String SELECTED_ANSWER = "selectedAnswer"; - public static final String INDEX = "index"; + private Logger logger = LoggerFactory.getLogger(AssessmentUtilServiceV2Impl.class); public Map validateQumlAssessment(List originalQuestionList, - List> userQuestionList) { + List> userQuestionList) { try { Integer correct = 0; Integer blank = 0; @@ -57,38 +49,35 @@ public Map validateQumlAssessment(List originalQuestionL Map answers = getQumlAnswers(originalQuestionList); for (Map question : userQuestionList) { List marked = new ArrayList<>(); - if (question.containsKey(QUESTION_TYPE)) { - String questionType = ((String) question.get(QUESTION_TYPE)).toLowerCase(); - Map editorStateObj = (Map) question.get(EDITOR_STATE); - List> options = (List>) editorStateObj.get(OPTIONS); + if (question.containsKey(Constants.QUESTION_TYPE)) { + String questionType = ((String) question.get(Constants.QUESTION_TYPE)).toLowerCase(); + Map editorStateObj = (Map) question.get(Constants.EDITOR_STATE); + List> options = (List>) editorStateObj + .get(Constants.OPTIONS); switch (questionType) { - case MTF: - for (Map option : options) { - marked.add(option.get(INDEX).toString() + "-" - + option.get(SELECTED_ANSWER).toString().toLowerCase()); - } - break; - case FTB: - for (Map option : options) { - marked.add((String) option.get(SELECTED_ANSWER)); - } - break; - case MCQ_SCA: - case MCQ_MCA: - for (Map option : options) { - if ((boolean) option.get(SELECTED_ANSWER)) { - marked.add((String) option.get(INDEX)); + case Constants.MTF: + for (Map option : options) { + marked.add(option.get(Constants.INDEX).toString() + "-" + + option.get(Constants.SELECTED_ANSWER).toString().toLowerCase()); } - } - break; - default: - break; + break; + case Constants.FTB: + for (Map option : options) { + marked.add((String) option.get(Constants.SELECTED_ANSWER)); + } + break; + case Constants.MCQ_SCA: + case Constants.MCQ_MCA: + for (Map option : options) { + if ((boolean) option.get(Constants.SELECTED_ANSWER)) { + marked.add((String) option.get(Constants.INDEX)); + } + } + break; + default: + break; } - } else { - // TODO - how to handle this case?? - // Currently throw error } - if (CollectionUtils.isEmpty(marked)) blank++; else { @@ -102,73 +91,81 @@ public Map validateQumlAssessment(List originalQuestionL else inCorrect++; } - total++; } // Increment the blank counter for skipped question objects if (answers.size() > userQuestionList.size()) { blank += answers.size() - userQuestionList.size(); } - result = ((correct * 100d) / (correct + blank + inCorrect)); - resultMap.put("result", result); - resultMap.put("incorrect", inCorrect); - resultMap.put("blank", blank); - resultMap.put("correct", correct); - resultMap.put("total", total); + total = correct + blank + inCorrect; + resultMap.put(Constants.RESULT, ((correct * 100d) / total)); + resultMap.put(Constants.INCORRECT, inCorrect); + resultMap.put(Constants.BLANK, blank); + resultMap.put(Constants.CORRECT, correct); + resultMap.put(Constants.TOTAL, total); return resultMap; } catch (Exception ex) { - logger.error(ex); - throw new ApplicationLogicError("Error when verifying assessment. Error : " + ex.getMessage(), ex); + logger.error("Error when verifying assessment. Error : "); } + return new HashMap<>(); } private Map getQumlAnswers(List questions) throws Exception { Map ret = new HashMap<>(); + + Map> questionMap = new HashMap>(); + for (String questionId : questions) { List correctOption = new ArrayList<>(); Map question = new HashMap<>(); String questionString = redisCacheMgr .getCache(Constants.QUESTION_ID + questionId); - if (!ObjectUtils.isEmpty(questionString)) { - question = mapper.readValue(questionString, new TypeReference>(){}); + if (!ObjectUtils.isEmpty(question)) { + question = mapper.readValue(questionString, new TypeReference>() { + }); } - if (ObjectUtils.isEmpty(question)) { - logger.error(new Exception("Failed to get the answer for question: " + questionId)); - // TODO - Need to handle this scenario. + else + { + logger.error("Failed to get the answer for question from redis cache: " + questionId); + questionMap = fetchQuestionMapDetails(questionId); + question = questionMap.get(questionId); } - if (question.containsKey(QUESTION_TYPE)) { - String questionType = ((String) question.get(QUESTION_TYPE)).toLowerCase(); - Map editorStateObj = (Map) question.get(EDITOR_STATE); - List> options = (List>) editorStateObj.get(OPTIONS); + if (question.containsKey(Constants.QUESTION_TYPE)) { + String questionType = ((String) question.get(Constants.QUESTION_TYPE)).toLowerCase(); + Map editorStateObj = (Map) question.get(Constants.EDITOR_STATE); + List> options = (List>) editorStateObj.get(Constants.OPTIONS); switch (questionType) { - case MTF: - for (Map option : options) { - Map valueObj = (Map) option.get(VALUE); - correctOption.add( - valueObj.get(VALUE).toString() + "-" + option.get(ANSWER).toString().toLowerCase()); - } - break; - case FTB: - for (Map option : options) { - correctOption.add((String) option.get(SELECTED_ANSWER)); - } - break; - case MCQ_SCA: - case MCQ_MCA: - for (Map option : options) { - if ((boolean) option.get(ANSWER)) { - Map valueObj = (Map) option.get(VALUE); - correctOption.add(valueObj.get(VALUE).toString()); + case Constants.MTF: + for (Map option : options) { + Map valueObj = (Map) option.get(Constants.VALUE); + correctOption.add(valueObj.get(Constants.VALUE).toString() + "-" + + option.get(Constants.ANSWER).toString().toLowerCase()); } - } - break; - default: - break; + break; + case Constants.FTB: + for (Map option : options) { + if ((boolean) option.get(Constants.ANSWER)) { + Map valueObj = (Map) option.get(Constants.VALUE); + correctOption.add(valueObj.get(Constants.BODY).toString()); + } + } + break; + case Constants.MCQ_SCA: + case Constants.MCQ_MCA: + for (Map option : options) { + if ((boolean) option.get(Constants.ANSWER)) { + Map valueObj = (Map) option.get(Constants.VALUE); + correctOption.add(valueObj.get(Constants.VALUE).toString()); + } + } + break; + default: + break; } } else { - for (Map options : (List>) question.get(OPTIONS)) { - if ((boolean) options.get(IS_CORRECT)) - correctOption.add(options.get(OPTION_ID).toString()); + for (Map options : (List>) question.get(Constants.OPTIONS)) { + if ((boolean) options.get(Constants.IS_CORRECT)) + correctOption.add(options.get(Constants.OPTION_ID).toString()); } } ret.put(question.get(Constants.IDENTIFIER).toString(), correctOption); @@ -176,4 +173,148 @@ private Map getQumlAnswers(List questions) throws Except return ret; } -} + + private Map> fetchQuestionMapDetails(String questionId) { + // Taking the list which was formed with the not found values in Redis, we are + // making an internal POST call to Question List API to fetch the details + Map> questionsMap = new HashMap<>(); + List> questionMapList = readQuestionDetails(Collections.singletonList(questionId)); + for (Map questionMapResponse : questionMapList) { + if (!ObjectUtils.isEmpty(questionMapResponse) + && Constants.OK.equalsIgnoreCase((String) questionMapResponse.get(Constants.RESPONSE_CODE))) { + List> questionMap = ((List>) ((Map) questionMapResponse + .get(Constants.RESULT)).get(Constants.QUESTIONS)); + for (Map question : questionMap) { + if (!ObjectUtils.isEmpty(questionMap)) { + questionsMap.put((String) question.get(Constants.IDENTIFIER), question); + redisCacheMgr.putCache(Constants.QUESTION_ID, question); + } + } + } + } + return questionsMap; + } + + @Override + public String fetchQuestionIdentifierValue(List identifierList, List questionList, String primaryCategory) + throws Exception { + List newIdentifierList = new ArrayList<>(); + newIdentifierList.addAll(identifierList); + + // Taking the list which was formed with the not found values in Redis, we are + // making an internal POST call to Question List API to fetch the details + if (!newIdentifierList.isEmpty()) { + List> questionMapList = readQuestionDetails(newIdentifierList); + for (Map questionMapResponse : questionMapList) { + if (!ObjectUtils.isEmpty(questionMapResponse) + && Constants.OK.equalsIgnoreCase((String) questionMapResponse.get(Constants.RESPONSE_CODE))) { + List> questionMap = ((List>) ((Map) questionMapResponse + .get(Constants.RESULT)).get(Constants.QUESTIONS)); + for (Map question : questionMap) { + if (!ObjectUtils.isEmpty(questionMap)) { + questionList.add(filterQuestionMapDetail(question, primaryCategory)); + } else { + logger.error(String.format("Failed to get Question Details for Id: %s", + question.get(Constants.IDENTIFIER).toString())); + return "Failed to get Question Details for Id: %s"; + } + } + } else { + logger.error( + String.format("Failed to get Question Details from the Question List API for the IDs: %s", + newIdentifierList.toString())); + return "Failed to get Question Details from the Question List API for the IDs"; + } + } + } + return ""; + } + + @Override + public Map filterQuestionMapDetail(Map questionMapResponse, String primaryCategory) { + List questionParams = serverProperties.getAssessmentQuestionParams(); + Map updatedQuestionMap = new HashMap<>(); + for (String questionParam : questionParams) { + if (questionMapResponse.containsKey(questionParam)) { + updatedQuestionMap.put(questionParam, questionMapResponse.get(questionParam)); + } + } + if (questionMapResponse.containsKey(Constants.EDITOR_STATE) + && primaryCategory.equalsIgnoreCase(Constants.PRACTICE_QUESTION_SET)) { + Map editorState = (Map) questionMapResponse.get(Constants.EDITOR_STATE); + updatedQuestionMap.put(Constants.EDITOR_STATE, editorState); + } + if (questionMapResponse.containsKey(Constants.CHOICES) + && updatedQuestionMap.containsKey(Constants.PRIMARY_CATEGORY) && !updatedQuestionMap + .get(Constants.PRIMARY_CATEGORY).toString().equalsIgnoreCase(Constants.FTB_QUESTION)) { + Map choicesObj = (Map) questionMapResponse.get(Constants.CHOICES); + Map updatedChoicesMap = new HashMap<>(); + if (choicesObj.containsKey(Constants.OPTIONS)) { + List> optionsMapList = (List>) choicesObj + .get(Constants.OPTIONS); + updatedChoicesMap.put(Constants.OPTIONS, optionsMapList); + } + updatedQuestionMap.put(Constants.CHOICES, updatedChoicesMap); + } + if (questionMapResponse.containsKey(Constants.RHS_CHOICES) + && updatedQuestionMap.containsKey(Constants.PRIMARY_CATEGORY) && updatedQuestionMap + .get(Constants.PRIMARY_CATEGORY).toString().equalsIgnoreCase(Constants.MTF_QUESTION)) { + List rhsChoicesObj = (List) questionMapResponse.get(Constants.RHS_CHOICES); + updatedQuestionMap.put(Constants.RHS_CHOICES, rhsChoicesObj); + } + + return updatedQuestionMap; + } + + @Override + public List> readQuestionDetails(List identifiers) { + try { + StringBuilder sbUrl = new StringBuilder(serverProperties.getAssessmentHost()); + sbUrl.append(serverProperties.getAssessmentQuestionListPath()); + Map headers = new HashMap<>(); + headers.put(Constants.AUTHORIZATION, serverProperties.getSbApiKey()); + Map requestBody = new HashMap<>(); + Map requestData = new HashMap<>(); + Map searchData = new HashMap<>(); + requestData.put(Constants.SEARCH, searchData); + requestBody.put(Constants.REQUEST, requestData); + List> questionDataList = new ArrayList<>(); + int chunkSize = 15; + for (int i = 0; i < identifiers.size(); i += chunkSize) { + List identifierList; + if ((i + chunkSize) >= identifiers.size()) { + identifierList = identifiers.subList(i, identifiers.size()); + } else { + identifierList = identifiers.subList(i, i + chunkSize); + } + searchData.put(Constants.IDENTIFIER, identifierList); + Map data = outboundRequestHandlerService.fetchResultUsingPost(sbUrl.toString(), + requestBody, headers); + if (!ObjectUtils.isEmpty(data)) { + questionDataList.add(data); + } + } + return questionDataList; + } catch (Exception e) { + logger.info(String.format("Failed to process the readQuestionDetails. %s", e.getMessage())); + } + return new ArrayList<>(); + } + + @Override + public Map getReadHierarchyApiResponse(String assessmentIdentifier, String token) { + try { + StringBuilder sbUrl = new StringBuilder(serverProperties.getAssessmentHost()); + sbUrl.append(serverProperties.getAssessmentHierarchyReadPath()); + String serviceURL = sbUrl.toString().replace(Constants.IDENTIFIER_REPLACER, assessmentIdentifier); + Map headers = new HashMap<>(); + headers.put(Constants.X_AUTH_TOKEN, token); + headers.put(Constants.AUTHORIZATION, serverProperties.getSbApiKey()); + Object o = outboundRequestHandlerService.fetchUsingGetWithHeaders(serviceURL, headers); + return new ObjectMapper().convertValue(o, Map.class); + } catch (Exception e) { + logger.error(e.getMessage()); + } + return new HashMap<>(); + } +} \ No newline at end of file diff --git a/src/main/java/org/sunbird/common/util/CbExtServerProperties.java b/src/main/java/org/sunbird/common/util/CbExtServerProperties.java index 75c47f334..9d63f62b3 100644 --- a/src/main/java/org/sunbird/common/util/CbExtServerProperties.java +++ b/src/main/java/org/sunbird/common/util/CbExtServerProperties.java @@ -431,6 +431,22 @@ public class CbExtServerProperties { @Value("${es.user.report.include.fields}") private String esUserReportIncludeFields; + + @Value("${assessment.use.redis}") + private boolean assessmentUseRedisCache; + + @Value("${kafka.topics.user.assessment.submit}") + private String assessmentSubmitTopic; + + @Value("${sso.url}") + private String ssoUrl; + + @Value("${sso.realm}") + private String ssoRealm; + + @Value("${sb.es.user.notification.preference.index}") + private String sbUserNotificationPreferenceIndex; + public String getUserAssessmentSubmissionDuration() { return userAssessmentSubmissionDuration; } @@ -1572,4 +1588,45 @@ public String[] getEsUserReportIncludeFields() { public void setEsUserReportIncludeFields(String esUserReportIncludeFields) { this.esUserReportIncludeFields = esUserReportIncludeFields; } + + + public boolean isAssessmentUseRedisCache() { + return assessmentUseRedisCache; + } + + public void setAssessmentUseRedisCache(boolean assessmentUseRedisCache) { + this.assessmentUseRedisCache = assessmentUseRedisCache; + } + + public String getAssessmentSubmitTopic() { + return assessmentSubmitTopic; + } + + public void setAssessmentSubmitTopic(String assessmentSubmitTopic) { + this.assessmentSubmitTopic = assessmentSubmitTopic; + } + + public String getSsoUrl() { + return ssoUrl; + } + + public void setSsoUrl(String ssoUrl) { + this.ssoUrl = ssoUrl; + } + + public String getSsoRealm() { + return ssoRealm; + } + + public void setSsoRealm(String ssoRealm) { + this.ssoRealm = ssoRealm; + } + + public String getSbUserNotificationPreferenceIndex() { + return sbUserNotificationPreferenceIndex; + } + + public void setSbUserNotificationPreferenceIndex(String sbUserNotificationPreferenceIndex) { + this.sbUserNotificationPreferenceIndex = sbUserNotificationPreferenceIndex; + } } \ No newline at end of file diff --git a/src/main/java/org/sunbird/common/util/Constants.java b/src/main/java/org/sunbird/common/util/Constants.java index 7b9325cbf..ddcda65a9 100644 --- a/src/main/java/org/sunbird/common/util/Constants.java +++ b/src/main/java/org/sunbird/common/util/Constants.java @@ -260,6 +260,7 @@ public class Constants { public static final String DOPT = "dopt"; public static final String PERSONAL_DETAILS = "personalDetails"; public static final String TRANSITION_DETAILS = "transitionDetails"; + public static final String UNAUTHORIZED_KEY = "Unauthorized"; public static final String UNAUTHORIZED = "unauthorized"; // Redis public static final String API_REDIS_DELETE = "api.redis.delete"; @@ -367,12 +368,15 @@ public class Constants { public static final String MTF_QUESTION = "MTF Question"; public static final String FTB_QUESTION = "FTB Question"; public static final String API_QUESTIONSET_HIERARCHY_GET = "api.questionset.hierarchy.get"; + public static final String API_RETAKE_ASSESSMENT_GET = "api.retake.assessment.get"; public static final String VER = "3.0"; public static final String API_QUESTIONS_LIST = "api.questions.list"; public static final String MINIMUM_PASS_PERCENTAGE = "minimumPassPercentage"; public static final String SCORE_CUTOFF_TYPE = "scoreCutoffType"; public static final String PASS_PERCENTAGE = "passPercentage"; public static final String TOTAL = "total"; + public static final String TOTAL_SCORE = "totalScore"; + public static final String SUBMIT_ASSESSMENT_RESPONSE = "submitassessmentresponse"; public static final String BLANK = "blank"; public static final String CORRECT = "correct"; public static final String INCORRECT = "incorrect"; @@ -535,9 +539,66 @@ public class Constants { public static final String PARENT_CONTENT_TYPE = "parentContentType"; public static final String NEW_COURSES = "newcourses"; public static final String OVERVIEW_BATCH_KEY = "/overview?batchId="; - public static final String LEAF_NODES_COUNT = "leafNodesCount"; + public static final String PRACTICE_QUESTION_SET = "Practice Question Set"; + public static final String EXPECTED_DURATION = "expectedDuration"; + public static final String SUBMITTED = "SUBMITTED"; + public static final String NOT_SUBMITTED = "NOT SUBMITTED"; + public static final String END_TIME = "endtime"; + public static final String ASSESSMENT_ID_KEY = "assessmentId"; + public static final String START_TIME = "starttime"; + public static final String CONTENT_ID_KEY = "contentId"; + public static final String QUESTION_TYPE = "qType"; + public static final String SELECTED_ANSWER = "selectedAnswer"; + public static final String INDEX = "index"; + public static final String MCQ_SCA = "mcq-sca"; + public static final String MCQ_MCA = "mcq-mca"; + public static final String FTB = "ftb"; + public static final String MTF = "mtf"; + public static final String IS_CORRECT = "isCorrect"; + public static final String OPTION_ID = "optionId"; + + public static final String TABLE_USER_ASSESSMENT_DATA = "user_assessment_data"; + + + public static final String USER_ID_DOESNT_EXIST = "User Id doesn't exist! Please supply a valid auth token"; + public static final String ASSESSMENT_DATA_START_TIME_NOT_UPDATED = "Assessment Data & Start Time not updated in the DB! Please check!"; + public static final String FAILED_TO_GET_QUESTION_DETAILS = "Failed to get Question List data from the Question List Api! Please check!"; + + public static final String ASSESSMENT_HIERARCHY_READ_FAILED = "Assessment hierarchy read failed, failed to process request"; + public static final String ASSESSMENT_ID_KEY_IS_NOT_PRESENT_IS_EMPTY = "Assessment Id Key is not present/is empty"; + + public static final String USER_ASSESSMENT_DATA_NOT_PRESENT = "User Assessment Data not present in Databases"; + public static final String ASSESSMENT_ID_INVALID = "The Assessment Id is Invalid/Doesn't match with our records"; + public static final String IDENTIFIER_LIST_IS_EMPTY = "Identifier List is Empty"; + public static final String THE_QUESTIONS_IDS_PROVIDED_DONT_MATCH = "The Questions Ids Provided don't match the active user assessment session"; + public static final String ASSESSMENT_ID_INVALID_SESSION_EXPIRED = "Assessment Id Invalid/Session Expired/Redis Cache doesn't have this question list details"; + public static final String INVALID_ASSESSMENT_ID = "Invalid Assessment Id"; + public static final String READ_ASSESSMENT_FAILED = "Failed to read assessment hierarchy for the given AssessmentId."; + public static final String READ_ASSESSMENT_START_TIME_FAILED = "Failed to read the assessment start time."; + public static final String WRONG_SECTION_DETAILS = "Wrong section details."; + public static final String ASSESSMENT_SUBMIT_EXPIRED = "The Assessment submission time-period is over! Assessment can't be submitted"; + public static final String ASSESSMENT_SUBMIT_INVALID_QUESTION = "The QuestionId provided don't match to the Assessment Read"; + public static final String ASSESSMENT_SUBMIT_QUESTION_READ_FAILED = "Failed to read Question Set from DB"; + + + public static final String ASSESSMENT_READ_RESPONSE = "assessmentreadresponse"; + public static final String API_SUBMIT_ASSESSMENT = "api.submit.asssessment"; + + public static final String API_READ_NOTIFICATION_PREFERENCE = "api.read.notification.preference"; + public static final String API_UPDATE_NOTIFICATION_PREFERENCE = "api.update.notification.preference"; + public static final String NOTIFICATION_PREFERENCE="notification_preference"; + public static final String TABLE_USER_NOTIFICATION_PREFERENCE = "user_notification_preference"; + public static final String ERROR_INVALID_USER_ID = "Invalid UserId"; + public static final String ERROR_INVALID_REQUEST_BODY = "Invalid Request Body"; public static final String CLIENT_ERROR = "CLIENT_ERROR"; + public static final String RETAKE_ASSESSMENT_DURATION = "retakeAssessmentDuration"; + public static final String MAX_ASSESSMENT_RETAKE_ATTEMPTS = "maxAssessmentRetakeAttempts"; + + public static final String SUBMIT_TIME = "submittime"; + public static final String LEAF_NODES_COUNT = "leafNodesCount"; public static final String PARENT = "parent"; + public static final String RETAKE_SECONDS_LEFT = "retakeSecondsLeft"; + public static final String RETAKE_ASSESSMENT = "retakeAssessments"; public static final String ORGANISATIONS = "organisations"; public static final String CIPHER_ALGORITHM = "AES"; From 6e22647f28870d38e5a77bc77e4af25831b1fc2b Mon Sep 17 00:00:00 2001 From: Juhi Date: Tue, 17 Jan 2023 17:57:23 +0530 Subject: [PATCH 06/21] changes --- .../service/AssessmentServiceV2Impl.java | 55 ++++--------------- .../org/sunbird/common/util/Constants.java | 4 +- 2 files changed, 13 insertions(+), 46 deletions(-) diff --git a/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java b/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java index 6e6c13678..a48bc9051 100644 --- a/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java +++ b/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java @@ -767,43 +767,21 @@ public SBApiResponse retakeAssessment(String assessmentIdentifier, String token) logger.info("AssessmentServiceV2Impl::retakeAssessment... Started"); SBApiResponse response = createDefaultResponse(Constants.API_RETAKE_ASSESSMENT_GET); String errMsg = ""; - long time = 0; - int duration = 0; - Boolean retakeAssessments = Boolean.FALSE; + int retakeAttemptsAllowed = 0; + int retakeAttemptsConsumed = 0; try { String userId = validateAuthTokenAndFetchUserId(token); if (userId != null) { List> existingDataList = assessmentRepository.fetchUserAssessmentDataFromDB(userId, assessmentIdentifier); - Map assessmentAllDetail = new HashMap<>(); errMsg = fetchReadHierarchyDetails(assessmentAllDetail, token, assessmentIdentifier); - duration = (int) assessmentAllDetail.get(Constants.RETAKE_ASSESSMENT_DURATION); - int count = (int) assessmentAllDetail.get(Constants.MAX_ASSESSMENT_RETAKE_ATTEMPTS); - if (!existingDataList.isEmpty()) { - Date assessmentEndTime = (Date) existingDataList.get(0).get(Constants.END_TIME); - if (assessmentEndTime != null) { - if (errMsg.isEmpty() && ((String) assessmentAllDetail.get(Constants.PRIMARY_CATEGORY)).equalsIgnoreCase(Constants.PRACTICE_QUESTION_SET)) { - retakeAssessments = Boolean.TRUE; - } else if (errMsg.isEmpty() - && (assessmentAllDetail.get(Constants.RETAKE_ASSESSMENT_DURATION)) != null && (assessmentAllDetail.get(Constants.MAX_ASSESSMENT_RETAKE_ATTEMPTS) != null)) { - if (count > 0) { - int assessmentCount = calculateAssessmentRetakeCount(count, userId, existingDataList); - if (assessmentCount > 0) { - time = calculateAssessmentRetakeTime( - duration, - assessmentEndTime); - if (time == 0) - retakeAssessments = Boolean.TRUE; - } - } - - } - } - } else { - retakeAssessments = Boolean.TRUE; + if (assessmentAllDetail.get(Constants.MAX_ASSESSMENT_RETAKE_ATTEMPTS) != null) { + retakeAttemptsAllowed = (int) assessmentAllDetail.get(Constants.MAX_ASSESSMENT_RETAKE_ATTEMPTS); } - } else { + retakeAttemptsConsumed = calculateAssessmentRetakeCount(existingDataList); + } + else { errMsg = Constants.USER_ID_DOESNT_EXIST; } } catch (Exception e) { @@ -815,14 +793,13 @@ public SBApiResponse retakeAssessment(String assessmentIdentifier, String token) response.getParams().setErrmsg(errMsg); response.setResponseCode(HttpStatus.INTERNAL_SERVER_ERROR); } else { - response.getResult().put(Constants.RETAKE_ASSESSMENT, retakeAssessments); - response.getResult().put(Constants.RETAKE_SECONDS_LEFT, time); - response.getResult().put(Constants.RETAKE_ASSESSMENT_DURATION, duration); + response.getResult().put(Constants.TOTAL_RETAKE_ATTEMPTS_ALLOWED, retakeAttemptsAllowed); + response.getResult().put(Constants.RETAKE_ATTEMPTS_CONSUMED, retakeAttemptsConsumed); } return response; } - private int calculateAssessmentRetakeCount(int count, String userId, List> userAssessmentData) { + private int calculateAssessmentRetakeCount(List> userAssessmentData) { List desiredKeys = Lists.newArrayList(Constants.SUBMIT_ASSESSMENT_RESPONSE); List values = userAssessmentData.stream() .flatMap(x -> desiredKeys.stream() @@ -830,16 +807,6 @@ private int calculateAssessmentRetakeCount(int count, String userId, List Date: Tue, 17 Jan 2023 18:13:27 +0530 Subject: [PATCH 07/21] changes --- src/main/java/org/sunbird/common/util/Constants.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/sunbird/common/util/Constants.java b/src/main/java/org/sunbird/common/util/Constants.java index 4c1fd76f6..81b5608dd 100644 --- a/src/main/java/org/sunbird/common/util/Constants.java +++ b/src/main/java/org/sunbird/common/util/Constants.java @@ -368,7 +368,7 @@ public class Constants { public static final String MTF_QUESTION = "MTF Question"; public static final String FTB_QUESTION = "FTB Question"; public static final String API_QUESTIONSET_HIERARCHY_GET = "api.questionset.hierarchy.get"; - public static final String API_RETAKE_ASSESSMENT_GET = "api.retake.assessment.get"; + public static final String API_RETAKE_ASSESSMENT_GET = "api.assessmment.attempt"; public static final String VER = "3.0"; public static final String API_QUESTIONS_LIST = "api.questions.list"; public static final String MINIMUM_PASS_PERCENTAGE = "minimumPassPercentage"; @@ -597,8 +597,8 @@ public class Constants { public static final String SUBMIT_TIME = "submittime"; public static final String LEAF_NODES_COUNT = "leafNodesCount"; public static final String PARENT = "parent"; - public static final String TOTAL_RETAKE_ATTEMPTS_ALLOWED = "totalRetakeAttemptsAllowed"; - public static final String RETAKE_ATTEMPTS_CONSUMED = "retakeAttemptsConsumed"; + public static final String TOTAL_RETAKE_ATTEMPTS_ALLOWED = "attemptsAllowed"; + public static final String RETAKE_ATTEMPTS_CONSUMED = "attemptsMade"; public static final String ORGANISATIONS = "organisations"; public static final String CIPHER_ALGORITHM = "AES"; From cf8bc93d754af0d646fa2c23da0c41360cde804b Mon Sep 17 00:00:00 2001 From: Juhi Date: Wed, 18 Jan 2023 13:40:26 +0530 Subject: [PATCH 08/21] changes --- .../sunbird/common/util/CbExtServerProperties.java | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/main/java/org/sunbird/common/util/CbExtServerProperties.java b/src/main/java/org/sunbird/common/util/CbExtServerProperties.java index 9d63f62b3..569a2b282 100644 --- a/src/main/java/org/sunbird/common/util/CbExtServerProperties.java +++ b/src/main/java/org/sunbird/common/util/CbExtServerProperties.java @@ -431,10 +431,6 @@ public class CbExtServerProperties { @Value("${es.user.report.include.fields}") private String esUserReportIncludeFields; - - @Value("${assessment.use.redis}") - private boolean assessmentUseRedisCache; - @Value("${kafka.topics.user.assessment.submit}") private String assessmentSubmitTopic; @@ -1589,15 +1585,6 @@ public void setEsUserReportIncludeFields(String esUserReportIncludeFields) { this.esUserReportIncludeFields = esUserReportIncludeFields; } - - public boolean isAssessmentUseRedisCache() { - return assessmentUseRedisCache; - } - - public void setAssessmentUseRedisCache(boolean assessmentUseRedisCache) { - this.assessmentUseRedisCache = assessmentUseRedisCache; - } - public String getAssessmentSubmitTopic() { return assessmentSubmitTopic; } From 4328d418db5b5184ddaa44e7f24ecc1fa38f2da3 Mon Sep 17 00:00:00 2001 From: Juhi Date: Fri, 20 Jan 2023 13:54:00 +0530 Subject: [PATCH 09/21] changes --- .../service/AssessmentServiceV2Impl.java | 286 +++++++----------- 1 file changed, 102 insertions(+), 184 deletions(-) diff --git a/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java b/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java index a48bc9051..dea76321d 100644 --- a/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java +++ b/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java @@ -72,64 +72,48 @@ public SBApiResponse readAssessment(String assessmentIdentifier, String token) { logger.info("readAssessment.. userId :" + userId); Map assessmentAllDetail = new HashMap<>(); errMsg = fetchReadHierarchyDetails(assessmentAllDetail, token, assessmentIdentifier); - if (errMsg.isEmpty() && !((String) assessmentAllDetail.get(Constants.PRIMARY_CATEGORY)) - .equalsIgnoreCase(Constants.PRACTICE_QUESTION_SET)) { + if (errMsg.isEmpty() && !((String) assessmentAllDetail.get(Constants.PRIMARY_CATEGORY)).equalsIgnoreCase(Constants.PRACTICE_QUESTION_SET)) { logger.info("Fetched assessment Details... for : " + assessmentIdentifier); - List> existingDataList = assessmentRepository - .fetchUserAssessmentDataFromDB(userId, assessmentIdentifier); + List> existingDataList = assessmentRepository.fetchUserAssessmentDataFromDB(userId, assessmentIdentifier); Timestamp assessmentStartTime = new Timestamp(new Date().getTime()); if (existingDataList.isEmpty()) { logger.info("Assessment read first time for user."); - response.getResult().put(Constants.QUESTION_SET, readAssessmentLevelData(assessmentAllDetail)); + setAssessmentDetail(response, assessmentAllDetail); redisCacheMgr.putCache(Constants.USER_ASSESS_REQ + assessmentIdentifier + "_" + token, response.getResult().get(Constants.QUESTION_SET)); int expectedDuration = (Integer) assessmentAllDetail.get(Constants.EXPECTED_DURATION); - Boolean isAssessmentUpdatedToDB = assessmentRepository.addUserAssesmentDataToDB(userId, - assessmentIdentifier, assessmentStartTime, - calculateAssessmentSubmitTime(expectedDuration, assessmentStartTime), - (Map) (response.getResult().get(Constants.QUESTION_SET)), - Constants.NOT_SUBMITTED); + Boolean isAssessmentUpdatedToDB = assessmentRepository.addUserAssesmentDataToDB(userId, assessmentIdentifier, assessmentStartTime, calculateAssessmentSubmitTime(expectedDuration, assessmentStartTime), (Map) (response.getResult().get(Constants.QUESTION_SET)), Constants.NOT_SUBMITTED); if (Boolean.FALSE.equals(isAssessmentUpdatedToDB)) { errMsg = Constants.ASSESSMENT_DATA_START_TIME_NOT_UPDATED; } } else { logger.info("Assessment read... user has details... "); Date existingAssessmentEndTime = (Date) (existingDataList.get(0).get(Constants.END_TIME)); - if (assessmentStartTime.compareTo(existingAssessmentEndTime) < 0 && ((String) existingDataList.get(0).get(Constants.STATUS)) - .equalsIgnoreCase(Constants.NOT_SUBMITTED)) { + if (assessmentStartTime.compareTo(existingAssessmentEndTime) < 0 && ((String) existingDataList.get(0).get(Constants.STATUS)).equalsIgnoreCase(Constants.NOT_SUBMITTED)) { Map questionSetFromAssessment; - String userQuestionSet = redisCacheMgr - .getCache(Constants.USER_ASSESS_REQ + assessmentIdentifier + "_" + token); + String userQuestionSet = redisCacheMgr.getCache(Constants.USER_ASSESS_REQ + assessmentIdentifier + "_" + token); if (!ObjectUtils.isEmpty(userQuestionSet)) { questionSetFromAssessment = mapper.readValue(userQuestionSet, new TypeReference>() { }); } else { - String questionSetFromAssessmentString = (String) existingDataList.get(0) - .get(Constants.ASSESSMENT_READ_RESPONSE); - questionSetFromAssessment = new Gson().fromJson( - questionSetFromAssessmentString, new TypeToken>() { - }.getType()); + String questionSetFromAssessmentString = (String) existingDataList.get(0).get(Constants.ASSESSMENT_READ_RESPONSE); + questionSetFromAssessment = new Gson().fromJson(questionSetFromAssessmentString, new TypeToken>() { + }.getType()); redisCacheMgr.putCache(Constants.USER_ASSESS_REQ + assessmentIdentifier + "_" + token, questionSetFromAssessment); } response.getResult().put(Constants.QUESTION_SET, questionSetFromAssessment); } else { logger.info("Assessment read... adding user data to db..."); - response.getResult().put(Constants.QUESTION_SET, - readAssessmentLevelData(assessmentAllDetail)); + setAssessmentDetail(response, assessmentAllDetail); int expectedDuration = (Integer) assessmentAllDetail.get(Constants.EXPECTED_DURATION); - Boolean isAssessmentUpdatedToDB = assessmentRepository.addUserAssesmentDataToDB(userId, - assessmentIdentifier, assessmentStartTime, - calculateAssessmentSubmitTime(expectedDuration, assessmentStartTime), - (Map) (response.getResult().get(Constants.QUESTION_SET)), - Constants.NOT_SUBMITTED); + Boolean isAssessmentUpdatedToDB = assessmentRepository.addUserAssesmentDataToDB(userId, assessmentIdentifier, assessmentStartTime, calculateAssessmentSubmitTime(expectedDuration, assessmentStartTime), (Map) (response.getResult().get(Constants.QUESTION_SET)), Constants.NOT_SUBMITTED); redisCacheMgr.putCache(Constants.USER_ASSESS_REQ + assessmentIdentifier + "_" + token, response.getResult().get(Constants.QUESTION_SET)); if (Boolean.FALSE.equals(isAssessmentUpdatedToDB)) { errMsg = Constants.ASSESSMENT_DATA_START_TIME_NOT_UPDATED; } } } - } else if (errMsg.isEmpty() && ((String) assessmentAllDetail.get(Constants.PRIMARY_CATEGORY)) - .equalsIgnoreCase(Constants.PRACTICE_QUESTION_SET)) { - response.getResult().put(Constants.QUESTION_SET, readAssessmentLevelData(assessmentAllDetail)); + } else if (errMsg.isEmpty() && ((String) assessmentAllDetail.get(Constants.PRIMARY_CATEGORY)).equalsIgnoreCase(Constants.PRACTICE_QUESTION_SET)) { + setAssessmentDetail(response, assessmentAllDetail); redisCacheMgr.putCache(Constants.USER_ASSESS_REQ + assessmentIdentifier + "_" + token, response.getResult().get(Constants.QUESTION_SET)); } } else { @@ -147,6 +131,14 @@ public SBApiResponse readAssessment(String assessmentIdentifier, String token) { return response; } + private void setAssessmentDetail(SBApiResponse response, Map assessmentAllDetail) { + if ((Boolean) assessmentAllDetail.get("readAssessmentParams")) { + response.getResult().put(Constants.QUESTION_SET, readAssessmentLevelData(assessmentAllDetail)); + } else { + response.getResult().put(Constants.QUESTION_SET, assessmentAllDetail); + } + } + public SBApiResponse readQuestionList(Map requestBody, String authUserToken) { SBApiResponse response = createDefaultResponse(Constants.API_SUBMIT_ASSESSMENT); String errMsg; @@ -173,10 +165,8 @@ public SBApiResponse readQuestionList(Map requestBody, String au List> newQuestionList = assessUtilServ.readQuestionDetails(newIdentifierList); if (!newQuestionList.isEmpty()) { for (Map questionMap : newQuestionList) { - if (!ObjectUtils.isEmpty(questionMap) && !ObjectUtils.isEmpty(((Map) questionMap.get(Constants.RESULT)) - .get(Constants.QUESTIONS))) { - List> questions = (List>) ((Map) questionMap.get(Constants.RESULT)) - .get(Constants.QUESTIONS); + if (!ObjectUtils.isEmpty(questionMap) && !ObjectUtils.isEmpty(((Map) questionMap.get(Constants.RESULT)).get(Constants.QUESTIONS))) { + List> questions = (List>) ((Map) questionMap.get(Constants.RESULT)).get(Constants.QUESTIONS); for (Map question : questions) { if (!question.isEmpty()) { redisCacheMgr.putCache(Constants.QUESTION_ID + question.get(Constants.IDENTIFIER), question); @@ -211,32 +201,30 @@ private String validateAuthTokenAndFetchUserId(String authUserToken) { return RequestInterceptor.fetchUserIdFromAccessToken(authUserToken); } - private String fetchReadHierarchyDetails(Map assessmentAllDetail, String token, - String assessmentIdentifier) throws IOException { - String assessmentData = redisCacheMgr - .getCache(Constants.ASSESSMENT_ID + assessmentIdentifier); - if (!ObjectUtils.isEmpty(assessmentData)) { - assessmentAllDetail.putAll(mapper.readValue(assessmentData, new TypeReference>() { - })); - } else { - Map readHierarchyApiResponse = assessUtilServ.getReadHierarchyApiResponse(assessmentIdentifier, - token); - if (ObjectUtils.isEmpty(readHierarchyApiResponse) - || !Constants.OK.equalsIgnoreCase((String) readHierarchyApiResponse.get(Constants.RESPONSE_CODE))) { - return Constants.ASSESSMENT_HIERARCHY_READ_FAILED; + private String fetchReadHierarchyDetails(Map assessmentAllDetail, String token, String assessmentIdentifier) throws IOException { + try { + String assessmentData = redisCacheMgr.getCache(Constants.ASSESSMENT_ID + assessmentIdentifier); + if (!ObjectUtils.isEmpty(assessmentData)) { + assessmentAllDetail.putAll(mapper.readValue(assessmentData, new TypeReference>() { + })); + assessmentAllDetail.put("readAssessmentParams", false); + } else { + Map readHierarchyApiResponse = assessUtilServ.getReadHierarchyApiResponse(assessmentIdentifier, token); + if (ObjectUtils.isEmpty(readHierarchyApiResponse) || !Constants.OK.equalsIgnoreCase((String) readHierarchyApiResponse.get(Constants.RESPONSE_CODE))) { + return Constants.ASSESSMENT_HIERARCHY_READ_FAILED; + } + assessmentAllDetail.putAll((Map) ((Map) readHierarchyApiResponse.get(Constants.RESULT)).get(Constants.QUESTION_SET)); + assessmentAllDetail.put("readAssessmentParams", true); + redisCacheMgr.putCache(Constants.ASSESSMENT_ID + assessmentIdentifier, ((Map) readHierarchyApiResponse.get(Constants.RESULT)).get(Constants.QUESTION_SET)); } - assessmentAllDetail - .putAll((Map) ((Map) readHierarchyApiResponse.get(Constants.RESULT)) - .get(Constants.QUESTION_SET)); - redisCacheMgr - .putCache(Constants.ASSESSMENT_ID + assessmentIdentifier, ((Map) readHierarchyApiResponse.get(Constants.RESULT)) - .get(Constants.QUESTION_SET)); + } catch (Exception e) { + logger.info("Error while fetching or mapping read hierarchy data" + e.getMessage()); + return Constants.ASSESSMENT_HIERARCHY_READ_FAILED; } return StringUtils.EMPTY; } - private Map validateQuestionListAPI(Map requestBody, String authUserToken, - List identifierList) throws IOException { + private Map validateQuestionListAPI(Map requestBody, String authUserToken, List identifierList) throws IOException { Map result = new HashMap<>(); String userId = validateAuthTokenAndFetchUserId(authUserToken); if (StringUtils.isBlank(userId)) { @@ -258,23 +246,17 @@ private Map validateQuestionListAPI(Map requestB Map userAssessmentAllDetail; if (errMsg.isEmpty()) { userAssessmentAllDetail = new HashMap<>(); - String userQuestionSet = redisCacheMgr - .getCache(Constants.USER_ASSESS_REQ + assessmentIdFromRequest + "_" + authUserToken); + String userQuestionSet = redisCacheMgr.getCache(Constants.USER_ASSESS_REQ + assessmentIdFromRequest + "_" + authUserToken); if (!ObjectUtils.isEmpty(userQuestionSet)) { userAssessmentAllDetail.putAll(mapper.readValue(userQuestionSet, new TypeReference>() { })); } else if (ObjectUtils.isEmpty(userQuestionSet)) { - if (!((String) assessmentAllDetail.get(Constants.PRIMARY_CATEGORY)) - .equalsIgnoreCase(Constants.PRACTICE_QUESTION_SET)) { - List> existingDataList = assessmentRepository.fetchUserAssessmentDataFromDB(userId, - assessmentIdFromRequest); - String questionSetFromAssessmentString = (!existingDataList.isEmpty()) - ? (String) existingDataList.get(0).get(Constants.ASSESSMENT_READ_RESPONSE) - : ""; + if (!((String) assessmentAllDetail.get(Constants.PRIMARY_CATEGORY)).equalsIgnoreCase(Constants.PRACTICE_QUESTION_SET)) { + List> existingDataList = assessmentRepository.fetchUserAssessmentDataFromDB(userId, assessmentIdFromRequest); + String questionSetFromAssessmentString = (!existingDataList.isEmpty()) ? (String) existingDataList.get(0).get(Constants.ASSESSMENT_READ_RESPONSE) : ""; if (!questionSetFromAssessmentString.isEmpty()) { - userAssessmentAllDetail.putAll(new Gson().fromJson(questionSetFromAssessmentString, - new TypeToken>() { - }.getType())); + userAssessmentAllDetail.putAll(new Gson().fromJson(questionSetFromAssessmentString, new TypeToken>() { + }.getType())); } else { result.put(Constants.ERROR_MESSAGE, Constants.USER_ASSESSMENT_DATA_NOT_PRESENT); return result; @@ -292,8 +274,7 @@ private Map validateQuestionListAPI(Map requestB if (assessmentIdFromDatabase.equalsIgnoreCase(assessmentIdFromRequest)) { result.put(Constants.PRIMARY_CATEGORY, (String) userAssessmentAllDetail.get(Constants.PRIMARY_CATEGORY)); List questionsFromAssessment = new ArrayList<>(); - List> sections = (List>) userAssessmentAllDetail - .get(Constants.CHILDREN); + List> sections = (List>) userAssessmentAllDetail.get(Constants.CHILDREN); for (Map section : sections) { questionsFromAssessment.addAll((List) section.get(Constants.CHILD_NODES)); // Out of the list of questions received in the payload, checking if the request @@ -320,8 +301,7 @@ public SBApiResponse submitAssessment(Map submitRequest, String List> hierarchySectionList = new ArrayList<>(); List questionsListFromAssessmentHierarchy = new ArrayList<>(); Map assessmentHierarchy = new HashMap<>(); - errMsg = validateSubmitAssessmentRequest(submitRequest, authUserToken, hierarchySectionList, - sectionListFromSubmitRequest, assessmentHierarchy); + errMsg = validateSubmitAssessmentRequest(submitRequest, authUserToken, hierarchySectionList, sectionListFromSubmitRequest, assessmentHierarchy); if (errMsg.isEmpty()) { String userId = validateAuthTokenAndFetchUserId(authUserToken); String scoreCutOffType = ((String) assessmentHierarchy.get(Constants.SCORE_CUTOFF_TYPE)).toLowerCase(); @@ -338,35 +318,26 @@ public SBApiResponse submitAssessment(Map submitRequest, String break; } } - if (!((String) (assessmentHierarchy.get(Constants.PRIMARY_CATEGORY))) - .equalsIgnoreCase(Constants.PRACTICE_QUESTION_SET)) { + if (!((String) (assessmentHierarchy.get(Constants.PRIMARY_CATEGORY))).equalsIgnoreCase(Constants.PRACTICE_QUESTION_SET)) { Map questionSetFromAssessment = new HashMap<>(); - String assessmentData = redisCacheMgr - .getCache(Constants.USER_ASSESS_REQ + (String) submitRequest.get(Constants.IDENTIFIER) + "_" + authUserToken); + String assessmentData = redisCacheMgr.getCache(Constants.USER_ASSESS_REQ + (String) submitRequest.get(Constants.IDENTIFIER) + "_" + authUserToken); if (!ObjectUtils.isEmpty(assessmentData)) { questionSetFromAssessment.putAll(mapper.readValue(assessmentData, new TypeReference>() { - })); + })); } else { - existingDataList = assessmentRepository.fetchUserAssessmentDataFromDB(userId, - (String) submitRequest.get(Constants.IDENTIFIER)); - String questionSetFromAssessmentString = (!existingDataList.isEmpty()) - ? (String) existingDataList.get(0).get(Constants.ASSESSMENT_READ_RESPONSE) - : ""; + existingDataList = assessmentRepository.fetchUserAssessmentDataFromDB(userId, (String) submitRequest.get(Constants.IDENTIFIER)); + String questionSetFromAssessmentString = (!existingDataList.isEmpty()) ? (String) existingDataList.get(0).get(Constants.ASSESSMENT_READ_RESPONSE) : ""; if (!questionSetFromAssessmentString.isEmpty()) { - questionSetFromAssessment = new Gson() - .fromJson(questionSetFromAssessmentString, new TypeToken>() { - }.getType()); + questionSetFromAssessment = new Gson().fromJson(questionSetFromAssessmentString, new TypeToken>() { + }.getType()); } } - if (questionSetFromAssessment != null - && questionSetFromAssessment.get(Constants.CHILDREN) != null) { - List> sections = (List>) questionSetFromAssessment - .get(Constants.CHILDREN); + if (questionSetFromAssessment != null && questionSetFromAssessment.get(Constants.CHILDREN) != null) { + List> sections = (List>) questionSetFromAssessment.get(Constants.CHILDREN); for (Map section : sections) { String sectionId = (String) section.get(Constants.IDENTIFIER); if (userSectionId.equalsIgnoreCase(sectionId)) { - questionsListFromAssessmentHierarchy = (List) section - .get(Constants.CHILD_NODES); + questionsListFromAssessmentHierarchy = (List) section.get(Constants.CHILD_NODES); break; } } @@ -378,26 +349,19 @@ public SBApiResponse submitAssessment(Map submitRequest, String hierarchySection.put(Constants.SCORE_CUTOFF_TYPE, scoreCutOffType); List> questionsListFromSubmitRequest = new ArrayList<>(); - if (userSectionData.containsKey(Constants.CHILDREN) - && !ObjectUtils.isEmpty(userSectionData.get(Constants.CHILDREN))) { - questionsListFromSubmitRequest = (List>) userSectionData - .get(Constants.CHILDREN); + if (userSectionData.containsKey(Constants.CHILDREN) && !ObjectUtils.isEmpty(userSectionData.get(Constants.CHILDREN))) { + questionsListFromSubmitRequest = (List>) userSectionData.get(Constants.CHILDREN); } Map result = new HashMap<>(); switch (scoreCutOffType) { case Constants.ASSESSMENT_LEVEL_SCORE_CUTOFF: { - result.putAll(createResponseMapWithProperStructure(hierarchySection, - assessUtilServ.validateQumlAssessment(questionsListFromAssessmentHierarchy, - questionsListFromSubmitRequest))); + result.putAll(createResponseMapWithProperStructure(hierarchySection, assessUtilServ.validateQumlAssessment(questionsListFromAssessmentHierarchy, questionsListFromSubmitRequest))); outgoingResponse.getResult().putAll(calculateAssessmentFinalResults(result)); - writeDataToDatabaseAndTriggerKafkaEvent(submitRequest, userId, existingDataList, result, - (String) assessmentHierarchy.get(Constants.PRIMARY_CATEGORY)); + writeDataToDatabaseAndTriggerKafkaEvent(submitRequest, userId, existingDataList, result, (String) assessmentHierarchy.get(Constants.PRIMARY_CATEGORY)); return outgoingResponse; } case Constants.SECTION_LEVEL_SCORE_CUTOFF: { - result.putAll(createResponseMapWithProperStructure(hierarchySection, - assessUtilServ.validateQumlAssessment(questionsListFromAssessmentHierarchy, - questionsListFromSubmitRequest))); + result.putAll(createResponseMapWithProperStructure(hierarchySection, assessUtilServ.validateQumlAssessment(questionsListFromAssessmentHierarchy, questionsListFromSubmitRequest))); sectionLevelsResults.add(result); } break; @@ -408,29 +372,21 @@ public SBApiResponse submitAssessment(Map submitRequest, String } else { hierarchySection.put(Constants.SCORE_CUTOFF_TYPE, scoreCutOffType); List> questionsListFromSubmitRequest = new ArrayList<>(); - if (userSectionData.containsKey(Constants.CHILDREN) - && !ObjectUtils.isEmpty(userSectionData.get(Constants.CHILDREN))) { - questionsListFromSubmitRequest = (List>) userSectionData - .get(Constants.CHILDREN); + if (userSectionData.containsKey(Constants.CHILDREN) && !ObjectUtils.isEmpty(userSectionData.get(Constants.CHILDREN))) { + questionsListFromSubmitRequest = (List>) userSectionData.get(Constants.CHILDREN); } List desiredKeys = Lists.newArrayList(Constants.IDENTIFIER); - List questionsList = questionsListFromSubmitRequest.stream() - .flatMap(x -> desiredKeys.stream().filter(x::containsKey).map(x::get)).collect(toList()); - questionsListFromAssessmentHierarchy = questionsList.stream() - .map(object -> Objects.toString(object, null)).collect(Collectors.toList()); + List questionsList = questionsListFromSubmitRequest.stream().flatMap(x -> desiredKeys.stream().filter(x::containsKey).map(x::get)).collect(toList()); + questionsListFromAssessmentHierarchy = questionsList.stream().map(object -> Objects.toString(object, null)).collect(Collectors.toList()); Map result = new HashMap<>(); switch (scoreCutOffType) { case Constants.ASSESSMENT_LEVEL_SCORE_CUTOFF: { - result.putAll(createResponseMapWithProperStructure(hierarchySection, - assessUtilServ.validateQumlAssessment(questionsListFromAssessmentHierarchy, - questionsListFromSubmitRequest))); + result.putAll(createResponseMapWithProperStructure(hierarchySection, assessUtilServ.validateQumlAssessment(questionsListFromAssessmentHierarchy, questionsListFromSubmitRequest))); outgoingResponse.getResult().putAll(calculateAssessmentFinalResults(result)); return outgoingResponse; } case Constants.SECTION_LEVEL_SCORE_CUTOFF: { - result.putAll(createResponseMapWithProperStructure(hierarchySection, - assessUtilServ.validateQumlAssessment(questionsListFromAssessmentHierarchy, - questionsListFromSubmitRequest))); + result.putAll(createResponseMapWithProperStructure(hierarchySection, assessUtilServ.validateQumlAssessment(questionsListFromAssessmentHierarchy, questionsListFromSubmitRequest))); sectionLevelsResults.add(result); } break; @@ -439,12 +395,10 @@ public SBApiResponse submitAssessment(Map submitRequest, String } } } - if (errMsg.isEmpty() && !ObjectUtils.isEmpty(scoreCutOffType) - && scoreCutOffType.equalsIgnoreCase(Constants.SECTION_LEVEL_SCORE_CUTOFF)) { + if (errMsg.isEmpty() && !ObjectUtils.isEmpty(scoreCutOffType) && scoreCutOffType.equalsIgnoreCase(Constants.SECTION_LEVEL_SCORE_CUTOFF)) { Map result = calculateSectionFinalResults(sectionLevelsResults); outgoingResponse.getResult().putAll(result); - writeDataToDatabaseAndTriggerKafkaEvent(submitRequest, userId, existingDataList, result, - (String) assessmentHierarchy.get(Constants.PRIMARY_CATEGORY)); + writeDataToDatabaseAndTriggerKafkaEvent(submitRequest, userId, existingDataList, result, (String) assessmentHierarchy.get(Constants.PRIMARY_CATEGORY)); return outgoingResponse; } } @@ -456,14 +410,10 @@ public SBApiResponse submitAssessment(Map submitRequest, String return outgoingResponse; } - private void writeDataToDatabaseAndTriggerKafkaEvent(Map submitRequest, String userId, - List> existingDataList, Map result, String primaryCategory) { + private void writeDataToDatabaseAndTriggerKafkaEvent(Map submitRequest, String userId, List> existingDataList, Map result, String primaryCategory) { try { - Date startTime = (!existingDataList.isEmpty()) ? (Date) existingDataList.get(0).get(Constants.START_TIME) - : null; - Boolean isAssessmentUpdatedToDB = assessmentRepository.updateUserAssesmentDataToDB(userId, - (String) submitRequest.get(Constants.IDENTIFIER), submitRequest, result, Constants.SUBMITTED, - startTime); + Date startTime = (!existingDataList.isEmpty()) ? (Date) existingDataList.get(0).get(Constants.START_TIME) : null; + Boolean isAssessmentUpdatedToDB = assessmentRepository.updateUserAssesmentDataToDB(userId, (String) submitRequest.get(Constants.IDENTIFIER), submitRequest, result, Constants.SUBMITTED, startTime); if (Boolean.TRUE.equals(isAssessmentUpdatedToDB)) { Map kafkaResult = new HashMap<>(); kafkaResult.put(Constants.CONTENT_ID_KEY, submitRequest.get(Constants.IDENTIFIER)); @@ -493,9 +443,7 @@ private void writeDataToDatabaseAndTriggerKafkaEvent(Map submitR } } - private String validateSubmitAssessmentRequest(Map submitRequest, String authUserToken, - List> hierarchySectionList, List> sectionListFromSubmitRequest, - Map assessmentHierarchy) throws IOException { + private String validateSubmitAssessmentRequest(Map submitRequest, String authUserToken, List> hierarchySectionList, List> sectionListFromSubmitRequest, Map assessmentHierarchy) throws IOException { String userId = validateAuthTokenAndFetchUserId(authUserToken); if (ObjectUtils.isEmpty(userId)) { return Constants.USER_ID_DOESNT_EXIST; @@ -514,14 +462,10 @@ private String validateSubmitAssessmentRequest(Map submitRequest } hierarchySectionList.addAll((List>) assessmentHierarchy.get(Constants.CHILDREN)); sectionListFromSubmitRequest.addAll((List>) submitRequest.get(Constants.CHILDREN)); - if (((String) (assessmentHierarchy.get(Constants.PRIMARY_CATEGORY))) - .equalsIgnoreCase(Constants.PRACTICE_QUESTION_SET)) + if (((String) (assessmentHierarchy.get(Constants.PRIMARY_CATEGORY))).equalsIgnoreCase(Constants.PRACTICE_QUESTION_SET)) return ""; - List> existingDataList = assessmentRepository.fetchUserAssessmentDataFromDB(userId, - assessmentIdFromRequest); - Date assessmentStartTime = (!existingDataList.isEmpty()) - ? (Date) existingDataList.get(0).get(Constants.START_TIME) - : null; + List> existingDataList = assessmentRepository.fetchUserAssessmentDataFromDB(userId, assessmentIdFromRequest); + Date assessmentStartTime = (!existingDataList.isEmpty()) ? (Date) existingDataList.get(0).get(Constants.START_TIME) : null; if (assessmentStartTime == null) { return Constants.READ_ASSESSMENT_START_TIME_FAILED; } @@ -531,17 +475,13 @@ private String validateSubmitAssessmentRequest(Map submitRequest int time = submissionTime.compareTo(later); if (time <= 0) { List desiredKeys = Lists.newArrayList(Constants.IDENTIFIER); - List hierarchySectionIds = hierarchySectionList.stream() - .flatMap(x -> desiredKeys.stream().filter(x::containsKey).map(x::get)).collect(toList()); - List submitSectionIds = sectionListFromSubmitRequest.stream() - .flatMap(x -> desiredKeys.stream().filter(x::containsKey).map(x::get)).collect(toList()); + List hierarchySectionIds = hierarchySectionList.stream().flatMap(x -> desiredKeys.stream().filter(x::containsKey).map(x::get)).collect(toList()); + List submitSectionIds = sectionListFromSubmitRequest.stream().flatMap(x -> desiredKeys.stream().filter(x::containsKey).map(x::get)).collect(toList()); if (!new HashSet<>(hierarchySectionIds).containsAll(submitSectionIds)) { return Constants.WRONG_SECTION_DETAILS; } else { - String areQuestionIdsSame = validateIfQuestionIdsAreSame(submitRequest, sectionListFromSubmitRequest, - desiredKeys, userId); - if (!areQuestionIdsSame.isEmpty()) - return areQuestionIdsSame; + String areQuestionIdsSame = validateIfQuestionIdsAreSame(submitRequest, sectionListFromSubmitRequest, desiredKeys, userId); + if (!areQuestionIdsSame.isEmpty()) return areQuestionIdsSame; } } else { return Constants.ASSESSMENT_SUBMIT_EXPIRED; @@ -549,38 +489,27 @@ private String validateSubmitAssessmentRequest(Map submitRequest return ""; } - private String validateIfQuestionIdsAreSame(Map submitRequest, - List> sectionListFromSubmitRequest, List desiredKeys, String userId) { - List> existingDataList = assessmentRepository.fetchUserAssessmentDataFromDB(userId, - (String) submitRequest.get(Constants.IDENTIFIER)); - String questionSetFromAssessmentString = (!existingDataList.isEmpty()) - ? (String) existingDataList.get(0).get(Constants.ASSESSMENT_READ_RESPONSE) - : ""; + private String validateIfQuestionIdsAreSame(Map submitRequest, List> sectionListFromSubmitRequest, List desiredKeys, String userId) { + List> existingDataList = assessmentRepository.fetchUserAssessmentDataFromDB(userId, (String) submitRequest.get(Constants.IDENTIFIER)); + String questionSetFromAssessmentString = (!existingDataList.isEmpty()) ? (String) existingDataList.get(0).get(Constants.ASSESSMENT_READ_RESPONSE) : ""; if (!questionSetFromAssessmentString.isEmpty()) { - Map questionSetFromAssessment = new Gson().fromJson(questionSetFromAssessmentString, - new TypeToken>() { - }.getType()); + Map questionSetFromAssessment = new Gson().fromJson(questionSetFromAssessmentString, new TypeToken>() { + }.getType()); if (questionSetFromAssessment != null && questionSetFromAssessment.get(Constants.CHILDREN) != null) { - List> sections = (List>) questionSetFromAssessment - .get(Constants.CHILDREN); + List> sections = (List>) questionSetFromAssessment.get(Constants.CHILDREN); List desiredKey = Lists.newArrayList(Constants.CHILD_NODES); - List questionList = sections.stream() - .flatMap(x -> desiredKey.stream().filter(x::containsKey).map(x::get)).collect(toList()); + List questionList = sections.stream().flatMap(x -> desiredKey.stream().filter(x::containsKey).map(x::get)).collect(toList()); List questionIdsFromAssessmentHierarchy = new ArrayList<>(); List> questionsListFromSubmitRequest = new ArrayList<>(); for (Object question : questionList) { questionIdsFromAssessmentHierarchy.addAll((List) question); } for (Map userSectionData : sectionListFromSubmitRequest) { - if (userSectionData.containsKey(Constants.CHILDREN) - && !ObjectUtils.isEmpty(userSectionData.get(Constants.CHILDREN))) { - questionsListFromSubmitRequest - .addAll((List>) userSectionData.get(Constants.CHILDREN)); + if (userSectionData.containsKey(Constants.CHILDREN) && !ObjectUtils.isEmpty(userSectionData.get(Constants.CHILDREN))) { + questionsListFromSubmitRequest.addAll((List>) userSectionData.get(Constants.CHILDREN)); } } - List userQuestionIdsFromSubmitRequest = questionsListFromSubmitRequest.stream() - .flatMap(x -> desiredKeys.stream().filter(x::containsKey).map(x::get)) - .collect(Collectors.toList()); + List userQuestionIdsFromSubmitRequest = questionsListFromSubmitRequest.stream().flatMap(x -> desiredKeys.stream().filter(x::containsKey).map(x::get)).collect(Collectors.toList()); if (!new HashSet<>(questionIdsFromAssessmentHierarchy).containsAll(userQuestionIdsFromSubmitRequest)) { return Constants.ASSESSMENT_SUBMIT_INVALID_QUESTION; } @@ -597,8 +526,7 @@ private Timestamp calculateAssessmentSubmitTime(int expectedDuration, Date asses if (serverProperties.getUserAssessmentSubmissionDuration().isEmpty()) { serverProperties.setUserAssessmentSubmissionDuration("120"); } - cal.add(Calendar.SECOND, - expectedDuration + Integer.parseInt(serverProperties.getUserAssessmentSubmissionDuration())); + cal.add(Calendar.SECOND, expectedDuration + Integer.parseInt(serverProperties.getUserAssessmentSubmissionDuration())); return new Timestamp(cal.getTime().getTime()); } @@ -668,8 +596,7 @@ private Map readAssessmentLevelData(Map assessme return assessmentFilteredDetail; } - private void readSectionLevelParams(Map assessmentAllDetail, - Map assessmentFilteredDetail) { + private void readSectionLevelParams(Map assessmentAllDetail, Map assessmentFilteredDetail) { List> sectionResponse = new ArrayList<>(); List sectionIdList = new ArrayList<>(); List sectionParams = serverProperties.getAssessmentSectionParams(); @@ -706,8 +633,7 @@ private List getQuestionIdList(Map questionListRequest) Map request = (Map) questionListRequest.get(Constants.REQUEST); if ((!ObjectUtils.isEmpty(request)) && request.containsKey(Constants.SEARCH)) { Map searchObj = (Map) request.get(Constants.SEARCH); - if (!ObjectUtils.isEmpty(searchObj) && searchObj.containsKey(Constants.IDENTIFIER) - && !CollectionUtils.isEmpty((List) searchObj.get(Constants.IDENTIFIER))) { + if (!ObjectUtils.isEmpty(searchObj) && searchObj.containsKey(Constants.IDENTIFIER) && !CollectionUtils.isEmpty((List) searchObj.get(Constants.IDENTIFIER))) { return (List) searchObj.get(Constants.IDENTIFIER); } } @@ -718,8 +644,7 @@ private List getQuestionIdList(Map questionListRequest) return Collections.emptyList(); } - public Map createResponseMapWithProperStructure(Map hierarchySection, - Map resultMap) { + public Map createResponseMapWithProperStructure(Map hierarchySection, Map resultMap) { Map sectionLevelResult = new HashMap<>(); sectionLevelResult.put(Constants.IDENTIFIER, hierarchySection.get(Constants.IDENTIFIER)); sectionLevelResult.put(Constants.OBJECT_TYPE, hierarchySection.get(Constants.OBJECT_TYPE)); @@ -742,8 +667,7 @@ public Map createResponseMapWithProperStructure(Map= ((Integer) hierarchySection.get(Constants.MINIMUM_PASS_PERCENTAGE))); + sectionLevelResult.put(Constants.PASS, result >= ((Integer) hierarchySection.get(Constants.MINIMUM_PASS_PERCENTAGE))); sectionLevelResult.put(Constants.OVERALL_RESULT, result); return sectionLevelResult; } @@ -772,16 +696,14 @@ public SBApiResponse retakeAssessment(String assessmentIdentifier, String token) try { String userId = validateAuthTokenAndFetchUserId(token); if (userId != null) { - List> existingDataList = assessmentRepository.fetchUserAssessmentDataFromDB(userId, - assessmentIdentifier); + List> existingDataList = assessmentRepository.fetchUserAssessmentDataFromDB(userId, assessmentIdentifier); Map assessmentAllDetail = new HashMap<>(); errMsg = fetchReadHierarchyDetails(assessmentAllDetail, token, assessmentIdentifier); if (assessmentAllDetail.get(Constants.MAX_ASSESSMENT_RETAKE_ATTEMPTS) != null) { retakeAttemptsAllowed = (int) assessmentAllDetail.get(Constants.MAX_ASSESSMENT_RETAKE_ATTEMPTS); } retakeAttemptsConsumed = calculateAssessmentRetakeCount(existingDataList); - } - else { + } else { errMsg = Constants.USER_ID_DOESNT_EXIST; } } catch (Exception e) { @@ -801,11 +723,7 @@ public SBApiResponse retakeAssessment(String assessmentIdentifier, String token) private int calculateAssessmentRetakeCount(List> userAssessmentData) { List desiredKeys = Lists.newArrayList(Constants.SUBMIT_ASSESSMENT_RESPONSE); - List values = userAssessmentData.stream() - .flatMap(x -> desiredKeys.stream() - .filter(x::containsKey) - .map(x::get) - ).collect(toList()); + List values = userAssessmentData.stream().flatMap(x -> desiredKeys.stream().filter(x::containsKey).map(x::get)).collect(toList()); Iterables.removeIf(values, Predicates.isNull()); return values.size(); } From 014336874de940b1c02e4835fb9d50cd6e22fdd5 Mon Sep 17 00:00:00 2001 From: Juhi Date: Fri, 20 Jan 2023 16:40:28 +0530 Subject: [PATCH 10/21] changes --- .../sunbird/assessment/service/AssessmentServiceV2Impl.java | 3 +++ .../assessment/service/AssessmentUtilServiceV2Impl.java | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java b/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java index dea76321d..3293c612f 100644 --- a/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java +++ b/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java @@ -210,11 +210,14 @@ private String fetchReadHierarchyDetails(Map assessmentAllDetail assessmentAllDetail.put("readAssessmentParams", false); } else { Map readHierarchyApiResponse = assessUtilServ.getReadHierarchyApiResponse(assessmentIdentifier, token); + logger.info(readHierarchyApiResponse.toString()); if (ObjectUtils.isEmpty(readHierarchyApiResponse) || !Constants.OK.equalsIgnoreCase((String) readHierarchyApiResponse.get(Constants.RESPONSE_CODE))) { return Constants.ASSESSMENT_HIERARCHY_READ_FAILED; } assessmentAllDetail.putAll((Map) ((Map) readHierarchyApiResponse.get(Constants.RESULT)).get(Constants.QUESTION_SET)); + logger.info(assessmentAllDetail.toString()); assessmentAllDetail.put("readAssessmentParams", true); + logger.info(assessmentAllDetail.toString()); redisCacheMgr.putCache(Constants.ASSESSMENT_ID + assessmentIdentifier, ((Map) readHierarchyApiResponse.get(Constants.RESULT)).get(Constants.QUESTION_SET)); } } catch (Exception e) { diff --git a/src/main/java/org/sunbird/assessment/service/AssessmentUtilServiceV2Impl.java b/src/main/java/org/sunbird/assessment/service/AssessmentUtilServiceV2Impl.java index 6a2451127..54720c873 100644 --- a/src/main/java/org/sunbird/assessment/service/AssessmentUtilServiceV2Impl.java +++ b/src/main/java/org/sunbird/assessment/service/AssessmentUtilServiceV2Impl.java @@ -313,7 +313,7 @@ public Map getReadHierarchyApiResponse(String assessmentIdentifi Object o = outboundRequestHandlerService.fetchUsingGetWithHeaders(serviceURL, headers); return new ObjectMapper().convertValue(o, Map.class); } catch (Exception e) { - logger.error(e.getMessage()); + logger.error("error in getReadHierarchyApiResponse " + e.getMessage()); } return new HashMap<>(); } From 8ac5c83ff1ee3bc8f28ece6eb807ec58aad2afdb Mon Sep 17 00:00:00 2001 From: Juhi Date: Fri, 20 Jan 2023 16:41:58 +0530 Subject: [PATCH 11/21] changes --- .../sunbird/assessment/service/AssessmentUtilServiceV2Impl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/sunbird/assessment/service/AssessmentUtilServiceV2Impl.java b/src/main/java/org/sunbird/assessment/service/AssessmentUtilServiceV2Impl.java index 54720c873..5803ffa01 100644 --- a/src/main/java/org/sunbird/assessment/service/AssessmentUtilServiceV2Impl.java +++ b/src/main/java/org/sunbird/assessment/service/AssessmentUtilServiceV2Impl.java @@ -310,6 +310,7 @@ public Map getReadHierarchyApiResponse(String assessmentIdentifi Map headers = new HashMap<>(); headers.put(Constants.X_AUTH_TOKEN, token); headers.put(Constants.AUTHORIZATION, serverProperties.getSbApiKey()); + logger.info(serviceURL); Object o = outboundRequestHandlerService.fetchUsingGetWithHeaders(serviceURL, headers); return new ObjectMapper().convertValue(o, Map.class); } catch (Exception e) { From ec8026b0552d6fb2d813e2cd98254bfb0f5bba37 Mon Sep 17 00:00:00 2001 From: Juhi Date: Fri, 20 Jan 2023 17:03:47 +0530 Subject: [PATCH 12/21] changes --- pom.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pom.xml b/pom.xml index a0501d899..a945d1ec5 100644 --- a/pom.xml +++ b/pom.xml @@ -171,6 +171,15 @@ poi-ooxml 3.11 + + + + org.jboss.resteasy + resteasy-client + 6.2.2.Final + + + redis.clients jedis From ace6639af8f3405a95a9b8e0b450b7491e5f3930 Mon Sep 17 00:00:00 2001 From: Juhi Date: Fri, 20 Jan 2023 17:04:42 +0530 Subject: [PATCH 13/21] changes --- pom.xml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/pom.xml b/pom.xml index a945d1ec5..985db8758 100644 --- a/pom.xml +++ b/pom.xml @@ -172,14 +172,6 @@ 3.11 - - - org.jboss.resteasy - resteasy-client - 6.2.2.Final - - - redis.clients jedis From 232f3e7a997293b9c3d9ce38d2ca67a44c3616f5 Mon Sep 17 00:00:00 2001 From: Juhi Date: Fri, 20 Jan 2023 17:18:57 +0530 Subject: [PATCH 14/21] changes --- .../sunbird/assessment/service/AssessmentServiceV2Impl.java | 6 +++++- .../assessment/service/AssessmentUtilServiceV2Impl.java | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java b/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java index 3293c612f..5e940b5a4 100644 --- a/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java +++ b/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java @@ -204,13 +204,17 @@ private String validateAuthTokenAndFetchUserId(String authUserToken) { private String fetchReadHierarchyDetails(Map assessmentAllDetail, String token, String assessmentIdentifier) throws IOException { try { String assessmentData = redisCacheMgr.getCache(Constants.ASSESSMENT_ID + assessmentIdentifier); + logger.info("Reading assessmentData from redis" + assessmentData); if (!ObjectUtils.isEmpty(assessmentData)) { assessmentAllDetail.putAll(mapper.readValue(assessmentData, new TypeReference>() { })); + logger.info(assessmentAllDetail.toString()); assessmentAllDetail.put("readAssessmentParams", false); + logger.info(assessmentAllDetail.toString()); } else { Map readHierarchyApiResponse = assessUtilServ.getReadHierarchyApiResponse(assessmentIdentifier, token); - logger.info(readHierarchyApiResponse.toString()); + if (!readHierarchyApiResponse.isEmpty()) + logger.info(readHierarchyApiResponse.toString()); if (ObjectUtils.isEmpty(readHierarchyApiResponse) || !Constants.OK.equalsIgnoreCase((String) readHierarchyApiResponse.get(Constants.RESPONSE_CODE))) { return Constants.ASSESSMENT_HIERARCHY_READ_FAILED; } diff --git a/src/main/java/org/sunbird/assessment/service/AssessmentUtilServiceV2Impl.java b/src/main/java/org/sunbird/assessment/service/AssessmentUtilServiceV2Impl.java index 5803ffa01..776ea50b6 100644 --- a/src/main/java/org/sunbird/assessment/service/AssessmentUtilServiceV2Impl.java +++ b/src/main/java/org/sunbird/assessment/service/AssessmentUtilServiceV2Impl.java @@ -312,7 +312,9 @@ public Map getReadHierarchyApiResponse(String assessmentIdentifi headers.put(Constants.AUTHORIZATION, serverProperties.getSbApiKey()); logger.info(serviceURL); Object o = outboundRequestHandlerService.fetchUsingGetWithHeaders(serviceURL, headers); - return new ObjectMapper().convertValue(o, Map.class); + Map data = new ObjectMapper().convertValue(o, Map.class); + logger.info(data.toString()); + return data; } catch (Exception e) { logger.error("error in getReadHierarchyApiResponse " + e.getMessage()); } From 03f7668c6d681c4e77119501779039fb719e8c26 Mon Sep 17 00:00:00 2001 From: Juhi Date: Mon, 23 Jan 2023 23:15:12 +0530 Subject: [PATCH 15/21] changes --- .../org/sunbird/assessment/service/AssessmentServiceV2Impl.java | 1 - .../sunbird/assessment/service/AssessmentUtilServiceV2Impl.java | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java b/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java index 5e940b5a4..4e87dab45 100644 --- a/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java +++ b/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java @@ -9,7 +9,6 @@ import com.google.gson.reflect.TypeToken; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang3.time.DateUtils; import org.joda.time.DateTime; import org.mortbay.util.ajax.JSON; import org.slf4j.Logger; diff --git a/src/main/java/org/sunbird/assessment/service/AssessmentUtilServiceV2Impl.java b/src/main/java/org/sunbird/assessment/service/AssessmentUtilServiceV2Impl.java index 776ea50b6..759d07cd6 100644 --- a/src/main/java/org/sunbird/assessment/service/AssessmentUtilServiceV2Impl.java +++ b/src/main/java/org/sunbird/assessment/service/AssessmentUtilServiceV2Impl.java @@ -260,6 +260,7 @@ public Map filterQuestionMapDetail(Map questionM && updatedQuestionMap.containsKey(Constants.PRIMARY_CATEGORY) && updatedQuestionMap .get(Constants.PRIMARY_CATEGORY).toString().equalsIgnoreCase(Constants.MTF_QUESTION)) { List rhsChoicesObj = (List) questionMapResponse.get(Constants.RHS_CHOICES); + Collections.shuffle(rhsChoicesObj); updatedQuestionMap.put(Constants.RHS_CHOICES, rhsChoicesObj); } From cb45daea308d6a3e6c9ad7092465c02fd938dfa8 Mon Sep 17 00:00:00 2001 From: Juhi Date: Tue, 24 Jan 2023 00:01:31 +0530 Subject: [PATCH 16/21] changes --- .../assessment/service/AssessmentServiceV2Impl.java | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java b/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java index 4e87dab45..d95f9c7d6 100644 --- a/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java +++ b/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java @@ -77,7 +77,7 @@ public SBApiResponse readAssessment(String assessmentIdentifier, String token) { Timestamp assessmentStartTime = new Timestamp(new Date().getTime()); if (existingDataList.isEmpty()) { logger.info("Assessment read first time for user."); - setAssessmentDetail(response, assessmentAllDetail); + response.getResult().put(Constants.QUESTION_SET, readAssessmentLevelData(assessmentAllDetail)); redisCacheMgr.putCache(Constants.USER_ASSESS_REQ + assessmentIdentifier + "_" + token, response.getResult().get(Constants.QUESTION_SET)); int expectedDuration = (Integer) assessmentAllDetail.get(Constants.EXPECTED_DURATION); Boolean isAssessmentUpdatedToDB = assessmentRepository.addUserAssesmentDataToDB(userId, assessmentIdentifier, assessmentStartTime, calculateAssessmentSubmitTime(expectedDuration, assessmentStartTime), (Map) (response.getResult().get(Constants.QUESTION_SET)), Constants.NOT_SUBMITTED); @@ -102,7 +102,7 @@ public SBApiResponse readAssessment(String assessmentIdentifier, String token) { response.getResult().put(Constants.QUESTION_SET, questionSetFromAssessment); } else { logger.info("Assessment read... adding user data to db..."); - setAssessmentDetail(response, assessmentAllDetail); + response.getResult().put(Constants.QUESTION_SET, readAssessmentLevelData(assessmentAllDetail)); int expectedDuration = (Integer) assessmentAllDetail.get(Constants.EXPECTED_DURATION); Boolean isAssessmentUpdatedToDB = assessmentRepository.addUserAssesmentDataToDB(userId, assessmentIdentifier, assessmentStartTime, calculateAssessmentSubmitTime(expectedDuration, assessmentStartTime), (Map) (response.getResult().get(Constants.QUESTION_SET)), Constants.NOT_SUBMITTED); redisCacheMgr.putCache(Constants.USER_ASSESS_REQ + assessmentIdentifier + "_" + token, response.getResult().get(Constants.QUESTION_SET)); @@ -112,7 +112,7 @@ public SBApiResponse readAssessment(String assessmentIdentifier, String token) { } } } else if (errMsg.isEmpty() && ((String) assessmentAllDetail.get(Constants.PRIMARY_CATEGORY)).equalsIgnoreCase(Constants.PRACTICE_QUESTION_SET)) { - setAssessmentDetail(response, assessmentAllDetail); + response.getResult().put(Constants.QUESTION_SET, readAssessmentLevelData(assessmentAllDetail)); redisCacheMgr.putCache(Constants.USER_ASSESS_REQ + assessmentIdentifier + "_" + token, response.getResult().get(Constants.QUESTION_SET)); } } else { @@ -207,20 +207,13 @@ private String fetchReadHierarchyDetails(Map assessmentAllDetail if (!ObjectUtils.isEmpty(assessmentData)) { assessmentAllDetail.putAll(mapper.readValue(assessmentData, new TypeReference>() { })); - logger.info(assessmentAllDetail.toString()); - assessmentAllDetail.put("readAssessmentParams", false); - logger.info(assessmentAllDetail.toString()); } else { Map readHierarchyApiResponse = assessUtilServ.getReadHierarchyApiResponse(assessmentIdentifier, token); if (!readHierarchyApiResponse.isEmpty()) - logger.info(readHierarchyApiResponse.toString()); if (ObjectUtils.isEmpty(readHierarchyApiResponse) || !Constants.OK.equalsIgnoreCase((String) readHierarchyApiResponse.get(Constants.RESPONSE_CODE))) { return Constants.ASSESSMENT_HIERARCHY_READ_FAILED; } assessmentAllDetail.putAll((Map) ((Map) readHierarchyApiResponse.get(Constants.RESULT)).get(Constants.QUESTION_SET)); - logger.info(assessmentAllDetail.toString()); - assessmentAllDetail.put("readAssessmentParams", true); - logger.info(assessmentAllDetail.toString()); redisCacheMgr.putCache(Constants.ASSESSMENT_ID + assessmentIdentifier, ((Map) readHierarchyApiResponse.get(Constants.RESULT)).get(Constants.QUESTION_SET)); } } catch (Exception e) { From bd611a4fc03a4ac8d34ac3fd718520bf7de4777a Mon Sep 17 00:00:00 2001 From: Juhi Date: Tue, 24 Jan 2023 11:59:39 +0530 Subject: [PATCH 17/21] changes --- .../assessment/service/AssessmentServiceV2Impl.java | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java b/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java index d95f9c7d6..6b4835729 100644 --- a/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java +++ b/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java @@ -100,8 +100,8 @@ public SBApiResponse readAssessment(String assessmentIdentifier, String token) { redisCacheMgr.putCache(Constants.USER_ASSESS_REQ + assessmentIdentifier + "_" + token, questionSetFromAssessment); } response.getResult().put(Constants.QUESTION_SET, questionSetFromAssessment); - } else { - logger.info("Assessment read... adding user data to db..."); + } else if ((assessmentStartTime.compareTo(existingAssessmentEndTime) < 0 && ((String) existingDataList.get(0).get(Constants.STATUS)).equalsIgnoreCase(Constants.SUBMITTED)) || assessmentStartTime.compareTo(existingAssessmentEndTime) > 0) { + logger.info("Incase the assessment is submitted before the end time, or the endtime has exceeded, read assessment freshly "); response.getResult().put(Constants.QUESTION_SET, readAssessmentLevelData(assessmentAllDetail)); int expectedDuration = (Integer) assessmentAllDetail.get(Constants.EXPECTED_DURATION); Boolean isAssessmentUpdatedToDB = assessmentRepository.addUserAssesmentDataToDB(userId, assessmentIdentifier, assessmentStartTime, calculateAssessmentSubmitTime(expectedDuration, assessmentStartTime), (Map) (response.getResult().get(Constants.QUESTION_SET)), Constants.NOT_SUBMITTED); @@ -130,14 +130,6 @@ public SBApiResponse readAssessment(String assessmentIdentifier, String token) { return response; } - private void setAssessmentDetail(SBApiResponse response, Map assessmentAllDetail) { - if ((Boolean) assessmentAllDetail.get("readAssessmentParams")) { - response.getResult().put(Constants.QUESTION_SET, readAssessmentLevelData(assessmentAllDetail)); - } else { - response.getResult().put(Constants.QUESTION_SET, assessmentAllDetail); - } - } - public SBApiResponse readQuestionList(Map requestBody, String authUserToken) { SBApiResponse response = createDefaultResponse(Constants.API_SUBMIT_ASSESSMENT); String errMsg; From 2e474a70ed7239c7275f23a039723ba5cdbfe58a Mon Sep 17 00:00:00 2001 From: Juhi Date: Wed, 25 Jan 2023 00:13:44 +0530 Subject: [PATCH 18/21] changes --- .../service/AssessmentServiceV2Impl.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java b/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java index 6b4835729..3edd4cbe9 100644 --- a/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java +++ b/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java @@ -199,6 +199,7 @@ private String fetchReadHierarchyDetails(Map assessmentAllDetail if (!ObjectUtils.isEmpty(assessmentData)) { assessmentAllDetail.putAll(mapper.readValue(assessmentData, new TypeReference>() { })); + assessmentAllDetail.put(Constants.EXPECTED_DURATION, 3600); } else { Map readHierarchyApiResponse = assessUtilServ.getReadHierarchyApiResponse(assessmentIdentifier, token); if (!readHierarchyApiResponse.isEmpty()) @@ -207,6 +208,7 @@ private String fetchReadHierarchyDetails(Map assessmentAllDetail } assessmentAllDetail.putAll((Map) ((Map) readHierarchyApiResponse.get(Constants.RESULT)).get(Constants.QUESTION_SET)); redisCacheMgr.putCache(Constants.ASSESSMENT_ID + assessmentIdentifier, ((Map) readHierarchyApiResponse.get(Constants.RESULT)).get(Constants.QUESTION_SET)); + assessmentAllDetail.put(Constants.EXPECTED_DURATION, 3600); } } catch (Exception e) { logger.info("Error while fetching or mapping read hierarchy data" + e.getMessage()); @@ -292,7 +294,8 @@ public SBApiResponse submitAssessment(Map submitRequest, String List> hierarchySectionList = new ArrayList<>(); List questionsListFromAssessmentHierarchy = new ArrayList<>(); Map assessmentHierarchy = new HashMap<>(); - errMsg = validateSubmitAssessmentRequest(submitRequest, authUserToken, hierarchySectionList, sectionListFromSubmitRequest, assessmentHierarchy); + Date assessmentStartTime = new Date(); + errMsg = validateSubmitAssessmentRequest(submitRequest, authUserToken, hierarchySectionList, sectionListFromSubmitRequest, assessmentHierarchy, assessmentStartTime); if (errMsg.isEmpty()) { String userId = validateAuthTokenAndFetchUserId(authUserToken); String scoreCutOffType = ((String) assessmentHierarchy.get(Constants.SCORE_CUTOFF_TYPE)).toLowerCase(); @@ -348,7 +351,7 @@ public SBApiResponse submitAssessment(Map submitRequest, String case Constants.ASSESSMENT_LEVEL_SCORE_CUTOFF: { result.putAll(createResponseMapWithProperStructure(hierarchySection, assessUtilServ.validateQumlAssessment(questionsListFromAssessmentHierarchy, questionsListFromSubmitRequest))); outgoingResponse.getResult().putAll(calculateAssessmentFinalResults(result)); - writeDataToDatabaseAndTriggerKafkaEvent(submitRequest, userId, existingDataList, result, (String) assessmentHierarchy.get(Constants.PRIMARY_CATEGORY)); + writeDataToDatabaseAndTriggerKafkaEvent(submitRequest, userId, assessmentStartTime, result, (String) assessmentHierarchy.get(Constants.PRIMARY_CATEGORY)); return outgoingResponse; } case Constants.SECTION_LEVEL_SCORE_CUTOFF: { @@ -389,7 +392,7 @@ public SBApiResponse submitAssessment(Map submitRequest, String if (errMsg.isEmpty() && !ObjectUtils.isEmpty(scoreCutOffType) && scoreCutOffType.equalsIgnoreCase(Constants.SECTION_LEVEL_SCORE_CUTOFF)) { Map result = calculateSectionFinalResults(sectionLevelsResults); outgoingResponse.getResult().putAll(result); - writeDataToDatabaseAndTriggerKafkaEvent(submitRequest, userId, existingDataList, result, (String) assessmentHierarchy.get(Constants.PRIMARY_CATEGORY)); + writeDataToDatabaseAndTriggerKafkaEvent(submitRequest, userId, assessmentStartTime, result, (String) assessmentHierarchy.get(Constants.PRIMARY_CATEGORY)); return outgoingResponse; } } @@ -401,9 +404,8 @@ public SBApiResponse submitAssessment(Map submitRequest, String return outgoingResponse; } - private void writeDataToDatabaseAndTriggerKafkaEvent(Map submitRequest, String userId, List> existingDataList, Map result, String primaryCategory) { + private void writeDataToDatabaseAndTriggerKafkaEvent(Map submitRequest, String userId, Date startTime, Map result, String primaryCategory) { try { - Date startTime = (!existingDataList.isEmpty()) ? (Date) existingDataList.get(0).get(Constants.START_TIME) : null; Boolean isAssessmentUpdatedToDB = assessmentRepository.updateUserAssesmentDataToDB(userId, (String) submitRequest.get(Constants.IDENTIFIER), submitRequest, result, Constants.SUBMITTED, startTime); if (Boolean.TRUE.equals(isAssessmentUpdatedToDB)) { Map kafkaResult = new HashMap<>(); @@ -434,7 +436,7 @@ private void writeDataToDatabaseAndTriggerKafkaEvent(Map submitR } } - private String validateSubmitAssessmentRequest(Map submitRequest, String authUserToken, List> hierarchySectionList, List> sectionListFromSubmitRequest, Map assessmentHierarchy) throws IOException { + private String validateSubmitAssessmentRequest(Map submitRequest, String authUserToken, List> hierarchySectionList, List> sectionListFromSubmitRequest, Map assessmentHierarchy, Date assessmentStartTime) throws IOException { String userId = validateAuthTokenAndFetchUserId(authUserToken); if (ObjectUtils.isEmpty(userId)) { return Constants.USER_ID_DOESNT_EXIST; @@ -456,7 +458,7 @@ private String validateSubmitAssessmentRequest(Map submitRequest if (((String) (assessmentHierarchy.get(Constants.PRIMARY_CATEGORY))).equalsIgnoreCase(Constants.PRACTICE_QUESTION_SET)) return ""; List> existingDataList = assessmentRepository.fetchUserAssessmentDataFromDB(userId, assessmentIdFromRequest); - Date assessmentStartTime = (!existingDataList.isEmpty()) ? (Date) existingDataList.get(0).get(Constants.START_TIME) : null; + assessmentStartTime = (!existingDataList.isEmpty()) ? (Date) existingDataList.get(0).get(Constants.START_TIME) : null; if (assessmentStartTime == null) { return Constants.READ_ASSESSMENT_START_TIME_FAILED; } From 2d4ad98fea780df7b6662cd25daa044544ea10a8 Mon Sep 17 00:00:00 2001 From: Juhi Date: Wed, 25 Jan 2023 11:41:30 +0530 Subject: [PATCH 19/21] changes --- .../org/sunbird/assessment/service/AssessmentServiceV2Impl.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java b/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java index 3edd4cbe9..e8e73ed1c 100644 --- a/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java +++ b/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java @@ -199,7 +199,6 @@ private String fetchReadHierarchyDetails(Map assessmentAllDetail if (!ObjectUtils.isEmpty(assessmentData)) { assessmentAllDetail.putAll(mapper.readValue(assessmentData, new TypeReference>() { })); - assessmentAllDetail.put(Constants.EXPECTED_DURATION, 3600); } else { Map readHierarchyApiResponse = assessUtilServ.getReadHierarchyApiResponse(assessmentIdentifier, token); if (!readHierarchyApiResponse.isEmpty()) @@ -208,7 +207,6 @@ private String fetchReadHierarchyDetails(Map assessmentAllDetail } assessmentAllDetail.putAll((Map) ((Map) readHierarchyApiResponse.get(Constants.RESULT)).get(Constants.QUESTION_SET)); redisCacheMgr.putCache(Constants.ASSESSMENT_ID + assessmentIdentifier, ((Map) readHierarchyApiResponse.get(Constants.RESULT)).get(Constants.QUESTION_SET)); - assessmentAllDetail.put(Constants.EXPECTED_DURATION, 3600); } } catch (Exception e) { logger.info("Error while fetching or mapping read hierarchy data" + e.getMessage()); From 8d0ea99b2f7d82300a465aa86ecd16f42dd83bdf Mon Sep 17 00:00:00 2001 From: Juhi Date: Wed, 25 Jan 2023 14:48:11 +0530 Subject: [PATCH 20/21] changes --- .../service/AssessmentServiceV2Impl.java | 81 +++++++++++-------- 1 file changed, 47 insertions(+), 34 deletions(-) diff --git a/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java b/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java index e8e73ed1c..e2ffcb92b 100644 --- a/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java +++ b/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java @@ -27,6 +27,7 @@ import org.sunbird.core.producer.Producer; import java.io.IOException; +import java.sql.Time; import java.sql.Timestamp; import java.util.*; import java.util.concurrent.TimeUnit; @@ -76,11 +77,15 @@ public SBApiResponse readAssessment(String assessmentIdentifier, String token) { List> existingDataList = assessmentRepository.fetchUserAssessmentDataFromDB(userId, assessmentIdentifier); Timestamp assessmentStartTime = new Timestamp(new Date().getTime()); if (existingDataList.isEmpty()) { + int expectedDuration = (Integer) assessmentAllDetail.get(Constants.EXPECTED_DURATION); + Timestamp assessmentEndTime = calculateAssessmentSubmitTime(expectedDuration, assessmentStartTime); logger.info("Assessment read first time for user."); - response.getResult().put(Constants.QUESTION_SET, readAssessmentLevelData(assessmentAllDetail)); + Map assessmentData = readAssessmentLevelData(assessmentAllDetail); + assessmentData.put(Constants.START_TIME, new Date(assessmentStartTime.getTime())); + assessmentData.put(Constants.END_TIME, new Date(assessmentEndTime.getTime())); + response.getResult().put(Constants.QUESTION_SET, assessmentData); redisCacheMgr.putCache(Constants.USER_ASSESS_REQ + assessmentIdentifier + "_" + token, response.getResult().get(Constants.QUESTION_SET)); - int expectedDuration = (Integer) assessmentAllDetail.get(Constants.EXPECTED_DURATION); - Boolean isAssessmentUpdatedToDB = assessmentRepository.addUserAssesmentDataToDB(userId, assessmentIdentifier, assessmentStartTime, calculateAssessmentSubmitTime(expectedDuration, assessmentStartTime), (Map) (response.getResult().get(Constants.QUESTION_SET)), Constants.NOT_SUBMITTED); + Boolean isAssessmentUpdatedToDB = assessmentRepository.addUserAssesmentDataToDB(userId, assessmentIdentifier, assessmentStartTime, assessmentEndTime, (Map) (response.getResult().get(Constants.QUESTION_SET)), Constants.NOT_SUBMITTED); if (Boolean.FALSE.equals(isAssessmentUpdatedToDB)) { errMsg = Constants.ASSESSMENT_DATA_START_TIME_NOT_UPDATED; } @@ -97,12 +102,18 @@ public SBApiResponse readAssessment(String assessmentIdentifier, String token) { String questionSetFromAssessmentString = (String) existingDataList.get(0).get(Constants.ASSESSMENT_READ_RESPONSE); questionSetFromAssessment = new Gson().fromJson(questionSetFromAssessmentString, new TypeToken>() { }.getType()); + questionSetFromAssessment.put(Constants.START_TIME, new Date(assessmentStartTime.getTime())); + questionSetFromAssessment.put(Constants.END_TIME, new Date(existingAssessmentEndTime.getTime())); + response.getResult().put(Constants.QUESTION_SET, questionSetFromAssessment); redisCacheMgr.putCache(Constants.USER_ASSESS_REQ + assessmentIdentifier + "_" + token, questionSetFromAssessment); } response.getResult().put(Constants.QUESTION_SET, questionSetFromAssessment); } else if ((assessmentStartTime.compareTo(existingAssessmentEndTime) < 0 && ((String) existingDataList.get(0).get(Constants.STATUS)).equalsIgnoreCase(Constants.SUBMITTED)) || assessmentStartTime.compareTo(existingAssessmentEndTime) > 0) { logger.info("Incase the assessment is submitted before the end time, or the endtime has exceeded, read assessment freshly "); - response.getResult().put(Constants.QUESTION_SET, readAssessmentLevelData(assessmentAllDetail)); + Map assessmentData = readAssessmentLevelData(assessmentAllDetail); + assessmentData.put(Constants.START_TIME, new Date(assessmentStartTime.getTime())); + assessmentData.put(Constants.END_TIME, new Date(existingAssessmentEndTime.getTime())); + response.getResult().put(Constants.QUESTION_SET, assessmentData); int expectedDuration = (Integer) assessmentAllDetail.get(Constants.EXPECTED_DURATION); Boolean isAssessmentUpdatedToDB = assessmentRepository.addUserAssesmentDataToDB(userId, assessmentIdentifier, assessmentStartTime, calculateAssessmentSubmitTime(expectedDuration, assessmentStartTime), (Map) (response.getResult().get(Constants.QUESTION_SET)), Constants.NOT_SUBMITTED); redisCacheMgr.putCache(Constants.USER_ASSESS_REQ + assessmentIdentifier + "_" + token, response.getResult().get(Constants.QUESTION_SET)); @@ -292,13 +303,13 @@ public SBApiResponse submitAssessment(Map submitRequest, String List> hierarchySectionList = new ArrayList<>(); List questionsListFromAssessmentHierarchy = new ArrayList<>(); Map assessmentHierarchy = new HashMap<>(); - Date assessmentStartTime = new Date(); - errMsg = validateSubmitAssessmentRequest(submitRequest, authUserToken, hierarchySectionList, sectionListFromSubmitRequest, assessmentHierarchy, assessmentStartTime); + errMsg = validateSubmitAssessmentRequest(submitRequest, authUserToken, hierarchySectionList, sectionListFromSubmitRequest, assessmentHierarchy); if (errMsg.isEmpty()) { String userId = validateAuthTokenAndFetchUserId(authUserToken); String scoreCutOffType = ((String) assessmentHierarchy.get(Constants.SCORE_CUTOFF_TYPE)).toLowerCase(); List> existingDataList = new ArrayList<>(); List> sectionLevelsResults = new ArrayList<>(); + Map questionSetFromAssessment = new HashMap<>(); for (Map hierarchySection : hierarchySectionList) { String hierarchySectionId = (String) hierarchySection.get(Constants.IDENTIFIER); String userSectionId = ""; @@ -311,8 +322,7 @@ public SBApiResponse submitAssessment(Map submitRequest, String } } if (!((String) (assessmentHierarchy.get(Constants.PRIMARY_CATEGORY))).equalsIgnoreCase(Constants.PRACTICE_QUESTION_SET)) { - Map questionSetFromAssessment = new HashMap<>(); - String assessmentData = redisCacheMgr.getCache(Constants.USER_ASSESS_REQ + (String) submitRequest.get(Constants.IDENTIFIER) + "_" + authUserToken); + String assessmentData = redisCacheMgr.getCache(Constants.USER_ASSESS_REQ + submitRequest.get(Constants.IDENTIFIER) + "_" + authUserToken); if (!ObjectUtils.isEmpty(assessmentData)) { questionSetFromAssessment.putAll(mapper.readValue(assessmentData, new TypeReference>() { })); @@ -349,7 +359,7 @@ public SBApiResponse submitAssessment(Map submitRequest, String case Constants.ASSESSMENT_LEVEL_SCORE_CUTOFF: { result.putAll(createResponseMapWithProperStructure(hierarchySection, assessUtilServ.validateQumlAssessment(questionsListFromAssessmentHierarchy, questionsListFromSubmitRequest))); outgoingResponse.getResult().putAll(calculateAssessmentFinalResults(result)); - writeDataToDatabaseAndTriggerKafkaEvent(submitRequest, userId, assessmentStartTime, result, (String) assessmentHierarchy.get(Constants.PRIMARY_CATEGORY)); + writeDataToDatabaseAndTriggerKafkaEvent(submitRequest, userId, questionSetFromAssessment, result, (String) assessmentHierarchy.get(Constants.PRIMARY_CATEGORY)); return outgoingResponse; } case Constants.SECTION_LEVEL_SCORE_CUTOFF: { @@ -390,7 +400,7 @@ public SBApiResponse submitAssessment(Map submitRequest, String if (errMsg.isEmpty() && !ObjectUtils.isEmpty(scoreCutOffType) && scoreCutOffType.equalsIgnoreCase(Constants.SECTION_LEVEL_SCORE_CUTOFF)) { Map result = calculateSectionFinalResults(sectionLevelsResults); outgoingResponse.getResult().putAll(result); - writeDataToDatabaseAndTriggerKafkaEvent(submitRequest, userId, assessmentStartTime, result, (String) assessmentHierarchy.get(Constants.PRIMARY_CATEGORY)); + writeDataToDatabaseAndTriggerKafkaEvent(submitRequest, userId, questionSetFromAssessment, result, (String) assessmentHierarchy.get(Constants.PRIMARY_CATEGORY)); return outgoingResponse; } } @@ -402,39 +412,42 @@ public SBApiResponse submitAssessment(Map submitRequest, String return outgoingResponse; } - private void writeDataToDatabaseAndTriggerKafkaEvent(Map submitRequest, String userId, Date startTime, Map result, String primaryCategory) { + private void writeDataToDatabaseAndTriggerKafkaEvent(Map submitRequest, String userId, Map questionSetFromAssessment, Map result, String primaryCategory) { try { - Boolean isAssessmentUpdatedToDB = assessmentRepository.updateUserAssesmentDataToDB(userId, (String) submitRequest.get(Constants.IDENTIFIER), submitRequest, result, Constants.SUBMITTED, startTime); - if (Boolean.TRUE.equals(isAssessmentUpdatedToDB)) { - Map kafkaResult = new HashMap<>(); - kafkaResult.put(Constants.CONTENT_ID_KEY, submitRequest.get(Constants.IDENTIFIER)); - kafkaResult.put(Constants.COURSE_ID, submitRequest.get(Constants.COURSE_ID) != null ? submitRequest.get(Constants.COURSE_ID) : ""); - kafkaResult.put(Constants.BATCH_ID, submitRequest.get(Constants.BATCH_ID) != null ? submitRequest.get(Constants.BATCH_ID) : ""); - kafkaResult.put(Constants.USER_ID, submitRequest.get(Constants.USER_ID)); - kafkaResult.put(Constants.ASSESSMENT_ID_KEY, submitRequest.get(Constants.IDENTIFIER)); - kafkaResult.put(Constants.PRIMARY_CATEGORY, primaryCategory); - kafkaResult.put(Constants.TOTAL_SCORE, result.get(Constants.OVERALL_RESULT)); - if ((primaryCategory.equalsIgnoreCase("Competency Assessment") && submitRequest.containsKey("competencies_v3") && submitRequest.get("competencies_v3") != null)) { - Object[] obj = (Object[]) JSON.parse((String) submitRequest.get("competencies_v3")); - if (obj != null) { - Object map = obj[0]; - ObjectMapper m = new ObjectMapper(); - Map props = m.convertValue(map, Map.class); - kafkaResult.put(Constants.COMPETENCY, props.isEmpty() ? "" : props); - System.out.println(obj); + if(questionSetFromAssessment.get(Constants.START_TIME)!=null) { + Date startTime = new Date((Long) questionSetFromAssessment.get(Constants.START_TIME)); + Boolean isAssessmentUpdatedToDB = assessmentRepository.updateUserAssesmentDataToDB(userId, (String) submitRequest.get(Constants.IDENTIFIER), submitRequest, result, Constants.SUBMITTED, startTime); + if (Boolean.TRUE.equals(isAssessmentUpdatedToDB)) { + Map kafkaResult = new HashMap<>(); + kafkaResult.put(Constants.CONTENT_ID_KEY, submitRequest.get(Constants.IDENTIFIER)); + kafkaResult.put(Constants.COURSE_ID, submitRequest.get(Constants.COURSE_ID) != null ? submitRequest.get(Constants.COURSE_ID) : ""); + kafkaResult.put(Constants.BATCH_ID, submitRequest.get(Constants.BATCH_ID) != null ? submitRequest.get(Constants.BATCH_ID) : ""); + kafkaResult.put(Constants.USER_ID, submitRequest.get(Constants.USER_ID)); + kafkaResult.put(Constants.ASSESSMENT_ID_KEY, submitRequest.get(Constants.IDENTIFIER)); + kafkaResult.put(Constants.PRIMARY_CATEGORY, primaryCategory); + kafkaResult.put(Constants.TOTAL_SCORE, result.get(Constants.OVERALL_RESULT)); + if ((primaryCategory.equalsIgnoreCase("Competency Assessment") && submitRequest.containsKey("competencies_v3") && submitRequest.get("competencies_v3") != null)) { + Object[] obj = (Object[]) JSON.parse((String) submitRequest.get("competencies_v3")); + if (obj != null) { + Object map = obj[0]; + ObjectMapper m = new ObjectMapper(); + Map props = m.convertValue(map, Map.class); + kafkaResult.put(Constants.COMPETENCY, props.isEmpty() ? "" : props); + System.out.println(obj); + } + System.out.println(obj); } - System.out.println(obj); + logger.info(kafkaResult.toString()); + kafkaProducer.push(serverProperties.getAssessmentSubmitTopic(), kafkaResult); } - logger.info(kafkaResult.toString()); - kafkaProducer.push(serverProperties.getAssessmentSubmitTopic(), kafkaResult); } } catch (Exception e) { logger.info(e.getMessage()); } } - private String validateSubmitAssessmentRequest(Map submitRequest, String authUserToken, List> hierarchySectionList, List> sectionListFromSubmitRequest, Map assessmentHierarchy, Date assessmentStartTime) throws IOException { + private String validateSubmitAssessmentRequest(Map submitRequest, String authUserToken, List> hierarchySectionList, List> sectionListFromSubmitRequest, Map assessmentHierarchy) throws IOException { String userId = validateAuthTokenAndFetchUserId(authUserToken); if (ObjectUtils.isEmpty(userId)) { return Constants.USER_ID_DOESNT_EXIST; @@ -456,7 +469,7 @@ private String validateSubmitAssessmentRequest(Map submitRequest if (((String) (assessmentHierarchy.get(Constants.PRIMARY_CATEGORY))).equalsIgnoreCase(Constants.PRACTICE_QUESTION_SET)) return ""; List> existingDataList = assessmentRepository.fetchUserAssessmentDataFromDB(userId, assessmentIdFromRequest); - assessmentStartTime = (!existingDataList.isEmpty()) ? (Date) existingDataList.get(0).get(Constants.START_TIME) : null; + Date assessmentStartTime = (!existingDataList.isEmpty()) ? (Date) existingDataList.get(0).get(Constants.START_TIME) : null; if (assessmentStartTime == null) { return Constants.READ_ASSESSMENT_START_TIME_FAILED; } From a6998165454cb0177ee4fce426eec66487971d94 Mon Sep 17 00:00:00 2001 From: Juhi Date: Fri, 27 Jan 2023 15:06:57 +0530 Subject: [PATCH 21/21] changes~ --- .../service/AssessmentServiceV2Impl.java | 88 +++++++++++-------- .../org/sunbird/common/util/Constants.java | 2 + 2 files changed, 52 insertions(+), 38 deletions(-) diff --git a/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java b/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java index e2ffcb92b..82156f5c9 100644 --- a/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java +++ b/src/main/java/org/sunbird/assessment/service/AssessmentServiceV2Impl.java @@ -26,11 +26,9 @@ import org.sunbird.common.util.RequestInterceptor; import org.sunbird.core.producer.Producer; +import java.util.*; import java.io.IOException; -import java.sql.Time; import java.sql.Timestamp; -import java.util.*; -import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import static java.util.stream.Collectors.toList; @@ -75,14 +73,14 @@ public SBApiResponse readAssessment(String assessmentIdentifier, String token) { if (errMsg.isEmpty() && !((String) assessmentAllDetail.get(Constants.PRIMARY_CATEGORY)).equalsIgnoreCase(Constants.PRACTICE_QUESTION_SET)) { logger.info("Fetched assessment Details... for : " + assessmentIdentifier); List> existingDataList = assessmentRepository.fetchUserAssessmentDataFromDB(userId, assessmentIdentifier); - Timestamp assessmentStartTime = new Timestamp(new Date().getTime()); + Timestamp assessmentStartTime = new Timestamp(new java.util.Date().getTime()); if (existingDataList.isEmpty()) { int expectedDuration = (Integer) assessmentAllDetail.get(Constants.EXPECTED_DURATION); Timestamp assessmentEndTime = calculateAssessmentSubmitTime(expectedDuration, assessmentStartTime); logger.info("Assessment read first time for user."); Map assessmentData = readAssessmentLevelData(assessmentAllDetail); - assessmentData.put(Constants.START_TIME, new Date(assessmentStartTime.getTime())); - assessmentData.put(Constants.END_TIME, new Date(assessmentEndTime.getTime())); + assessmentData.put(Constants.START_TIME, assessmentStartTime.getTime()); + assessmentData.put(Constants.END_TIME, assessmentEndTime.getTime()); response.getResult().put(Constants.QUESTION_SET, assessmentData); redisCacheMgr.putCache(Constants.USER_ASSESS_REQ + assessmentIdentifier + "_" + token, response.getResult().get(Constants.QUESTION_SET)); Boolean isAssessmentUpdatedToDB = assessmentRepository.addUserAssesmentDataToDB(userId, assessmentIdentifier, assessmentStartTime, assessmentEndTime, (Map) (response.getResult().get(Constants.QUESTION_SET)), Constants.NOT_SUBMITTED); @@ -91,8 +89,9 @@ public SBApiResponse readAssessment(String assessmentIdentifier, String token) { } } else { logger.info("Assessment read... user has details... "); - Date existingAssessmentEndTime = (Date) (existingDataList.get(0).get(Constants.END_TIME)); - if (assessmentStartTime.compareTo(existingAssessmentEndTime) < 0 && ((String) existingDataList.get(0).get(Constants.STATUS)).equalsIgnoreCase(Constants.NOT_SUBMITTED)) { + java.util.Date existingAssessmentEndTime = (java.util.Date) (existingDataList.get(0).get(Constants.END_TIME)); + Timestamp existingAssessmentEndTimeTimestamp = new Timestamp(existingAssessmentEndTime.getTime()); + if (assessmentStartTime.compareTo(existingAssessmentEndTimeTimestamp) < 0 && ((String) existingDataList.get(0).get(Constants.STATUS)).equalsIgnoreCase(Constants.NOT_SUBMITTED)) { Map questionSetFromAssessment; String userQuestionSet = redisCacheMgr.getCache(Constants.USER_ASSESS_REQ + assessmentIdentifier + "_" + token); if (!ObjectUtils.isEmpty(userQuestionSet)) { @@ -102,8 +101,8 @@ public SBApiResponse readAssessment(String assessmentIdentifier, String token) { String questionSetFromAssessmentString = (String) existingDataList.get(0).get(Constants.ASSESSMENT_READ_RESPONSE); questionSetFromAssessment = new Gson().fromJson(questionSetFromAssessmentString, new TypeToken>() { }.getType()); - questionSetFromAssessment.put(Constants.START_TIME, new Date(assessmentStartTime.getTime())); - questionSetFromAssessment.put(Constants.END_TIME, new Date(existingAssessmentEndTime.getTime())); + questionSetFromAssessment.put(Constants.START_TIME, assessmentStartTime.getTime()); + questionSetFromAssessment.put(Constants.END_TIME, existingAssessmentEndTimeTimestamp.getTime()); response.getResult().put(Constants.QUESTION_SET, questionSetFromAssessment); redisCacheMgr.putCache(Constants.USER_ASSESS_REQ + assessmentIdentifier + "_" + token, questionSetFromAssessment); } @@ -111,10 +110,12 @@ public SBApiResponse readAssessment(String assessmentIdentifier, String token) { } else if ((assessmentStartTime.compareTo(existingAssessmentEndTime) < 0 && ((String) existingDataList.get(0).get(Constants.STATUS)).equalsIgnoreCase(Constants.SUBMITTED)) || assessmentStartTime.compareTo(existingAssessmentEndTime) > 0) { logger.info("Incase the assessment is submitted before the end time, or the endtime has exceeded, read assessment freshly "); Map assessmentData = readAssessmentLevelData(assessmentAllDetail); - assessmentData.put(Constants.START_TIME, new Date(assessmentStartTime.getTime())); - assessmentData.put(Constants.END_TIME, new Date(existingAssessmentEndTime.getTime())); - response.getResult().put(Constants.QUESTION_SET, assessmentData); int expectedDuration = (Integer) assessmentAllDetail.get(Constants.EXPECTED_DURATION); + assessmentStartTime = new Timestamp(new java.util.Date().getTime()); + Timestamp assessmentEndTime = calculateAssessmentSubmitTime(expectedDuration, assessmentStartTime); + assessmentData.put(Constants.START_TIME, assessmentStartTime.getTime()); + assessmentData.put(Constants.END_TIME, assessmentEndTime.getTime()); + response.getResult().put(Constants.QUESTION_SET, assessmentData); Boolean isAssessmentUpdatedToDB = assessmentRepository.addUserAssesmentDataToDB(userId, assessmentIdentifier, assessmentStartTime, calculateAssessmentSubmitTime(expectedDuration, assessmentStartTime), (Map) (response.getResult().get(Constants.QUESTION_SET)), Constants.NOT_SUBMITTED); redisCacheMgr.putCache(Constants.USER_ASSESS_REQ + assessmentIdentifier + "_" + token, response.getResult().get(Constants.QUESTION_SET)); if (Boolean.FALSE.equals(isAssessmentUpdatedToDB)) { @@ -213,9 +214,9 @@ private String fetchReadHierarchyDetails(Map assessmentAllDetail } else { Map readHierarchyApiResponse = assessUtilServ.getReadHierarchyApiResponse(assessmentIdentifier, token); if (!readHierarchyApiResponse.isEmpty()) - if (ObjectUtils.isEmpty(readHierarchyApiResponse) || !Constants.OK.equalsIgnoreCase((String) readHierarchyApiResponse.get(Constants.RESPONSE_CODE))) { - return Constants.ASSESSMENT_HIERARCHY_READ_FAILED; - } + if (ObjectUtils.isEmpty(readHierarchyApiResponse) || !Constants.OK.equalsIgnoreCase((String) readHierarchyApiResponse.get(Constants.RESPONSE_CODE))) { + return Constants.ASSESSMENT_HIERARCHY_READ_FAILED; + } assessmentAllDetail.putAll((Map) ((Map) readHierarchyApiResponse.get(Constants.RESULT)).get(Constants.QUESTION_SET)); redisCacheMgr.putCache(Constants.ASSESSMENT_ID + assessmentIdentifier, ((Map) readHierarchyApiResponse.get(Constants.RESULT)).get(Constants.QUESTION_SET)); } @@ -414,8 +415,9 @@ public SBApiResponse submitAssessment(Map submitRequest, String private void writeDataToDatabaseAndTriggerKafkaEvent(Map submitRequest, String userId, Map questionSetFromAssessment, Map result, String primaryCategory) { try { - if(questionSetFromAssessment.get(Constants.START_TIME)!=null) { - Date startTime = new Date((Long) questionSetFromAssessment.get(Constants.START_TIME)); + if (questionSetFromAssessment.get(Constants.START_TIME) != null) { + Long existingAssessmentStartTime = (Long) questionSetFromAssessment.get(Constants.START_TIME); + Timestamp startTime = new Timestamp(existingAssessmentStartTime); Boolean isAssessmentUpdatedToDB = assessmentRepository.updateUserAssesmentDataToDB(userId, (String) submitRequest.get(Constants.IDENTIFIER), submitRequest, result, Constants.SUBMITTED, startTime); if (Boolean.TRUE.equals(isAssessmentUpdatedToDB)) { Map kafkaResult = new HashMap<>(); @@ -469,26 +471,36 @@ private String validateSubmitAssessmentRequest(Map submitRequest if (((String) (assessmentHierarchy.get(Constants.PRIMARY_CATEGORY))).equalsIgnoreCase(Constants.PRACTICE_QUESTION_SET)) return ""; List> existingDataList = assessmentRepository.fetchUserAssessmentDataFromDB(userId, assessmentIdFromRequest); - Date assessmentStartTime = (!existingDataList.isEmpty()) ? (Date) existingDataList.get(0).get(Constants.START_TIME) : null; - if (assessmentStartTime == null) { - return Constants.READ_ASSESSMENT_START_TIME_FAILED; - } - int expectedDuration = (Integer) assessmentHierarchy.get(Constants.EXPECTED_DURATION); - Timestamp later = calculateAssessmentSubmitTime(expectedDuration, assessmentStartTime); - Timestamp submissionTime = new Timestamp(new Date().getTime()); - int time = submissionTime.compareTo(later); - if (time <= 0) { - List desiredKeys = Lists.newArrayList(Constants.IDENTIFIER); - List hierarchySectionIds = hierarchySectionList.stream().flatMap(x -> desiredKeys.stream().filter(x::containsKey).map(x::get)).collect(toList()); - List submitSectionIds = sectionListFromSubmitRequest.stream().flatMap(x -> desiredKeys.stream().filter(x::containsKey).map(x::get)).collect(toList()); - if (!new HashSet<>(hierarchySectionIds).containsAll(submitSectionIds)) { - return Constants.WRONG_SECTION_DETAILS; + if (!existingDataList.isEmpty()) { + if (!((String) existingDataList.get(0).get(Constants.STATUS)).equalsIgnoreCase(Constants.SUBMITTED)) { + Date assessmentStartTime = (!existingDataList.isEmpty()) ? (Date) existingDataList.get(0).get(Constants.START_TIME) : null; + if (assessmentStartTime == null) { + return Constants.READ_ASSESSMENT_START_TIME_FAILED; + } + int expectedDuration = (Integer) assessmentHierarchy.get(Constants.EXPECTED_DURATION); + Timestamp later = calculateAssessmentSubmitTime(expectedDuration, new Timestamp(assessmentStartTime.getTime())); + Timestamp submissionTime = new Timestamp(new Date().getTime()); + int time = submissionTime.compareTo(later); + if (time <= 0) { + List desiredKeys = Lists.newArrayList(Constants.IDENTIFIER); + List hierarchySectionIds = hierarchySectionList.stream().flatMap(x -> desiredKeys.stream().filter(x::containsKey).map(x::get)).collect(toList()); + List submitSectionIds = sectionListFromSubmitRequest.stream().flatMap(x -> desiredKeys.stream().filter(x::containsKey).map(x::get)).collect(toList()); + if (!new HashSet<>(hierarchySectionIds).containsAll(submitSectionIds)) { + return Constants.WRONG_SECTION_DETAILS; + } else { + String areQuestionIdsSame = validateIfQuestionIdsAreSame(submitRequest, sectionListFromSubmitRequest, desiredKeys, userId); + if (!areQuestionIdsSame.isEmpty()) return areQuestionIdsSame; + } + } + else { + return Constants.ASSESSMENT_SUBMIT_EXPIRED; + } } else { - String areQuestionIdsSame = validateIfQuestionIdsAreSame(submitRequest, sectionListFromSubmitRequest, desiredKeys, userId); - if (!areQuestionIdsSame.isEmpty()) return areQuestionIdsSame; + return Constants.ASSESSMENT_ALREADY_SUBMITTED; } - } else { - return Constants.ASSESSMENT_SUBMIT_EXPIRED; + } + else { + return Constants.USER_ASSESSMENT_DATA_NOT_PRESENT; } return ""; } @@ -524,9 +536,9 @@ private String validateIfQuestionIdsAreSame(Map submitRequest, L return ""; } - private Timestamp calculateAssessmentSubmitTime(int expectedDuration, Date assessmentStartTime) { + private Timestamp calculateAssessmentSubmitTime(int expectedDuration, Timestamp assessmentStartTime) { Calendar cal = Calendar.getInstance(); - cal.setTimeInMillis(new Timestamp(assessmentStartTime.getTime()).getTime()); + cal.setTimeInMillis(assessmentStartTime.getTime()); if (serverProperties.getUserAssessmentSubmissionDuration().isEmpty()) { serverProperties.setUserAssessmentSubmissionDuration("120"); } diff --git a/src/main/java/org/sunbird/common/util/Constants.java b/src/main/java/org/sunbird/common/util/Constants.java index 81b5608dd..6f010d396 100644 --- a/src/main/java/org/sunbird/common/util/Constants.java +++ b/src/main/java/org/sunbird/common/util/Constants.java @@ -577,6 +577,8 @@ public class Constants { public static final String READ_ASSESSMENT_START_TIME_FAILED = "Failed to read the assessment start time."; public static final String WRONG_SECTION_DETAILS = "Wrong section details."; public static final String ASSESSMENT_SUBMIT_EXPIRED = "The Assessment submission time-period is over! Assessment can't be submitted"; + public static final String ASSESSMENT_ALREADY_SUBMITTED = "This Assessment is already Submitted!"; + public static final String ASSESSMENT_SUBMIT_INVALID_QUESTION = "The QuestionId provided don't match to the Assessment Read"; public static final String ASSESSMENT_SUBMIT_QUESTION_READ_FAILED = "Failed to read Question Set from DB";