Skip to content

Commit

Permalink
4.8.0 lookup enhancements (#36)
Browse files Browse the repository at this point in the history
* sunbird-course-getPatrcipantList changes

* Batch listing updates (#35)

* Changes for particpant list - includes crud

* Fixes in user enrollment and lookup table

* Modifications for CassandraOperations files

* Removed unnecessary changes

* Removed unnecessary changes

---------

Co-authored-by: wilky singh <wilky.singh@tarento.com>

* Updated code as per new version

* Added limit for participants list

* Removed unnecessary info statement

---------

Co-authored-by: sreeragksgh <sreeragsajeesh@gmail.com>
Co-authored-by: somvitbhowmik <38094153+somvitbhowmik@users.noreply.github.com>
Co-authored-by: wilky singh <wilky.singh@tarento.com>
  • Loading branch information
4 people authored Apr 22, 2023
1 parent 7c53658 commit 84d4a47
Show file tree
Hide file tree
Showing 10 changed files with 241 additions and 18 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.sunbird.learner.actors.coursebatch.dao;
import java.security.Timestamp;
import java.util.List;
import java.util.Map;
import org.sunbird.common.models.response.Response;
import org.sunbird.common.request.Request;
import org.sunbird.common.request.RequestContext;
import org.sunbird.models.batch.user.BatchUser;
import org.sunbird.models.course.batch.CourseBatch;
import org.sunbird.models.user.courses.UserCourses;

public interface BatchUserDao {
/**
* Get user courses information.
*
* @param batchId,userId user courses identifiers
* @param requestContext
* @return User batch information
*/

BatchUser readById(RequestContext requestContext, String batchId);
BatchUser read(RequestContext requestContext, String batchId, String userId);
Response insertBatchLookupRecord(RequestContext requestContext, Map<String, Object> userCoursesDetails);

Response updateBatchLookupRecord(RequestContext requestContext, String courseId, String batchId, Map<String, Object> updateAttributes,Map<String, Object> activeStatus);


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package org.sunbird.learner.actors.coursebatch.dao.impl;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.collections.CollectionUtils;
import org.sunbird.cassandra.CassandraOperation;
import org.sunbird.common.CassandraUtil;
import org.sunbird.common.models.response.Response;
import org.sunbird.common.models.util.JsonKey;
import org.sunbird.common.request.RequestContext;
import org.sunbird.helper.ServiceFactory;
import org.sunbird.learner.actors.coursebatch.dao.BatchUserDao;
import org.sunbird.learner.util.Util;
import org.sunbird.models.batch.user.BatchUser;
import org.sunbird.common.models.util.LoggerUtil;


import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class BatchUserDaoImpl implements BatchUserDao{
protected LoggerUtil logger = new LoggerUtil(this.getClass());
private CassandraOperation cassandraOperation = ServiceFactory.getInstance();
private ObjectMapper mapper = new ObjectMapper();
static BatchUserDao batchUserDao;
private static final String KEYSPACE_NAME =
Util.dbInfoMap.get(JsonKey.ENROLLMENT_BATCH_DB).getKeySpace();

private static final String ENROLLMENT_BATCH =
Util.dbInfoMap.get(JsonKey.ENROLLMENT_BATCH_DB).getTableName();
public static BatchUserDao getInstance() {
if (batchUserDao == null) {
batchUserDao = new BatchUserDaoImpl();
}
return batchUserDao;
}

@Override
public BatchUser readById(RequestContext requestContext, String batchId) {
Map<String, Object> primaryKey = new HashMap<>();
primaryKey.put(JsonKey.BATCH_ID, batchId);
Response response = cassandraOperation.getRecordByIdentifier(requestContext, KEYSPACE_NAME, ENROLLMENT_BATCH, primaryKey, null);
try {
List<Map<String, Object>> batchUserList =
(List<Map<String, Object>>) response.get(JsonKey.RESPONSE);
if (CollectionUtils.isEmpty(batchUserList)) {
return null;
}
return mapper.convertValue((Map<String, Object>) batchUserList.get(0), BatchUser.class);
} catch (Exception e) {
logger.error(requestContext, "Failed to read BatchUser Table. Exception: ", e);
return null;
}
}

@Override
public BatchUser read(RequestContext requestContext, String batchId, String userId) {
Map<String, Object> primaryKey = new HashMap<>();
primaryKey.put(JsonKey.BATCH_ID, batchId);
primaryKey.put(JsonKey.USER_ID, userId);
Response response = cassandraOperation.getRecordByIdentifier(requestContext, KEYSPACE_NAME, ENROLLMENT_BATCH, primaryKey, null);
try {
List<Map<String, Object>> batchUserList =
(List<Map<String, Object>>) response.get(JsonKey.RESPONSE);
if (CollectionUtils.isEmpty(batchUserList)) {
return null;
}
return mapper.readValue(mapper.writeValueAsString(batchUserList.get(0)), new TypeReference<BatchUser>() {});
} catch (Exception e) {
logger.error(requestContext, "Failed to read BatchUser Table. Exception: ", e);
return null;
}
}
@Override
public Response insertBatchLookupRecord(RequestContext requestContext, Map<String, Object> userCoursesDetails) {
return cassandraOperation.insertRecord(requestContext, KEYSPACE_NAME, ENROLLMENT_BATCH, userCoursesDetails);
}


@Override
public Response updateBatchLookupRecord(RequestContext requestContext, String batchId, String userId, Map<String, Object> map,Map<String, Object> activeStatus) {
Map<String, Object> primaryKey = new HashMap<>();
primaryKey.put(JsonKey.BATCH_ID, batchId);
primaryKey.put(JsonKey.USER_ID, userId);
primaryKey.put(JsonKey.ENROLLED_DATE, map.get("enrolled_date"));
Map<String, Object> attributeMap = new HashMap<>();
attributeMap.putAll(activeStatus);
attributeMap.remove(JsonKey.BATCH_ID);
attributeMap = CassandraUtil.changeCassandraColumnMapping(attributeMap);
return cassandraOperation.updateRecord(
requestContext, KEYSPACE_NAME, ENROLLMENT_BATCH, attributeMap, primaryKey);
}
}




Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.util.stream.Collectors;
import org.apache.commons.collections.CollectionUtils;
import org.sunbird.cassandra.CassandraOperation;
import org.sunbird.common.Constants;
import org.sunbird.common.models.response.Response;
import org.sunbird.common.models.util.JsonKey;
import org.sunbird.common.request.RequestContext;
Expand All @@ -23,6 +24,7 @@ public class UserCoursesDaoImpl implements UserCoursesDao {
private static final String TABLE_NAME =
Util.dbInfoMap.get(JsonKey.LEARNER_COURSE_DB).getTableName();
private static final String USER_ENROLMENTS = Util.dbInfoMap.get(JsonKey.USER_ENROLMENTS_DB).getTableName();
private static final String ENROLMENT_BATCH_LOOKUP = Util.dbInfoMap.get(JsonKey.ENROLLMENT_BATCH_DB).getTableName();
public static UserCoursesDao getInstance() {
if (userCoursesDao == null) {
userCoursesDao = new UserCoursesDaoImpl();
Expand Down Expand Up @@ -119,19 +121,22 @@ public List<String> getBatchParticipants(RequestContext requestContext, String b
Map<String, Object> queryMap = new HashMap<>();
queryMap.put(JsonKey.BATCH_ID, batchId);
Response response =
cassandraOperation.getRecordsByIndexedProperty(KEYSPACE_NAME, USER_ENROLMENTS, "batchid", batchId, requestContext);
cassandraOperation.getRecordByIdentifier(requestContext,KEYSPACE_NAME, ENROLMENT_BATCH_LOOKUP, queryMap, null, Constants.DEFAULT_LIMIT);
/*cassandraOperation.getRecords(
requestContext, KEYSPACE_NAME, USER_ENROLMENTS, queryMap, Arrays.asList(JsonKey.USER_ID, JsonKey.ACTIVE));*/
List<Map<String, Object>> userCoursesList =
(List<Map<String, Object>>) response.get(JsonKey.RESPONSE);
if (CollectionUtils.isEmpty(userCoursesList)) {
return null;
}
return userCoursesList
.stream()
.filter(userCourse -> (active == (boolean) userCourse.get(JsonKey.ACTIVE)))
.map(userCourse -> (String) userCourse.get(JsonKey.USER_ID))
.collect(Collectors.toList());
List<String> userList = new ArrayList<String>();
for(Map<String, Object> userCourse : userCoursesList) {
if(userCourse.get(JsonKey.ACTIVE) != null
&& (active == (boolean) userCourse.get(JsonKey.ACTIVE))) {
userList.add((String) userCourse.get(JsonKey.USER_ID));
}
}
return userList;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ private static void initializeDBProperty() {
dbInfoMap.put(
JsonKey.ASSESSMENT_AGGREGATOR_DB, getDbInfoObject(COURSE_KEY_SPACE_NAME, "assessment_aggregator"));
dbInfoMap.put(JsonKey.USER_ENROLMENTS_DB, getDbInfoObject(COURSE_KEY_SPACE_NAME, "user_enrolments"));
dbInfoMap.put(JsonKey.ENROLLMENT_BATCH_DB, getDbInfoObject(COURSE_KEY_SPACE_NAME, "enrollment_batch_lookup"));
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package org.sunbird.models.batch.user;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;

import java.io.Serializable;
import java.sql.Timestamp;

@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class BatchUser implements Serializable {

private static final long serialVersionUID = 1L;
private String batchId;

private String userId;

private Boolean active;

private Timestamp enrolledDate;

public String getBatchId() {
return batchId;
}

public void setBatchId(String batchId) {
this.batchId = batchId;
}

public String getUserId() {
return userId;
}

public void setUserId(String userId) {
this.userId = userId;
}

public Boolean getActive() {
return active;
}

public void setActive(Boolean active) {
this.active = active;
}

public Timestamp getEnrolledDate() {
return enrolledDate;
}

public void setEnrolledDate(Timestamp enrolledDate) {
this.enrolledDate = enrolledDate;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,16 @@ import org.sunbird.common.models.util.ProjectUtil.EnrolmentType
import org.sunbird.common.models.util._
import org.sunbird.common.request.{Request, RequestContext}
import org.sunbird.common.responsecode.ResponseCode
import org.sunbird.learner.actors.coursebatch.dao.impl.{CourseBatchDaoImpl, UserCoursesDaoImpl}
import org.sunbird.learner.actors.coursebatch.dao.{CourseBatchDao, UserCoursesDao}
import org.sunbird.learner.actors.coursebatch.dao.impl.{BatchUserDaoImpl, CourseBatchDaoImpl, UserCoursesDaoImpl}
import org.sunbird.learner.actors.coursebatch.dao.{BatchUserDao, CourseBatchDao, UserCoursesDao}
import org.sunbird.learner.actors.group.dao.impl.GroupDaoImpl
import org.sunbird.learner.util.{ContentSearchUtil, ContentUtil, CourseBatchSchedulerUtil, JsonUtil, Util}
import org.sunbird.models.course.batch.CourseBatch
import org.sunbird.models.user.courses.UserCourses
import org.sunbird.cache.util.RedisCacheUtil
import org.sunbird.common.CassandraUtil
import org.sunbird.common.models.util.ProjectUtil;
import org.sunbird.common.models.util.ProjectUtil
import org.sunbird.models.batch.user.BatchUser
import org.sunbird.telemetry.util.TelemetryUtil

import scala.collection.JavaConversions._
Expand All @@ -41,14 +42,14 @@ class CourseEnrolmentActor @Inject()(@Named("course-batch-notification-actor") c
*/
var courseBatchDao: CourseBatchDao = new CourseBatchDaoImpl()
var userCoursesDao: UserCoursesDao = new UserCoursesDaoImpl()
var batchUserDao : BatchUserDao = new BatchUserDaoImpl()
var groupDao: GroupDaoImpl = new GroupDaoImpl()
val isCacheEnabled = if (StringUtils.isNotBlank(ProjectUtil.getConfigValue("user_enrolments_response_cache_enable")))
(ProjectUtil.getConfigValue("user_enrolments_response_cache_enable")).toBoolean else true
val ttl: Int = if (StringUtils.isNotBlank(ProjectUtil.getConfigValue("user_enrolments_response_cache_ttl")))
(ProjectUtil.getConfigValue("user_enrolments_response_cache_ttl")).toInt else 60
private val DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd")


override def preStart { println("Starting CourseEnrolmentActor") }

override def postStop {
Expand Down Expand Up @@ -80,27 +81,30 @@ class CourseEnrolmentActor @Inject()(@Named("course-batch-notification-actor") c
val batchId: String = request.get(JsonKey.BATCH_ID).asInstanceOf[String]
val batchData: CourseBatch = courseBatchDao.readById( courseId, batchId, request.getRequestContext)
val enrolmentData: UserCourses = userCoursesDao.read(request.getRequestContext, userId, courseId, batchId)
val batchUserData: BatchUser = batchUserDao.read(request.getRequestContext, batchId, userId)
validateEnrolment(batchData, enrolmentData, true)
val dataBatch: util.Map[String, AnyRef] = createBatchUserMapping(batchId, userId,batchUserData)
val data: java.util.Map[String, AnyRef] = createUserEnrolmentMap(userId, courseId, batchId, enrolmentData, request.getContext.getOrDefault(JsonKey.REQUEST_ID, "").asInstanceOf[String])
upsertEnrollment(userId, courseId, batchId, data, (null == enrolmentData), request.getRequestContext)
upsertEnrollment(userId, courseId, batchId, data, dataBatch, (null == enrolmentData), request.getRequestContext)
logger.info(request.getRequestContext, "CourseEnrolmentActor :: enroll :: Deleting redis for key " + getCacheKey(userId))
cacheUtil.delete(getCacheKey(userId))
sender().tell(successResponse(), self)
generateTelemetryAudit(userId, courseId, batchId, data, "enrol", JsonKey.CREATE, request.getContext)
notifyUser(userId, batchData, JsonKey.ADD)
}


def unEnroll(request:Request): Unit = {
val courseId: String = request.get(JsonKey.COURSE_ID).asInstanceOf[String]
val userId: String = request.get(JsonKey.USER_ID).asInstanceOf[String]
val batchId: String = request.get(JsonKey.BATCH_ID).asInstanceOf[String]
val batchData: CourseBatch = courseBatchDao.readById(courseId, batchId, request.getRequestContext)
val enrolmentData: UserCourses = userCoursesDao.read(request.getRequestContext, userId, courseId, batchId)
val batchUserData: BatchUser = batchUserDao.read(request.getRequestContext, batchId, userId)
val dataBatch: util.Map[String, AnyRef] = createBatchUserMapping(batchId, userId,batchUserData)
getUpdatedStatus(enrolmentData)
validateEnrolment(batchData, enrolmentData, false)
val data: java.util.Map[String, AnyRef] = new java.util.HashMap[String, AnyRef]() {{ put(JsonKey.ACTIVE, ProjectUtil.ActiveStatus.INACTIVE.getValue.asInstanceOf[AnyRef]) }}
upsertEnrollment(userId,courseId, batchId, data, false, request.getRequestContext)
upsertEnrollment(userId,courseId, batchId, data,dataBatch, false, request.getRequestContext)
logger.info(request.getRequestContext, "CourseEnrolmentActor :: unEnroll :: Deleting redis for key " + getCacheKey(userId))
cacheUtil.delete(getCacheKey(userId))
sender().tell(successResponse(), self)
Expand Down Expand Up @@ -212,17 +216,19 @@ class CourseEnrolmentActor @Inject()(@Named("course-batch-notification-actor") c

if((2 == batchData.getStatus) || (null != batchData.getEndDate && LocalDateTime.now().isAfter(LocalDate.parse(DATE_FORMAT.format(batchData.getEndDate), DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MAX))))
ProjectCommonException.throwClientErrorException(ResponseCode.courseBatchAlreadyCompleted, ResponseCode.courseBatchAlreadyCompleted.getErrorMessage)

if(isEnrol && null != batchData.getEnrollmentEndDate && LocalDateTime.now().isAfter(LocalDate.parse(DATE_FORMAT.format(batchData.getEnrollmentEndDate), DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MAX)))
ProjectCommonException.throwClientErrorException(ResponseCode.courseBatchEnrollmentDateEnded, ResponseCode.courseBatchEnrollmentDateEnded.getErrorMessage)

if(isEnrol && null != enrolmentData && enrolmentData.isActive) ProjectCommonException.throwClientErrorException(ResponseCode.userAlreadyEnrolledCourse, ResponseCode.userAlreadyEnrolledCourse.getErrorMessage)
if(!isEnrol && (null == enrolmentData || !enrolmentData.isActive)) ProjectCommonException.throwClientErrorException(ResponseCode.userNotEnrolledCourse, ResponseCode.userNotEnrolledCourse.getErrorMessage)
if(!isEnrol && ProjectUtil.ProgressStatus.COMPLETED.getValue == enrolmentData.getStatus) ProjectCommonException.throwClientErrorException(ResponseCode.courseBatchAlreadyCompleted, ResponseCode.courseBatchAlreadyCompleted.getErrorMessage)
}

def upsertEnrollment(userId: String, courseId: String, batchId: String, data: java.util.Map[String, AnyRef], isNew: Boolean, requestContext: RequestContext): Unit = {
def upsertEnrollment(userId: String, courseId: String, batchId: String, data: java.util.Map[String, AnyRef], dataBatch:java.util.Map[String, AnyRef] ,isNew: Boolean, requestContext: RequestContext): Unit = {
val dataMap = CassandraUtil.changeCassandraColumnMapping(data)
val dataBatchMap = CassandraUtil.changeCassandraColumnMapping(dataBatch)

// code for find root cause of null value in prod(16-02-2023)
try {
val activeStatus = dataMap.get(JsonKey.ACTIVE);
Expand All @@ -238,8 +244,10 @@ class CourseEnrolmentActor @Inject()(@Named("course-batch-notification-actor") c
// END
if(isNew) {
userCoursesDao.insertV2(requestContext, dataMap)
batchUserDao.insertBatchLookupRecord(requestContext,dataBatchMap)
} else {
userCoursesDao.updateV2(requestContext, userId, courseId, batchId, dataMap)
batchUserDao.updateBatchLookupRecord(requestContext, batchId, userId, dataBatchMap, dataMap)
}
}

Expand All @@ -258,6 +266,18 @@ class CourseEnrolmentActor @Inject()(@Named("course-batch-notification-actor") c
}
}}

def createBatchUserMapping(batchId: String, userId: String,batchUserData :BatchUser): java.util.Map[String, AnyRef] =
new java.util.HashMap[String, AnyRef]() {
put(JsonKey.BATCH_ID, batchId)
put(JsonKey.USER_ID, userId)
put(JsonKey.ACTIVE, ProjectUtil.ActiveStatus.ACTIVE.getValue.asInstanceOf[AnyRef])
if(batchUserData == null) {
put(JsonKey.COURSE_ENROLL_DATE, ProjectUtil.getTimeStamp)
} else {
put(JsonKey.COURSE_ENROLL_DATE, batchUserData.getEnrolledDate)
}
}

def notifyUser(userId: String, batchData: CourseBatch, operationType: String): Unit = {
val isNotifyUser = java.lang.Boolean.parseBoolean(PropertiesCache.getInstance().getProperty(JsonKey.SUNBIRD_COURSE_BATCH_NOTIFICATIONS_ENABLED))
if(isNotifyUser){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -290,4 +290,5 @@ public Response getRecordsWithLimit(
*/
Response batchInsertLogged(RequestContext requestContext, String keyspaceName, String tableName, List<Map<String, Object>> records);

Response getRecordByIdentifier(RequestContext requestContext, String keyspaceName, String tableName, Object key, List<String> fields, int limit);
}
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,12 @@ public Response updateRecord(
@Override
public Response getRecordByIdentifier(
RequestContext requestContext, String keyspaceName, String tableName, Object key, List<String> fields) {
return getRecordByIdentifier(requestContext, keyspaceName, tableName, key, fields, -1);
}

@Override
public Response getRecordByIdentifier(
RequestContext requestContext, String keyspaceName, String tableName, Object key, List<String> fields, int limit) {
long startTime = System.currentTimeMillis();
logger.debug(requestContext, "Cassandra Service getRecordBy key method started at ==" + startTime);
Response response = new Response();
Expand All @@ -453,8 +459,11 @@ public Response getRecordByIdentifier(
CassandraUtil.createQuery(x.getKey(), x.getValue(), selectWhere);
});
}
logger.debug(requestContext, selectWhere.getQueryString());
ResultSet results = session.execute(selectWhere);
if (limit != -1) {
selectQuery.limit(limit);
}
logger.debug(requestContext, selectQuery.getQueryString());
ResultSet results = session.execute(selectQuery);
response = CassandraUtil.createResponse(results);
} catch (Exception e) {
logger.error(requestContext, Constants.EXCEPTION_MSG_FETCH + tableName + " : " + e.getMessage(), e);
Expand Down
Loading

0 comments on commit 84d4a47

Please sign in to comment.