Unverified Commit 256808a6 authored by Pradyumna's avatar Pradyumna Committed by GitHub
Browse files

Merge pull request #356 from PradyumnaNagendra/SC-2218

SC-2218: Scores in group aggregates
parents 0639bd05 2edc8f58
master 4.0.0_RC4 4.1.0-loadtest-fixes SB-25890 SB-25890-1 bootcamp collection-csv dependabot/maven/course-mw/course-actors-common/com.fasterxml.jackson.core-jackson-databind-2.12.7.1 dependabot/maven/course-mw/course-actors-common/org.postgresql-postgresql-42.4.1 dependabot/maven/course-mw/enrolment-actor/com.fasterxml.jackson.core-jackson-databind-2.12.7.1 dependabot/maven/course-mw/sunbird-util/sunbird-cassandra-utils/com.fasterxml.jackson.core-jackson-databind-2.12.7.1 dependabot/maven/course-mw/sunbird-util/sunbird-notification/com.fasterxml.jackson.core-jackson-databind-2.12.7.1 dependabot/maven/course-mw/sunbird-util/sunbird-platform-core/actor-core/com.fasterxml.jackson.core-jackson-databind-2.12.7.1 dependabot/maven/course-mw/sunbird-util/sunbird-platform-core/actor-util/com.fasterxml.jackson.core-jackson-databind-2.12.7.1 dependabot/maven/course-mw/sunbird-util/sunbird-platform-core/auth-verifier/com.fasterxml.jackson.core-jackson-databind-2.12.7.1 dependabot/maven/course-mw/sunbird-util/sunbird-platform-core/common-util/com.fasterxml.jackson.core-jackson-databind-2.12.7.1 dependabot/maven/course-mw/sunbird-util/sunbird-platform-core/common-util/org.apache.kafka-kafka-clients-0.10.2.2 dependabot/maven/service/com.fasterxml.jackson.core-jackson-databind-2.12.7.1 helmchart release-3.9.0 release-4.0.0 release-4.1.0 release-4.2.0 release-4.4.0 release-4.5.0 release-4.6.0 release-4.8.0 release-4.9.0 release-5.0.0 release-5.0.1 release-5.0.2 release-5.1.0 release-5.2.0 release-5.2.1 release-5.3.0 release-5.3.1 release-5.4.0 release-5.3.1_RC1 release-5.3.0_RC1 release-5.2.0_RC2 release-5.2.0_RC1 release-5.1.0_RC2 release-5.1.0_RC1 release-5.0.1_RC3 release-5.0.1_RC2 release-5.0.1_RC1 release-5.0.0_RC6 release-5.0.0_RC5 release-5.0.0_RC4 release-5.0.0_RC3 release-5.0.0_RC2 release-5.0.0_RC1 release-4.9.0_RC4 release-4.9.0_RC3 release-4.9.0_RC2 release-4.9.0_RC1 release-4.8.0_RC2 release-4.8.0_RC1 release-4.6.0_RC10 release-4.6.0_RC9 release-4.6.0_RC8 release-4.6.0_RC7 release-4.6.0_RC6 release-4.6.0_RC5 release-4.6.0_RC4 release-4.6.0_RC3 release-4.6.0_RC2 release-4.6.0_RC1 release-4.5.0_RC4 release-4.5.0_RC3 release-4.5.0_RC2 release-4.5.0_RC1 release-4.4.0_RC3 release-4.4.0_RC2 release-4.4.0_RC1 release-4.2.0_RC1 release-4.1.0_RC4 release-4.1.0_RC3 release-4.1.0_RC2 release-4.1.0_RC1 release-4.0.0_RC7 release-4.0.0_RC6 release-4.0.0_RC5 release-4.0.0_RC4 release-4.0.0_RC3 release-4.0.0_RC2 release-4.0.0_RC1 release-3.9.0_RC7 release-3.9.0_RC6 release-3.9.0_RC5 release-3.9.0_RC4 release-3.9.0_RC3 release-3.9.0_RC2 release-3.9.0_RC1
No related merge requests found
Showing with 110 additions and 65 deletions
+110 -65
......@@ -16,7 +16,10 @@ import org.apache.http.HttpHeaders;
import org.sunbird.common.exception.ProjectCommonException;
import org.sunbird.common.models.response.HttpUtilResponse;
import org.sunbird.common.models.util.*;
import org.sunbird.common.request.Request;
import org.sunbird.common.request.RequestContext;
import org.sunbird.common.responsecode.ResponseCode;
import org.sunbird.common.util.JsonUtil;
/**
* This class will make the call to EkStep content search
......@@ -26,11 +29,19 @@ import org.sunbird.common.responsecode.ResponseCode;
public final class ContentUtil {
private static ObjectMapper mapper = new ObjectMapper();
public static Map<String, String> headerMap = new HashMap<>();
private static String EKSTEP_COURSE_SEARCH_QUERY =
"{\"request\": {\"filters\":{\"contentType\": [\"Course\"], \"identifier\": \"COURSE_ID_PLACEHOLDER\", \"status\": \"Live\", \"mimeType\": \"application/vnd.ekstep.content-collection\", \"trackable.enabled\": \"Yes\"},\"limit\": 1}}";
private static LoggerUtil logger = new LoggerUtil(ContentUtil.class);
private ContentUtil() {}
static {
String header = ProjectUtil.getConfigValue(JsonKey.EKSTEP_AUTHORIZATION);
header = JsonKey.BEARER + header;
headerMap.put(JsonKey.AUTHORIZATION, header);
headerMap.put("Content-Type", "application/json");
}
/**
* @param params String
* @param headers Map<String, String>
......@@ -113,11 +124,12 @@ public final class ContentUtil {
"BaseMetricsActor:makePostRequest: Response from analytics store for metrics", null, new HashMap<>(){{put("result", result);}});
return result;
}
public static Map<String, Object> getContent(String courseId) {
public static Map<String, Object> getContent(String courseId, List<String> fields) {
Map<String, Object> resMap = new HashMap<>();
Map<String, String> headers = new HashMap<>();
try {
String baseContentreadUrl = ProjectUtil.getConfigValue(JsonKey.EKSTEP_BASE_URL) + "/content/v3/read/" + courseId + "?fields=status";
String fieldsStr = StringUtils.join(fields, ",");
String baseContentreadUrl = ProjectUtil.getConfigValue(JsonKey.EKSTEP_BASE_URL) + "/content/v3/read/" + courseId + "?fields=" + fieldsStr;
headers.put(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
headers.put(JsonKey.AUTHORIZATION, PropertiesCache.getInstance().getProperty(JsonKey.EKSTEP_AUTHORIZATION));
......@@ -167,4 +179,22 @@ public final class ContentUtil {
}
return null;
}
public static boolean updateCollection(RequestContext requestContext, String collectionId, Map<String, Object> data) {
String response = "";
try {
String contentUpdateBaseUrl = ProjectUtil.getConfigValue(JsonKey.LEARNING_SERVICE_BASE_URL);
Request request = new Request();
request.put("content", data);
response =
HttpUtil.sendPatchRequest(
contentUpdateBaseUrl
+ PropertiesCache.getInstance().getProperty(JsonKey.EKSTEP_CONTENT_UPDATE_URL)
+ collectionId, JsonUtil.serialize(request),
headerMap);
} catch (Exception e) {
logger.error(requestContext, "Error while doing system update to collection " + e.getMessage(), e);
}
return JsonKey.SUCCESS.equalsIgnoreCase(response);
}
}
......@@ -88,7 +88,7 @@ public class ContentUtilTest {
public void getContentTest() throws Exception {
PowerMockito.when(HttpUtil.sendGetRequest(Mockito.anyString(), Mockito.any()))
.thenReturn("{\"result\":{\"content\":{\"contentType\":\"Course\",\"identifier\":\"do_1130293726460805121168\",\"languageCode\":[\"en\"],\"status\":\"Live\"}}}");
Map<String, Object> result = ContentUtil.getContent("do_1130293726460805121168");
Map<String, Object> result = ContentUtil.getContent("do_1130293726460805121168", null);
Assert.assertNotNull(result);
Assert.assertNotNull(result.get(JsonKey.CONTENT));
}
......
package org.sunbird.learner.actors.coursebatch;
import static org.sunbird.common.models.util.JsonKey.ID;
import static org.sunbird.common.models.util.JsonKey.NULL;
import static org.sunbird.common.models.util.JsonKey.PARTICIPANTS;
import akka.actor.ActorRef;
......@@ -101,7 +102,7 @@ public class CourseBatchManagementActor extends BaseActor {
ResponseCode.invalidRequestParameter.getErrorMessage(), PARTICIPANTS));
}
CourseBatch courseBatch = JsonUtil.convert(request, CourseBatch.class);
courseBatch.setStatus(ProgressStatus.NOT_STARTED.getValue());
courseBatch.setStatus(setCourseBatchStatus(actorMessage.getRequestContext(), (String) request.get(JsonKey.START_DATE)));
String courseId = (String) request.get(JsonKey.COURSE_ID);
Map<String, Object> contentDetails = getContentDetails(actorMessage.getRequestContext(),courseId, headers);
courseBatch.setCreatedDate(ProjectUtil.getFormattedDate());
......@@ -129,8 +130,7 @@ public class CourseBatchManagementActor extends BaseActor {
TelemetryUtil.telemetryProcessingCall(request, targetObject, correlatedObject, actorMessage.getContext());
// updateBatchCount(courseBatch);
//Generate Instruction event. Send courseId for batch
pushInstructionEvent(actorMessage.getRequestContext(), courseId,courseBatchId);
updateCollection(actorMessage.getRequestContext(), courseBatch, contentDetails);
if (courseNotificationActive()) {
batchOperationNotifier(actorMessage, courseBatch, null);
}
......@@ -174,6 +174,9 @@ public class CourseBatchManagementActor extends BaseActor {
Map<String, Object> participantsMap = new HashMap<>();
List<Map<String, Object>> correlatedObject = new ArrayList<>();
Map<String, String> headers =
(Map<String, String>) actorMessage.getContext().get(JsonKey.HEADER);
String requestedBy = (String) actorMessage.getContext().get(JsonKey.REQUESTED_BY);
Map<String, Object> request = actorMessage.getRequest();
if (Util.isNotNull(request.get(JsonKey.PARTICIPANTS))) {
......@@ -186,12 +189,12 @@ public class CourseBatchManagementActor extends BaseActor {
request.containsKey(JsonKey.BATCH_ID)
? (String) request.get(JsonKey.BATCH_ID)
: (String) request.get(JsonKey.ID);
String requestedBy = (String) actorMessage.getContext().get(JsonKey.REQUESTED_BY);
CourseBatch oldBatch =
courseBatchDao.readById((String) request.get(JsonKey.COURSE_ID), batchId, actorMessage.getRequestContext());
CourseBatch courseBatch = getUpdateCourseBatch(actorMessage.getRequestContext(), request);
courseBatch.setUpdatedDate(ProjectUtil.getFormattedDate());
checkBatchStatus(courseBatch);
Map<String, Object> contentDetails = getContentDetails(actorMessage.getRequestContext(),courseBatch.getCourseId(), headers);
validateUserPermission(courseBatch, requestedBy);
validateContentOrg(actorMessage.getRequestContext(), courseBatch.getCreatedFor());
validateMentors(courseBatch, (String) actorMessage.getContext().getOrDefault(JsonKey.X_AUTH_TOKEN, ""), actorMessage.getRequestContext());
......@@ -211,7 +214,7 @@ public class CourseBatchManagementActor extends BaseActor {
rollUp.put("l1", courseBatch.getCourseId());
TelemetryUtil.addTargetObjectRollUp(rollUp, targetObject);
TelemetryUtil.telemetryProcessingCall(courseBatchMap, targetObject, correlatedObject, actorMessage.getContext());
pushInstructionEvent(actorMessage.getRequestContext(), (String) request.get(JsonKey.COURSE_ID),batchId);
updateCollection(actorMessage.getRequestContext(), courseBatch, contentDetails);
if (courseNotificationActive()) {
batchOperationNotifier(actorMessage, courseBatch, participantsMap);
}
......@@ -296,45 +299,23 @@ public class CourseBatchManagementActor extends BaseActor {
sender().tell(response, self());
}
private void pushInstructionEvent(RequestContext requestContext, String courseId, String batchId)
throws Exception {
Map<String, Object> data = new HashMap<>();
data.put(
CourseJsonKey.ACTOR,
new HashMap<String, Object>() {
{
put(JsonKey.ID, InstructionEvent.COURSE_BATCH_UPDATE.getActorId());
put(JsonKey.TYPE, InstructionEvent.COURSE_BATCH_UPDATE.getActorType());
}
});
data.put(
CourseJsonKey.OBJECT,
new HashMap<String, Object>() {
{
put(JsonKey.ID, courseId + CourseJsonKey.UNDERSCORE + batchId);
put(JsonKey.TYPE, InstructionEvent.COURSE_BATCH_UPDATE.getType());
}
});
data.put(CourseJsonKey.ACTION, InstructionEvent.COURSE_BATCH_UPDATE.getAction());
data.put(
CourseJsonKey.E_DATA,
new HashMap<String, Object>() {
{
put(JsonKey.COURSE_ID, courseId);
put(JsonKey.BATCH_ID, batchId);
put(CourseJsonKey.ACTION, InstructionEvent.COURSE_BATCH_UPDATE.getAction());
put(CourseJsonKey.ITERATION, 1);
}
});
String topic = ProjectUtil.getConfigValue("kafka_topics_instruction");
logger.info(requestContext, "CourseBatchManagementctor: pushInstructionEvent :Event Data "
+ data+" and Topic "+topic);
InstructionEventGenerator.pushInstructionEvent(batchId, topic, data);
private int setCourseBatchStatus(RequestContext requestContext, String startDate) {
try {
Date todayDate = DATE_FORMAT.parse(DATE_FORMAT.format(new Date()));
Date requestedStartDate = DATE_FORMAT.parse(startDate);
logger.info(requestContext, "CourseBatchManagementActor:setCourseBatchStatus: todayDate="
+ todayDate + ", requestedStartDate=" + requestedStartDate);
if (todayDate.compareTo(requestedStartDate) == 0) {
return ProgressStatus.STARTED.getValue();
} else {
return ProgressStatus.NOT_STARTED.getValue();
}
} catch (ParseException e) {
logger.error(requestContext, "CourseBatchManagementActor:setCourseBatchStatus: Exception occurred with error message = " + e.getMessage(), e);
}
return ProgressStatus.NOT_STARTED.getValue();
}
private void validateMentors(CourseBatch courseBatch, String authToken, RequestContext requestContext) {
List<String> mentors = courseBatch.getMentors();
......@@ -593,7 +574,7 @@ public class CourseBatchManagementActor extends BaseActor {
}
private Map<String, Object> getContentDetails(RequestContext requestContext, String courseId, Map<String, String> headers) {
Map<String, Object> ekStepContent = ContentUtil.getContent(courseId);
Map<String, Object> ekStepContent = ContentUtil.getContent(courseId, Arrays.asList("status", "batches"));
logger.info(requestContext, "CourseBatchManagementActor:getEkStepContent: courseId: " + courseId, null,
ekStepContent);
String status = (String) ((Map<String, Object>)ekStepContent.getOrDefault("content", new HashMap<>())).getOrDefault("status", "");
......@@ -686,4 +667,34 @@ public class CourseBatchManagementActor extends BaseActor {
}
return template;
}
private void updateCollection(RequestContext requestContext, CourseBatch courseBatch, Map<String, Object> contentDetails) {
List<Map<String, Object>> batches = (List<Map<String, Object>>) contentDetails.getOrDefault("batches", new ArrayList<>());
Map<String, Object> data = new HashMap<>();
data.put("batchId", courseBatch.getBatchId());
data.put("name", courseBatch.getName());
data.put("createdFor", courseBatch.getCreatedFor());
data.put("startDate", courseBatch.getStartDate());
data.put("endDate", courseBatch.getEndDate());
data.put("enrollmentType", courseBatch.getEnrollmentType());
data.put("status", courseBatch.getStatus());
data.put("enrollmentEndDate", getEnrollmentEndDate(courseBatch.getEnrollmentEndDate(), courseBatch.getEndDate()));
batches.removeIf(map -> StringUtils.equalsIgnoreCase(courseBatch.getBatchId(), (String)map.get("batchId")));
batches.add(data);
ContentUtil.updateCollection(requestContext, courseBatch.getCourseId(), new HashMap<String, Object>() {{ put("batches", batches);}});
}
private Object getEnrollmentEndDate(String enrollmentEndDate, String endDate) {
return Optional.ofNullable(enrollmentEndDate).map(x -> x).orElse(Optional.ofNullable(endDate).map(y ->{
Calendar cal = Calendar.getInstance();
try {
cal.setTime(DATE_FORMAT.parse(y));
cal.add(Calendar.DAY_OF_MONTH, -1);
return DATE_FORMAT.format(cal.getTime());
} catch (ParseException e) {
return null;
}
}).orElse(null));
}
}
......@@ -146,6 +146,6 @@ public class CourseBatchManagementActorTest extends SunbirdApplicationActorTest
}});
}};
when(ContentUtil.getContent(
Mockito.anyString())).thenReturn(courseMap);
Mockito.anyString(), Mockito.anyList())).thenReturn(courseMap);
}
}
......@@ -31,17 +31,18 @@ import org.sunbird.common.request.Request;
import org.sunbird.common.responsecode.ResponseCode;
import org.sunbird.helper.ServiceFactory;
import org.sunbird.kafka.client.InstructionEventGenerator;
import org.sunbird.kafka.client.KafkaClient;
import org.sunbird.learner.actors.coursebatch.CourseBatchManagementActor;
import org.sunbird.learner.constants.CourseJsonKey;
import org.sunbird.learner.util.ContentUtil;
import org.sunbird.learner.util.CourseBatchUtil;
import org.sunbird.learner.util.JsonUtil;
import org.sunbird.learner.util.Util;
@RunWith(PowerMockRunner.class)
@SuppressStaticInitializationFor("org.sunbird.kafka.client.KafkaClient")
@PrepareForTest({ServiceFactory.class, EsClientFactory.class, CourseBatchUtil.class, Util.class, InstructionEventGenerator.class, KafkaClient.class})
@PowerMockIgnore({"javax.management.*"})
@PrepareForTest({ServiceFactory.class, EsClientFactory.class, CourseBatchUtil.class, Util.class, ContentUtil.class})
@PowerMockIgnore({"javax.management.*", "javax.net.ssl.*", "javax.security.*", "jdk.internal.reflect.*",
"sun.security.ssl.*", "javax.net.ssl.*", "javax.crypto.*",
"com.sun.org.apache.xerces.*", "javax.xml.*", "org.xml.*"})
public class CourseBatchManagementActorTest {
public ActorSystem system = ActorSystem.create("system");
......@@ -58,21 +59,11 @@ public class CourseBatchManagementActorTest {
@Before
public void setUp() throws Exception {
mockCassandraOperation = mock(CassandraOperationImpl.class);
PowerMockito.mockStatic(InstructionEventGenerator.class);
PowerMockito.mockStatic(KafkaClient.class);
PowerMockito.doNothing()
.when(
InstructionEventGenerator.class,
"pushInstructionEvent",
Mockito.anyString(),
Mockito.anyMap());
PowerMockito.doNothing()
.when(KafkaClient.class, "send", Mockito.anyString(), Mockito.anyString());
ActorRef actorRef = mock(ActorRef.class);
PowerMockito.mockStatic(ServiceFactory.class);
when(ServiceFactory.getInstance()).thenReturn(mockCassandraOperation);
PowerMockito.mockStatic(CourseBatchUtil.class);
PowerMockito.mockStatic(ContentUtil.class);
}
private String calculateDate(int dayOffset) {
......@@ -90,6 +81,7 @@ public class CourseBatchManagementActorTest {
when(mockCassandraOperation.getRecordByIdentifier(
Mockito.any(), Mockito.anyString(), Mockito.anyString(), Mockito.anyMap(), Mockito.any()))
.thenReturn(mockGetRecordByIdResponse);
mockCourseEnrollmentActor();
TestKit probe = new TestKit(system);
ActorRef subject = system.actorOf(props);
......@@ -126,6 +118,8 @@ public class CourseBatchManagementActorTest {
PowerMockito.doNothing().when(CourseBatchUtil.class);
CourseBatchUtil.syncCourseBatchForeground(null, BATCH_ID, new HashMap<>());
PowerMockito.mockStatic(ContentUtil.class);
mockCourseEnrollmentActor();
TestKit probe = new TestKit(system);
ActorRef subject = system.actorOf(props);
......@@ -504,4 +498,15 @@ public class CourseBatchManagementActorTest {
"}";
return JsonUtil.deserialize(template, Map.class);
}
private void mockCourseEnrollmentActor(){
Map<String, Object> courseMap = new HashMap<String, Object>() {{
put("content", new HashMap<String, Object>() {{
put("contentType", "Course");
put("status", "Live");
}});
}};
when(ContentUtil.getContent(
Mockito.anyString(), Mockito.anyList())).thenReturn(courseMap);
}
}
......@@ -102,11 +102,10 @@ class GroupAggregatesActor @Inject()(implicit val cacheUtil: RedisCacheUtil) ext
val finalMemberList = if(CollectionUtils.isNotEmpty(usersAggs) && CollectionUtils.isNotEmpty(groupMembers)) {
val membersMap = groupMembers.asScala.toList.filter(x => StringUtils.isNotBlank(x.getOrDefault("userId", "").asInstanceOf[String]))
.map(obj => (obj.getOrDefault("userId", "").asInstanceOf[String], obj)).toMap.asJava
val aggName = "completedCount"
usersAggs.map(dbAggRecord => {
val dbAgg = dbAggRecord.get("agg").asInstanceOf[java.util.Map[String, AnyRef]]
val aggLastUpdated = dbAggRecord.get("agg_last_updated").asInstanceOf[java.util.Map[String, AnyRef]]
val agg = List(Map("metric"-> aggName, "value" -> dbAgg.get(aggName), "lastUpdatedOn" -> aggLastUpdated.get(aggName)).asJava).asJava
val agg = dbAgg.map(aggregate => Map("metric"-> aggregate._1, "value" -> aggregate._2, "lastUpdatedOn" -> aggLastUpdated.get(aggregate._1)).asJava).toList.asJava
val userId = dbAggRecord.get("user_id").asInstanceOf[String]
(membersMap.get(userId).filterKeys(key => GROUP_MEMBERS_METADATA.contains(key)) ++ Map("agg" -> agg)).asJava
}).toList
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment